Manually resolve path relatively to root_dir to prevent escape#328
Manually resolve path relatively to root_dir to prevent escape#328HorlogeSkynet wants to merge 2 commits intomasterfrom
root_dir to prevent escape#328Conversation
509cc4f to
5ab542e
Compare
There was a problem hiding this comment.
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.
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.
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 🙇