-
Notifications
You must be signed in to change notification settings - Fork 68
Manually resolve path relatively to root_dir to prevent escape
#328
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
base: master
Are you sure you want to change the base?
Conversation
509cc4f to
5ab542e
Compare
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.
Hi @HorlogeSkynet , maybe I'm misunderstanding something, but right now I only see the part that prevents "unjust" escapes from the chroot (from absolute links or from going above the root) but I don't see any code that would "bend" "legit" absolute symlinks back into the chroot.
Let me demo what I think we'd need in some form:
def resolve_chroot_symlink(link_location, root_dir):
assert os.path.commonprefix([link_location, root_dir]) == root_dir
while True:
try:
resolved = os.readlink(link_location)
except FileNotFoundError: # includes case "not a symlink"
return link_location
if resolved.startswith('/'):
# i.e. absolute path (with regard to the chroot)
# that we need to move back inside the chroot
resolved = os.path.join(root_dir, resolved.lstrip('/'))
else:
# i.e. relative path that we make absolute
resolved = os.path.join(os.path.dirname(link_location), resolved)
if os.path.commonprefix([resolved, root_dir]) != root_dir:
raise Value('ESCAPE DETECTED') # TODO
link_location = resolvedWhat do you think?
5ab542e to
b9004e8
Compare
|
Dear Sebastian, sorry for the delay. So I tweaked your function a bit in order to :
You will see that I opted for links resolution on the verge of calling I've implemented three short test cases to check our new logic (note : relative symbolic links resolving is already tested by regular rootfs under I also took the liberty to update our Bye ! Thanks for your time 👋 |
root_dir, and prevent escape
hartwork
left a comment
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.
Hi @HorlogeSkynet kudos for the new tests and the loop detection! 👍 I believe a few details need more work, please see my comments below
b9004e8 to
c97754d
Compare
🙏 My mistake ! There was an empty directory that Git didn't track, I've just fixed this 😉 Waiting for your inputs, thanks for your time 👋 EDIT : If you are tired of these round trips, feel free to directly amend the branch ! |
c97754d to
5186ad6
Compare
5186ad6 to
568cce4
Compare
568cce4 to
1087c2d
Compare
|
PR's (finally) ready @hartwork ! |
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.
Hello @HorlogeSkynet, sorry for the big delay. I found some remaining issues. Please see my four comments below for details:
a1af721 to
91de73f
Compare
5d9b5ba to
e40187b
Compare
7dc0126 to
a46f5a7
Compare
ddb9177 to
9911c30
Compare
|
Dear @python-distro/maintainers, Dear @hartwork (if you haven't muted notifications from this repository 🙃), I've finally taken the time to rework this feature (fix ?). What has been done :
This branch as also been rebased, and hence now "ready". Thanks for your time, |
9911c30 to
af1c8ad
Compare
Hi @HorlogeSkynet, back in 2022-08 — soon two years ago — I implemented a solution on branch |
af1c8ad to
7a85cfa
Compare
|
Hey @hartwork, and thanks for your answer. Indeed, I completely forgot about this (these) discussions, since GitHub archived them... I took a quick glimpse of your branch which I find very complex (but this bug/feature is not trivial at all, and my new algorithm is possibly sill broken). So I'll sum up the situation here again, so @python-distro/maintainers will have the full context to properly review this (these) branches : The idea is to "fix" the
So we (@hartwork and I) worked on these issues without opting for solutions as requiring system privileges or using a third-party dependency.
From here, we see multiple options that I'd like to propose/discuss with you :
Thanks for your time, see you all 👋 |
7a85cfa to
dc19990
Compare
Implementation reworked and rebased
dc19990 to
5e7a64f
Compare
root_dir, and prevent escaperoot_dir to prevent escape
1284169 to
f0e57c0
Compare
f0e57c0 to
9f3ae66
Compare
|
@adamjstewart As #369 is now closed and we eventually don't "open" another file, I take the liberty to re-propose this patch to address concerns raised in #311. I agree it's a big piece, but as it's safely guarded by |
Explicitly disabling third-programs data sources is not required since 2a89f76 (disabled by default if `root_dir` is set).
This patch is a followup of #311 (2a89f76). It appeared that we were not resolving paths when reading from files. This means that symbolic links present under `root_dir` could be blindly followed, eventually leading _outside_ of `root_dir` (i.e host own files). Note : this patch **only** changes LinuxDistribution `root_dir` parameter behavior.
9f3ae66 to
50f1498
Compare
|
@HorlogeSkynet this one's a bit outside my area of expertise. I think someone else would be better to review this, as I barely understand the problem it's trying to solve. |
Two years and a half, except for Sebastian, no one really gave a damn about this issue. This PR resolves rootfs symbolic links relatively to chroot to prevent this behavior, but is still vulnerable to TOCTOU, |
Dear Sebastian, dear maintainers,
This PR drafts a first implementation to address concerns raised in #311 review.
Currently, paths are not manually resolved, and by following symbolic links, this may lead to outside specified
root_dir.By using
os.path.realpathandos.path.commonprefix, we can verify that important paths are still prefixed byroot_dir, once they have been resolved.It turned out enforcing those checks was not as easy as I thought :
PermissionErroractually fits, but I was out of option__prevent_root_dir_escapefunction might require a renaming tooAt least, the new functional test actually enlightens the issue.
--> A deep review is required, ideas are welcome and commits on this branch too 🙃
Have a nice WE all 🙇