Bash script to create a chroot jail

For discussions about programming, programming questions/advice, and projects that don't really have anything to do with Puppy.
Post Reply
Message
Author
jamesjeffries2
Posts: 196
Joined: Mon 28 Apr 2008, 00:50

Bash script to create a chroot jail

#1 Post by jamesjeffries2 »

I am trying to write a script that will create a basic chroot jail. Here is the code so far:

Code: Select all

#!/bin/bash

# debugging only
rm -rf /tmp/chroot

# Set up chroot directory
mkdir /tmp/chroot
pushd /tmp/chroot
mkdir bin etc lib var home

# Copy in the relevant parts of the system
APPS="/bin/bash /bin/ls /bin/mkdir /bin/mv /bin/pwd /bin/rm /bin/ping"
for prog in $APPS; do
echo "===========";
echo $prog;
#sleep 1
cp $prog ./ --parents

# obtain a list of related libraries
ldd $prog > /dev/null
if [ "$?" = 0 ] ; then
LIBS=`ldd $prog | awk '{ print $3 }' | grep -v \(`
echo $LIBS
for l in $LIBS; do
#mkdir -p ./`dirname $l` > /dev/null 2>&1
cp $l ./ --parents
done
fi
done

popd

# change root
chroot /tmp/chroot /bin/bash
however when i run it I get the following error:

Code: Select all

chroot: can't execute '/bin/bash': No such file or directory

Anyone got much experience with chroot that might help?

Cheers,
Jim

big_bass
Posts: 1740
Joined: Mon 13 Aug 2007, 12:21

#2 Post by big_bass »

Hey jamesjeffries2

I use chroots a lot
on puppy , slackware and slitaz

now there are several way of doing this depending how complete you need it


.1.)simple for building basic packages
2.)runnnig the os for testing
3.) full os running same as a standard install

and there is always tweaking required to set it up
depending on the version

Joe

jamesjeffries2
Posts: 196
Joined: Mon 28 Apr 2008, 00:50

#3 Post by jamesjeffries2 »

Option 2 looks best to me.

This script was more just to see if I could get it working at a very basic level.

I can get it to work if I copy the whole of /bin and /lib accross, but want to see if I can build it up from the nothing to see what I can learn from it.

But also could be useful for packaging too, never occurred to me to use it for that before

amigo
Posts: 2629
Joined: Mon 02 Apr 2007, 06:52

#4 Post by amigo »

This is a little long, but I#ll post the whole thing -which is just a part of a routine for installing software in a chroot jail:

Code: Select all

# This file is part of the src2pkg program:
# Copyright 2005-2010 Gilbert Ashley <amigo@ibilio.org>
# src2pkg is released under the GNU General Public License Version 2

# This method installs all files into a 'false root' directory, the PKG_DIR,
# but uses unionfs and chroot rather than sentry.  This usually works when
# using DESTDIR and JAIL is not supported by the Makefiles and is less
# intrusive than installing to the real root directory, backing up overwritten
# files and then restoring them

## free_union
free_union() {
umount -l "$UNION_DIR/OBJ_DIR" &> /dev/null
umount -l "$UNION_DIR"/tmp &> /dev/null
umount -l "$UNION_DIR"/var/tmp &> /dev/null
umount -l "$UNION_DIR"/sys &> /dev/null
umount -l "$UNION_DIR"/proc &> /dev/null
umount -l "$UNION_DIR"/dev &> /dev/null
umount -l "$UNION_DIR" &> /dev/null
}
## User cancelled at a 'sensitive' spot, so scold them!
trap_union_int() {
  echo
  echo $RED"   *** OUCH!!! *** "$NORMAL"Dangerous cancellation"
  echo "   Please don't cancel while fake_install is running."
  echo "   Cleaning up hanging mounts on unionfs."
  free_union
  FAILED="CANCELLED"
  case $AUDIO_NOTIFICATION in
	BEEP)	echo -ne '\a';sleep .5;echo -ne '\a' ;;
	SAY)
		case $TTS_ENGINE in
			flite) flite "Dangerous cancellation" 2> /dev/null ;;
			festival) echo "Dangerous cancellation" |festival --tts 2> /dev/null ;;
		esac
		;;
	PLAY)	play /usr/share/src2pkg/sounds/ouch &> /dev/null ;;
  esac
  exit
}

install_to_union_root() {
echo $BLUE"Installing in UNION chroot - "$NORMAL"Using: '$INSTALL_COMMAND $INSTALL_RULE'"$NORMAL
UNION_DIR_NAME=$NAME-$VERSION-union-$BUILD$SIG
UNION_DIR="$PKG_BUILDS_DIR"/$UNION_DIR_NAME
EXCL_DIR_NAME=$NAME-$VERSION-excl-$BUILD$SIG
EXCL_DIR="$PKG_BUILDS_DIR"/$EXCL_DIR_NAME

mkdir -p "$PKG_DIR"

# don't do full recursive delete - losing important files if one of the
# excludes doesn't properly umount is a Very Bad Thing.
rmdir "$UNION_DIR" 2> /dev/null
rm -rf "$EXCL_DIR"
mkdir -p "$UNION_DIR"
mkdir -p "$EXCL_DIR"

# create mount-points for dirs we will be binding
mkdir -p "$EXCL_DIR"/dev
mkdir -p "$EXCL_DIR"/proc
mkdir -p "$EXCL_DIR"/sys
mkdir -p "$EXCL_DIR"/var/tmp
mkdir -p "$EXCL_DIR"/tmp


case "$UNIONFS_TYPE" in
   "unionfs")
      mount -t unionfs -o dirs="$PKG_DIR"=rw:/=ro:"$EXCL_DIR"=ro unionfs "$UNION_DIR"
   ;;
   "unionfs-fuse")
      unionfs -o cow "$PKG_DIR"=RW:/=RO:"$EXCL_DIR"=RO "$UNION_DIR"
   ;;
esac

# set the trap_union_int to be sure we don't leave mounts hanging if interrupted
trap trap_union_int 2

# bind the system dirs in the union root
mount --bind /dev "$UNION_DIR"/dev
mount --bind /proc "$UNION_DIR"/proc
mount --bind /sys "$UNION_DIR"/sys
mount --bind /var/tmp "$UNION_DIR"/var/tmp
mount --bind /tmp "$UNION_DIR"/tmp

# create an explicit and uniquely-named OBJ_DIR under the UNION_DIR. We need to do this because if the
# original OBJ_DIR is on a separate filesystem it won't be there under the UNION_DIR unless it is explicitly
# bind-mounted. We create a unique directory so we can safely and easily remove it afterwards.
# We do this in the UNION_DIR because it is RW -sometimes install create new files so we need OBJ_DIR writable
#mkdir -p "$EXCL_DIR"/OBJ_DIR
mkdir -p "$UNION_DIR"/OBJ_DIR
# bind the $OBJ_DIR in the union root
mount --bind "$OBJ_DIR" "$UNION_DIR"/OBJ_DIR

# we could use fakeroot for this step, but we'll need to also use it later when checking and correcting ownerships and perms
if [[ $LOG_COMMANDS = "YES" ]] ; then
	#
	if ! [[ $LOG_DIR ]] ; then
		LOG_DIR="$OBJ_DIR"
	elif [[ "$LOG_DIR" != "$CWD" ]] && [[ "${LOG_DIR:0:1}" != "/" ]] ; then
		echo $YELLOW"Warning! "$NORMAL"LOG_DIR is set to an invalid path."
		echo "         It must be set to \$CWD or an absolute path."
	fi
	echo $BLUE"Logging output to: "$NORMAL"LOG_DIR/$NAME-make-install.log"
	( chroot "$UNION_DIR" /bin/sh -c "cd OBJ_DIR && ${INSTALL_COMMAND} ${INSTALL_RULE} &> $NAME-make-install.log ; exit" )
	if ! [[ -f "$LOG_DIR"/$NAME-make-install.log ]] ; then
		cp "$OBJ_DIR"/$NAME-make-install.log "$LOG_DIR"/
	fi
elif [[ $QUIET = "YES" ]] ; then
	( chroot "$UNION_DIR" /bin/sh -c "cd OBJ_DIR && ${INSTALL_COMMAND} ${INSTALL_RULE} &> /dev/null ; exit" )
else
	( chroot "$UNION_DIR" /bin/sh -c "cd OBJ_DIR && ${INSTALL_COMMAND} ${INSTALL_RULE} ; exit" )
fi
RETVAL=$?

# unmount the OBJ_DIR
umount -l "$UNION_DIR/OBJ_DIR"
# after unmounting the $UNION_DIR/OBJ_DIR, remove
# the dir so it doesn't get included in the package
# ( cd "$UNION_DIR" && rm -rf OBJ_DIR )
rmdir "$UNION_DIR"/OBJ_DIR || echo $YELLOW"Warning - "$NORMAL"Unable to remove OBJ_DIR!"
# unmount the system dirs from the union root
umount -l "$UNION_DIR"/tmp
umount -l "$UNION_DIR"/var/tmp
umount -l "$UNION_DIR"/sys
umount -l "$UNION_DIR"/proc
umount -l "$UNION_DIR"/dev

if umount "$UNION_DIR" ; then
	true
else 
	echo $YELLOW"Warning - "$NORMAL"Forcing umount of UNION_DIR!"
	umount -l "$UNION_DIR"
fi

rmdir "$UNION_DIR" || echo $YELLOW"Warning - "$NORMAL"Unable to remove UNION_DIR!"

( cd "$PKG_BUILDS_DIR" && rm -rf $EXCL_DIR_NAME )

# Delete all metadata - really shouldn't be thrown away like this
case "$UNIONFS_TYPE" in
	"unionfs")
	find "$PKG_DIR" -name ".wh.*" -exec rm "{}" ";"
	;;
	"unionfs-fuse")
	rm -rf "$PKG_DIR/.unionfs/"
	;;
esac

# some tentative error handling
if [ $RETVAL -gt 0 ] ; then
	# FIXME: what post-processing needs to happen?
	echo "Failed"
	FAILED="CHROOT install in $FUNCNAME"
fi

}
The main points to obeserve are: don't copy file over as it takes a very long time and uses lots of disk space. Instead use 'miunt bind...' to duplicate the content; you don't have to use unionfs mounts, depending on what you are trying to do.
Maybe you should tell us what you are trying to do as there may be a better way than going to the trouble of creating a chroot.

jamesjeffries2
Posts: 196
Joined: Mon 28 Apr 2008, 00:50

#5 Post by jamesjeffries2 »

Just wanted to see how minimal I could get something to just run a web browser.

So that people could have completely secure browsing as the rest of the filesystem would be completely unreachable.

Not had much chance to look at this in the last couple of days due to work, but thinking about it im pretty sure /tmp doesnt allow you to execute stuff, so that could well be the problem.

EDIT: tried it not in /tmp but still no luck.

Cheers amigo thats quite useful, ill have a proper look at it later.

big_bass
Posts: 1740
Joined: Mon 13 Aug 2007, 12:21

#6 Post by big_bass »

jamesjeffries2

Code: Select all

 completely secure browsing as the rest of the filesystem would be completely unreachable. 
No, that wont work
all you would have to do would exit to prompt and type

Code: Select all

exit 
not much for security there :shock:

to leave the chroot

and you would have the full control

there are better ways and thats add user
just for browsing ? secured base OS
why not slitaz its already set up that way



Joe

aragon
Posts: 1698
Joined: Mon 15 Oct 2007, 12:18
Location: Germany

#7 Post by aragon »

although an old post, i thought i post a link i found today about a 'bash-sandbox'

http://igurublog.wordpress.com/download ... /#programs

aragon

Post Reply