How to create a chroot from which root cannot escape using chdir(“..”) on Linux, inside a filesystem?
Clash Royale CLAN TAG#URR8PPP
I have a directory /var/mychoot
on the same filesystem as /
, and I've started the program /var/mychroot/prog
as sudo chroot /var/mychroot /prog
, so the program is running as EUID 0.
If the program executes the chdir("..") escape technique, then it is able to escape the chroot and see everything within /
. (I've verified this on Linux 4.18.)
I want to prevent such an escape. In fact I want to prevent all kinds of chroot escapes, but in this question I'm only interested in how the chdir("..") escape technique can be prevented on modern Linux systems. For this I'm looking for alternatives of the chroot(2) system call.
I've found 2 solutions: pivot_root and MS_MOVE, but they only work if /var/mychroot
is a mount point, so they fail if /var/mychroot
is just a subdirectory within the /
filesystem. Is there another solution in this case?
I want to avoid techniques using LD_PRELOAD
(because LD_PRELOAD
doesn't affect statically linked executables), techniques using ptrace(2) (because then I'm not able to run strace
within the chroot, and also ptrace(2) is very tricky to get right: processes will crash or hang) and real virtualization (e.g. Xen or KVM or QEMU; because of the performance overhead and the less flexible memory provisioning).
To recap, I need:
- an alternative of chroot(2) system call,
- with which root can restrict processes running as root (EUID 0),
- to a subdirectory of the filesystem of
/
, - which prevents the chdir("..") escape technique,
- and doesn't use
LD_PRELOAD
or
ptrace(2) or- virtualization (e.g. Xen, KVM or QEMU),
- and it runs on a modern Linux system,
- with and unpatched kernel.
Does it exist?
linux chroot containers
add a comment |
I have a directory /var/mychoot
on the same filesystem as /
, and I've started the program /var/mychroot/prog
as sudo chroot /var/mychroot /prog
, so the program is running as EUID 0.
If the program executes the chdir("..") escape technique, then it is able to escape the chroot and see everything within /
. (I've verified this on Linux 4.18.)
I want to prevent such an escape. In fact I want to prevent all kinds of chroot escapes, but in this question I'm only interested in how the chdir("..") escape technique can be prevented on modern Linux systems. For this I'm looking for alternatives of the chroot(2) system call.
I've found 2 solutions: pivot_root and MS_MOVE, but they only work if /var/mychroot
is a mount point, so they fail if /var/mychroot
is just a subdirectory within the /
filesystem. Is there another solution in this case?
I want to avoid techniques using LD_PRELOAD
(because LD_PRELOAD
doesn't affect statically linked executables), techniques using ptrace(2) (because then I'm not able to run strace
within the chroot, and also ptrace(2) is very tricky to get right: processes will crash or hang) and real virtualization (e.g. Xen or KVM or QEMU; because of the performance overhead and the less flexible memory provisioning).
To recap, I need:
- an alternative of chroot(2) system call,
- with which root can restrict processes running as root (EUID 0),
- to a subdirectory of the filesystem of
/
, - which prevents the chdir("..") escape technique,
- and doesn't use
LD_PRELOAD
or
ptrace(2) or- virtualization (e.g. Xen, KVM or QEMU),
- and it runs on a modern Linux system,
- with and unpatched kernel.
Does it exist?
linux chroot containers
Why would you need root to run in a jail? Usually you'd drop root privileges once set up and depend on services or setuid exes for access to privileged calls and areas (e.g., network).
– melds
Jan 5 at 2:17
1
@melds: For example, running in a jail as root is useful ifapt-get install UNTRUSTED-PACKAGE
is run, where the the install script of the package can contain malicious code. A similar use case isdocker run UNTRUSTED-IMAGE
, the default commands of such packages run as root. Docker is not using chroot for filesystem isolation, and I'm also interested in understanding what would break if it did, and how it could be fixed.
– pts
Jan 5 at 2:29
add a comment |
I have a directory /var/mychoot
on the same filesystem as /
, and I've started the program /var/mychroot/prog
as sudo chroot /var/mychroot /prog
, so the program is running as EUID 0.
If the program executes the chdir("..") escape technique, then it is able to escape the chroot and see everything within /
. (I've verified this on Linux 4.18.)
I want to prevent such an escape. In fact I want to prevent all kinds of chroot escapes, but in this question I'm only interested in how the chdir("..") escape technique can be prevented on modern Linux systems. For this I'm looking for alternatives of the chroot(2) system call.
I've found 2 solutions: pivot_root and MS_MOVE, but they only work if /var/mychroot
is a mount point, so they fail if /var/mychroot
is just a subdirectory within the /
filesystem. Is there another solution in this case?
I want to avoid techniques using LD_PRELOAD
(because LD_PRELOAD
doesn't affect statically linked executables), techniques using ptrace(2) (because then I'm not able to run strace
within the chroot, and also ptrace(2) is very tricky to get right: processes will crash or hang) and real virtualization (e.g. Xen or KVM or QEMU; because of the performance overhead and the less flexible memory provisioning).
To recap, I need:
- an alternative of chroot(2) system call,
- with which root can restrict processes running as root (EUID 0),
- to a subdirectory of the filesystem of
/
, - which prevents the chdir("..") escape technique,
- and doesn't use
LD_PRELOAD
or
ptrace(2) or- virtualization (e.g. Xen, KVM or QEMU),
- and it runs on a modern Linux system,
- with and unpatched kernel.
Does it exist?
linux chroot containers
I have a directory /var/mychoot
on the same filesystem as /
, and I've started the program /var/mychroot/prog
as sudo chroot /var/mychroot /prog
, so the program is running as EUID 0.
If the program executes the chdir("..") escape technique, then it is able to escape the chroot and see everything within /
. (I've verified this on Linux 4.18.)
I want to prevent such an escape. In fact I want to prevent all kinds of chroot escapes, but in this question I'm only interested in how the chdir("..") escape technique can be prevented on modern Linux systems. For this I'm looking for alternatives of the chroot(2) system call.
I've found 2 solutions: pivot_root and MS_MOVE, but they only work if /var/mychroot
is a mount point, so they fail if /var/mychroot
is just a subdirectory within the /
filesystem. Is there another solution in this case?
I want to avoid techniques using LD_PRELOAD
(because LD_PRELOAD
doesn't affect statically linked executables), techniques using ptrace(2) (because then I'm not able to run strace
within the chroot, and also ptrace(2) is very tricky to get right: processes will crash or hang) and real virtualization (e.g. Xen or KVM or QEMU; because of the performance overhead and the less flexible memory provisioning).
To recap, I need:
- an alternative of chroot(2) system call,
- with which root can restrict processes running as root (EUID 0),
- to a subdirectory of the filesystem of
/
, - which prevents the chdir("..") escape technique,
- and doesn't use
LD_PRELOAD
or
ptrace(2) or- virtualization (e.g. Xen, KVM or QEMU),
- and it runs on a modern Linux system,
- with and unpatched kernel.
Does it exist?
linux chroot containers
linux chroot containers
edited Jan 5 at 6:57
filbranden
7,4002837
7,4002837
asked Jan 5 at 0:46
ptspts
384413
384413
Why would you need root to run in a jail? Usually you'd drop root privileges once set up and depend on services or setuid exes for access to privileged calls and areas (e.g., network).
– melds
Jan 5 at 2:17
1
@melds: For example, running in a jail as root is useful ifapt-get install UNTRUSTED-PACKAGE
is run, where the the install script of the package can contain malicious code. A similar use case isdocker run UNTRUSTED-IMAGE
, the default commands of such packages run as root. Docker is not using chroot for filesystem isolation, and I'm also interested in understanding what would break if it did, and how it could be fixed.
– pts
Jan 5 at 2:29
add a comment |
Why would you need root to run in a jail? Usually you'd drop root privileges once set up and depend on services or setuid exes for access to privileged calls and areas (e.g., network).
– melds
Jan 5 at 2:17
1
@melds: For example, running in a jail as root is useful ifapt-get install UNTRUSTED-PACKAGE
is run, where the the install script of the package can contain malicious code. A similar use case isdocker run UNTRUSTED-IMAGE
, the default commands of such packages run as root. Docker is not using chroot for filesystem isolation, and I'm also interested in understanding what would break if it did, and how it could be fixed.
– pts
Jan 5 at 2:29
Why would you need root to run in a jail? Usually you'd drop root privileges once set up and depend on services or setuid exes for access to privileged calls and areas (e.g., network).
– melds
Jan 5 at 2:17
Why would you need root to run in a jail? Usually you'd drop root privileges once set up and depend on services or setuid exes for access to privileged calls and areas (e.g., network).
– melds
Jan 5 at 2:17
1
1
@melds: For example, running in a jail as root is useful if
apt-get install UNTRUSTED-PACKAGE
is run, where the the install script of the package can contain malicious code. A similar use case is docker run UNTRUSTED-IMAGE
, the default commands of such packages run as root. Docker is not using chroot for filesystem isolation, and I'm also interested in understanding what would break if it did, and how it could be fixed.– pts
Jan 5 at 2:29
@melds: For example, running in a jail as root is useful if
apt-get install UNTRUSTED-PACKAGE
is run, where the the install script of the package can contain malicious code. A similar use case is docker run UNTRUSTED-IMAGE
, the default commands of such packages run as root. Docker is not using chroot for filesystem isolation, and I'm also interested in understanding what would break if it did, and how it could be fixed.– pts
Jan 5 at 2:29
add a comment |
2 Answers
2
active
oldest
votes
To protect against the specific chdir("..")
escape technique you mentioned, you can simply drop the capability to execute chroot(2)
again once you're chrooted to /var/mychroot
yourself. The escape technique requires another call to chroot()
, so blocking that is enough to prevent it from working.
You can do that with Linux capabilities, by dropping CAP_SYS_CHROOT
which is the one needed for chroot(2)
to be available.
For example:
outside# chroot /var/mychroot
inside# capsh --drop=cap_sys_chroot --
inside# ./escape_chroot
chroot(baz): Operation not permitted
(The second prompt inside the chroot is from a shell spawned from capsh
. You can make it run another command with, for example, capsh --drop=cap_sys_chroot -- -c 'exec ./escape_chroot'
.)
But a much better technique is to just use pivot_root
, since it protects from many of the other possible exploits that chroot(2)
will not protect from.
You mentioned that it only works if /var/mychroot
is a mount point, but you can make it a mount point by simply bind mounting it into itself.
Note that you need to create a mount namespace to use pivot_root
to create a jail, otherwise it will try to change the root of all processes in your filesystem, which is most likely not what you want here...
So the whole sequence goes:
outside# unshare -m
outside# mount --bind /var/mychroot /var/mychroot
outside# cd /var/mychroot
outside# mkdir old_root
outside# pivot_root . old_root
limbo# exec chroot .
inside# umount /old_root
(Again, many of these commands are spawning new shells. unshare
does that, so does chroot
itself. You can work around those by passing commands as extra arguments. In some cases you might want to pass sh -c '...'
for a full script.)
At this point, you're inside a pivot_root
jail in a separate mount namespace, and the fact that /var/mychroot
is simply a directory of the original root (and not a mount of a separate device or loop device) didn't really prevent this from working, thanks to the bind mount into itself.
Running the escape code, you'll see that the jail works as expected (even though the escape code claims otherwise):
inside# touch /inside_jail
inside# ./escape_chroot
Exploit seems to work. =)
inside# # ls -ld /inside_jail /old_root
-rw-r--r--. 1 0 0 0 Jan 5 23:45 /inside_jail
dr-xr-xr-x. 20 0 0 4096 Jul 5 23:45 /old_root
As you can see, still inside the jail... The exploit code is just a bit naive and assumes that as long as the operations (chroot
, chdir
) have succeeded, that was enough to escape the jail, which is not really the case...
So consider using this technique to create a jail that is superior to chroot
and does not require using Linux capabilities to block operations inside it (such as creating additional chroot
s, which might actually be useful or required for what you're actually trying to run in a jail.)
1
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
add a comment |
they only work if /var/mychroot is a mount point, so they fail if /var/mychroot is just a subdirectory within the / filesystem.
You can make any directory a mount point: mount --rbind /var/mychoot /var/mychoot
.
This step - and others that you will need - are covered here:
How to perform chroot with Linux namespaces?
In fact I want to prevent all kinds of chroot escapes
Combine the above with user namespaces.
Alternatively, seccomp
. This is how Docker prevents contained processes calling mount()
, for example. (When you mount a block device a second time, you get a second view of that filesystem, which more or less counts as an escape). Copy Docker's list of allowed syscalls - root has lots of different ways of escaping.
https://docs.docker.com/engine/security/seccomp/
https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
1
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f492607%2fhow-to-create-a-chroot-from-which-root-cannot-escape-using-chdir-on-linux%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
To protect against the specific chdir("..")
escape technique you mentioned, you can simply drop the capability to execute chroot(2)
again once you're chrooted to /var/mychroot
yourself. The escape technique requires another call to chroot()
, so blocking that is enough to prevent it from working.
You can do that with Linux capabilities, by dropping CAP_SYS_CHROOT
which is the one needed for chroot(2)
to be available.
For example:
outside# chroot /var/mychroot
inside# capsh --drop=cap_sys_chroot --
inside# ./escape_chroot
chroot(baz): Operation not permitted
(The second prompt inside the chroot is from a shell spawned from capsh
. You can make it run another command with, for example, capsh --drop=cap_sys_chroot -- -c 'exec ./escape_chroot'
.)
But a much better technique is to just use pivot_root
, since it protects from many of the other possible exploits that chroot(2)
will not protect from.
You mentioned that it only works if /var/mychroot
is a mount point, but you can make it a mount point by simply bind mounting it into itself.
Note that you need to create a mount namespace to use pivot_root
to create a jail, otherwise it will try to change the root of all processes in your filesystem, which is most likely not what you want here...
So the whole sequence goes:
outside# unshare -m
outside# mount --bind /var/mychroot /var/mychroot
outside# cd /var/mychroot
outside# mkdir old_root
outside# pivot_root . old_root
limbo# exec chroot .
inside# umount /old_root
(Again, many of these commands are spawning new shells. unshare
does that, so does chroot
itself. You can work around those by passing commands as extra arguments. In some cases you might want to pass sh -c '...'
for a full script.)
At this point, you're inside a pivot_root
jail in a separate mount namespace, and the fact that /var/mychroot
is simply a directory of the original root (and not a mount of a separate device or loop device) didn't really prevent this from working, thanks to the bind mount into itself.
Running the escape code, you'll see that the jail works as expected (even though the escape code claims otherwise):
inside# touch /inside_jail
inside# ./escape_chroot
Exploit seems to work. =)
inside# # ls -ld /inside_jail /old_root
-rw-r--r--. 1 0 0 0 Jan 5 23:45 /inside_jail
dr-xr-xr-x. 20 0 0 4096 Jul 5 23:45 /old_root
As you can see, still inside the jail... The exploit code is just a bit naive and assumes that as long as the operations (chroot
, chdir
) have succeeded, that was enough to escape the jail, which is not really the case...
So consider using this technique to create a jail that is superior to chroot
and does not require using Linux capabilities to block operations inside it (such as creating additional chroot
s, which might actually be useful or required for what you're actually trying to run in a jail.)
1
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
add a comment |
To protect against the specific chdir("..")
escape technique you mentioned, you can simply drop the capability to execute chroot(2)
again once you're chrooted to /var/mychroot
yourself. The escape technique requires another call to chroot()
, so blocking that is enough to prevent it from working.
You can do that with Linux capabilities, by dropping CAP_SYS_CHROOT
which is the one needed for chroot(2)
to be available.
For example:
outside# chroot /var/mychroot
inside# capsh --drop=cap_sys_chroot --
inside# ./escape_chroot
chroot(baz): Operation not permitted
(The second prompt inside the chroot is from a shell spawned from capsh
. You can make it run another command with, for example, capsh --drop=cap_sys_chroot -- -c 'exec ./escape_chroot'
.)
But a much better technique is to just use pivot_root
, since it protects from many of the other possible exploits that chroot(2)
will not protect from.
You mentioned that it only works if /var/mychroot
is a mount point, but you can make it a mount point by simply bind mounting it into itself.
Note that you need to create a mount namespace to use pivot_root
to create a jail, otherwise it will try to change the root of all processes in your filesystem, which is most likely not what you want here...
So the whole sequence goes:
outside# unshare -m
outside# mount --bind /var/mychroot /var/mychroot
outside# cd /var/mychroot
outside# mkdir old_root
outside# pivot_root . old_root
limbo# exec chroot .
inside# umount /old_root
(Again, many of these commands are spawning new shells. unshare
does that, so does chroot
itself. You can work around those by passing commands as extra arguments. In some cases you might want to pass sh -c '...'
for a full script.)
At this point, you're inside a pivot_root
jail in a separate mount namespace, and the fact that /var/mychroot
is simply a directory of the original root (and not a mount of a separate device or loop device) didn't really prevent this from working, thanks to the bind mount into itself.
Running the escape code, you'll see that the jail works as expected (even though the escape code claims otherwise):
inside# touch /inside_jail
inside# ./escape_chroot
Exploit seems to work. =)
inside# # ls -ld /inside_jail /old_root
-rw-r--r--. 1 0 0 0 Jan 5 23:45 /inside_jail
dr-xr-xr-x. 20 0 0 4096 Jul 5 23:45 /old_root
As you can see, still inside the jail... The exploit code is just a bit naive and assumes that as long as the operations (chroot
, chdir
) have succeeded, that was enough to escape the jail, which is not really the case...
So consider using this technique to create a jail that is superior to chroot
and does not require using Linux capabilities to block operations inside it (such as creating additional chroot
s, which might actually be useful or required for what you're actually trying to run in a jail.)
1
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
add a comment |
To protect against the specific chdir("..")
escape technique you mentioned, you can simply drop the capability to execute chroot(2)
again once you're chrooted to /var/mychroot
yourself. The escape technique requires another call to chroot()
, so blocking that is enough to prevent it from working.
You can do that with Linux capabilities, by dropping CAP_SYS_CHROOT
which is the one needed for chroot(2)
to be available.
For example:
outside# chroot /var/mychroot
inside# capsh --drop=cap_sys_chroot --
inside# ./escape_chroot
chroot(baz): Operation not permitted
(The second prompt inside the chroot is from a shell spawned from capsh
. You can make it run another command with, for example, capsh --drop=cap_sys_chroot -- -c 'exec ./escape_chroot'
.)
But a much better technique is to just use pivot_root
, since it protects from many of the other possible exploits that chroot(2)
will not protect from.
You mentioned that it only works if /var/mychroot
is a mount point, but you can make it a mount point by simply bind mounting it into itself.
Note that you need to create a mount namespace to use pivot_root
to create a jail, otherwise it will try to change the root of all processes in your filesystem, which is most likely not what you want here...
So the whole sequence goes:
outside# unshare -m
outside# mount --bind /var/mychroot /var/mychroot
outside# cd /var/mychroot
outside# mkdir old_root
outside# pivot_root . old_root
limbo# exec chroot .
inside# umount /old_root
(Again, many of these commands are spawning new shells. unshare
does that, so does chroot
itself. You can work around those by passing commands as extra arguments. In some cases you might want to pass sh -c '...'
for a full script.)
At this point, you're inside a pivot_root
jail in a separate mount namespace, and the fact that /var/mychroot
is simply a directory of the original root (and not a mount of a separate device or loop device) didn't really prevent this from working, thanks to the bind mount into itself.
Running the escape code, you'll see that the jail works as expected (even though the escape code claims otherwise):
inside# touch /inside_jail
inside# ./escape_chroot
Exploit seems to work. =)
inside# # ls -ld /inside_jail /old_root
-rw-r--r--. 1 0 0 0 Jan 5 23:45 /inside_jail
dr-xr-xr-x. 20 0 0 4096 Jul 5 23:45 /old_root
As you can see, still inside the jail... The exploit code is just a bit naive and assumes that as long as the operations (chroot
, chdir
) have succeeded, that was enough to escape the jail, which is not really the case...
So consider using this technique to create a jail that is superior to chroot
and does not require using Linux capabilities to block operations inside it (such as creating additional chroot
s, which might actually be useful or required for what you're actually trying to run in a jail.)
To protect against the specific chdir("..")
escape technique you mentioned, you can simply drop the capability to execute chroot(2)
again once you're chrooted to /var/mychroot
yourself. The escape technique requires another call to chroot()
, so blocking that is enough to prevent it from working.
You can do that with Linux capabilities, by dropping CAP_SYS_CHROOT
which is the one needed for chroot(2)
to be available.
For example:
outside# chroot /var/mychroot
inside# capsh --drop=cap_sys_chroot --
inside# ./escape_chroot
chroot(baz): Operation not permitted
(The second prompt inside the chroot is from a shell spawned from capsh
. You can make it run another command with, for example, capsh --drop=cap_sys_chroot -- -c 'exec ./escape_chroot'
.)
But a much better technique is to just use pivot_root
, since it protects from many of the other possible exploits that chroot(2)
will not protect from.
You mentioned that it only works if /var/mychroot
is a mount point, but you can make it a mount point by simply bind mounting it into itself.
Note that you need to create a mount namespace to use pivot_root
to create a jail, otherwise it will try to change the root of all processes in your filesystem, which is most likely not what you want here...
So the whole sequence goes:
outside# unshare -m
outside# mount --bind /var/mychroot /var/mychroot
outside# cd /var/mychroot
outside# mkdir old_root
outside# pivot_root . old_root
limbo# exec chroot .
inside# umount /old_root
(Again, many of these commands are spawning new shells. unshare
does that, so does chroot
itself. You can work around those by passing commands as extra arguments. In some cases you might want to pass sh -c '...'
for a full script.)
At this point, you're inside a pivot_root
jail in a separate mount namespace, and the fact that /var/mychroot
is simply a directory of the original root (and not a mount of a separate device or loop device) didn't really prevent this from working, thanks to the bind mount into itself.
Running the escape code, you'll see that the jail works as expected (even though the escape code claims otherwise):
inside# touch /inside_jail
inside# ./escape_chroot
Exploit seems to work. =)
inside# # ls -ld /inside_jail /old_root
-rw-r--r--. 1 0 0 0 Jan 5 23:45 /inside_jail
dr-xr-xr-x. 20 0 0 4096 Jul 5 23:45 /old_root
As you can see, still inside the jail... The exploit code is just a bit naive and assumes that as long as the operations (chroot
, chdir
) have succeeded, that was enough to escape the jail, which is not really the case...
So consider using this technique to create a jail that is superior to chroot
and does not require using Linux capabilities to block operations inside it (such as creating additional chroot
s, which might actually be useful or required for what you're actually trying to run in a jail.)
answered Jan 5 at 7:51
filbrandenfilbranden
7,4002837
7,4002837
1
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
add a comment |
1
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
1
1
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
FYI I've found the command-line tool jchroot which automates this pivot_root(2) technique. I've verified on Linux 3.13 and 4.18 that the chdir("..") escape technique doesn't work with this pivot_root(2) technique as used by jchroot in github.com/vincentbernat/jchroot/blob/…
– pts
Jan 5 at 12:47
add a comment |
they only work if /var/mychroot is a mount point, so they fail if /var/mychroot is just a subdirectory within the / filesystem.
You can make any directory a mount point: mount --rbind /var/mychoot /var/mychoot
.
This step - and others that you will need - are covered here:
How to perform chroot with Linux namespaces?
In fact I want to prevent all kinds of chroot escapes
Combine the above with user namespaces.
Alternatively, seccomp
. This is how Docker prevents contained processes calling mount()
, for example. (When you mount a block device a second time, you get a second view of that filesystem, which more or less counts as an escape). Copy Docker's list of allowed syscalls - root has lots of different ways of escaping.
https://docs.docker.com/engine/security/seccomp/
https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
1
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
add a comment |
they only work if /var/mychroot is a mount point, so they fail if /var/mychroot is just a subdirectory within the / filesystem.
You can make any directory a mount point: mount --rbind /var/mychoot /var/mychoot
.
This step - and others that you will need - are covered here:
How to perform chroot with Linux namespaces?
In fact I want to prevent all kinds of chroot escapes
Combine the above with user namespaces.
Alternatively, seccomp
. This is how Docker prevents contained processes calling mount()
, for example. (When you mount a block device a second time, you get a second view of that filesystem, which more or less counts as an escape). Copy Docker's list of allowed syscalls - root has lots of different ways of escaping.
https://docs.docker.com/engine/security/seccomp/
https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
1
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
add a comment |
they only work if /var/mychroot is a mount point, so they fail if /var/mychroot is just a subdirectory within the / filesystem.
You can make any directory a mount point: mount --rbind /var/mychoot /var/mychoot
.
This step - and others that you will need - are covered here:
How to perform chroot with Linux namespaces?
In fact I want to prevent all kinds of chroot escapes
Combine the above with user namespaces.
Alternatively, seccomp
. This is how Docker prevents contained processes calling mount()
, for example. (When you mount a block device a second time, you get a second view of that filesystem, which more or less counts as an escape). Copy Docker's list of allowed syscalls - root has lots of different ways of escaping.
https://docs.docker.com/engine/security/seccomp/
https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
they only work if /var/mychroot is a mount point, so they fail if /var/mychroot is just a subdirectory within the / filesystem.
You can make any directory a mount point: mount --rbind /var/mychoot /var/mychoot
.
This step - and others that you will need - are covered here:
How to perform chroot with Linux namespaces?
In fact I want to prevent all kinds of chroot escapes
Combine the above with user namespaces.
Alternatively, seccomp
. This is how Docker prevents contained processes calling mount()
, for example. (When you mount a block device a second time, you get a second view of that filesystem, which more or less counts as an escape). Copy Docker's list of allowed syscalls - root has lots of different ways of escaping.
https://docs.docker.com/engine/security/seccomp/
https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
edited Jan 5 at 13:59
answered Jan 5 at 10:14
sourcejedisourcejedi
23.4k437103
23.4k437103
1
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
add a comment |
1
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
1
1
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
Thank you for both the solution and the insightful links on hardening a containers and chroot environments. Unfortunately it's not possible to accept multiple answers, but you have my very keen upvote.
– pts
Jan 5 at 12:51
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f492607%2fhow-to-create-a-chroot-from-which-root-cannot-escape-using-chdir-on-linux%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Why would you need root to run in a jail? Usually you'd drop root privileges once set up and depend on services or setuid exes for access to privileged calls and areas (e.g., network).
– melds
Jan 5 at 2:17
1
@melds: For example, running in a jail as root is useful if
apt-get install UNTRUSTED-PACKAGE
is run, where the the install script of the package can contain malicious code. A similar use case isdocker run UNTRUSTED-IMAGE
, the default commands of such packages run as root. Docker is not using chroot for filesystem isolation, and I'm also interested in understanding what would break if it did, and how it could be fixed.– pts
Jan 5 at 2:29