The jail approach mentioned in previous articles has been implemented on the dev system. It took about 4 hours of coding this afternoon.
The setup script
I spent some time today gathering together the stuff I’d mentioned in the two previous posts on this topic. The result is a one-line command which will create a chroot environment, complete with mount points and scripts, and output the required /etc/fstab entries. I created a Jail subdirectory in the main scripts directory. In there, we have:
$ find . . ./CVS ./CVS/Root ./CVS/Repository ./CVS/Entries ./scripts ./scripts/CVS ./scripts/CVS/Root ./scripts/CVS/Repository ./scripts/CVS/Entries ./scripts/vars.sh ./scripts/make-port.sh ./scripts/make-master-port-test.sh ./scripts/make-category-comment.sh ./README.txt ./create-jail-directories.sh $ cat README.txt FreshPorts now uses a chroot strategy for extracting information from the ports tree. To create the chroot structure, which I often refer to as a jail, issue the following command: ./create-jail-directories.sh ~/tmp/JAIL /home/dan/PORTS-SVN The directory structure will be created at ~/tmp/JAIL The system expects an up-to-date copy of the ports tree at /home/dan/PORTS-SVN The scripts required for the jail will be copied to the base directory of the jail. These scripts are located in the scripts subdirectory relative to the file you are reading now. This script will output a number of mount points which need to be added to /etc/fstab. After doing that, issue a 'mount -a' command and your jail structure is complete and ready to do.
To setup my jail directory, I issued this command:
$ ./create-jail-directories.sh /var/FreshPorts/jail /wdc/dan/PORTS-SVNSVN # Put the following in /etc/fstab /wdc/dan/PORTS-SVN /var/FreshPorts/jail/usr/ports nullfs ro,nosuid,noexec 0 0 /usr/share/mk /var/FreshPorts/jail/usr/share/mk nullfs ro,nosuid,noexec 0 0 /usr/sbin /var/FreshPorts/jail/usr/sbin nullfs ro,nosuid 0 0 /usr/bin /var/FreshPorts/jail/usr/bin nullfs ro,nosuid 0 0 /libexec /var/FreshPorts/jail/libexec nullfs ro,nosuid 0 0 /usr/lib /var/FreshPorts/jail/usr/lib nullfs ro,nosuid 0 0 /sbin /var/FreshPorts/jail/sbin nullfs ro,nosuid 0 0 /lib /var/FreshPorts/jail/lib nullfs ro,nosuid 0 0 /bin /var/FreshPorts/jail/bin nullfs ro,nosuid 0 0 none /var/FreshPorts/jail/dev devfs rw 0 0
As you can see, the root directory is populated with the required scripts:
$ ls /var/FreshPorts/jail bin lib make-category-comment.sh make-port.sh usr dev libexec make-master-port-test.sh sbin vars.sh
The code changes
The source code changes were pretty minimal. I’ll let you judge for yourself:
cvs diff: Diffing . Index: category.pm =================================================================== RCS file: /home/repositories/freshports-1/scripts/category.pm,v retrieving revision 1.10 diff -u -r1.10 category.pm --- category.pm 18 Dec 2009 17:22:04 -0000 1.10 +++ category.pm 29 Dec 2012 21:48:04 -0000 @@ -202,10 +202,11 @@ chdir "$MakefileDirectory"; - my $makecommand = "make -V COMMENT " . - "DISTDIR=$FreshPorts::Constants::DISTDIR " . - "PORTSDIR=$FreshPorts::Config::path_to_ports LOCALBASE=/nonexistentlocal 2>$TmpFile"; +# my $makecommand = "make -V COMMENT " . +# "DISTDIR=$FreshPorts::Constants::DISTDIR " . +# "PORTSDIR=$FreshPorts::Config::path_to_ports LOCALBASE=/nonexistentlocal 2>$TmpFile"; + my $makecommand = "/usr/local/bin/sudo /usr/sbin/chroot -u $FreshPorts::Config::JailUser $FreshPorts::Config::JailBaseDir $FreshPorts::Config::JailCategoryDescrptionScript $category 2>$TmpFile"; print "makecommand = $makecommand\n"; my $MakeResults = `$makecommand`; Index: port.pm =================================================================== RCS file: /home/repositories/freshports-1/scripts/port.pm,v retrieving revision 1.69 diff -u -r1.69 port.pm --- port.pm 25 Sep 2012 18:11:23 -0000 1.69 +++ port.pm 29 Dec 2012 21:48:04 -0000 @@ -442,14 +442,16 @@ # IF YOU CHANGE THE MAKE COMMAND, CHANGE THE SPLIT!!!!!!!!!!!!!!! # # - $makecommand = "make -V PORTNAME -V PKGNAME -V DESCR -V CATEGORIES -V PORTVERSION -V PORTREVISION " . - " -V COMMENT -V COMMENTFILE -V MAINTAINER -V EXTRACT_SUFX " . - " -V BUILD_DEPENDS -V RUN_DEPENDS -V LIB_DEPENDS -V FORBIDDEN -V BROKEN -V DEPRECATED -V IGNORE ". - " -V MASTER_PORT -V LATEST_LINK -V NO_LATEST_LINK -V NO_PACKAGE -V PKGNAMEPREFIX -V PKGNAMESUFFIX -V PORTEPOCH " . - " -V RESTRICTED -V NO_CDROM -V EXPIRATION_DATE -V IS_INTERACTIVE " . - " -V ONLY_FOR_ARCHS -V NOT_FOR_ARCHS -V LICENSE -f $Makefile " . - " DISTDIR=$FreshPorts::Constants::DISTDIR " . - " PORTSDIR=$FreshPorts::Config::path_to_ports LOCALBASE=/nonexistentlocal 2>$TmpFile"; +# $makecommand = "make -V PORTNAME -V PKGNAME -V DESCR -V CATEGORIES -V PORTVERSION -V PORTREVISION " . +# " -V COMMENT -V COMMENTFILE -V MAINTAINER -V EXTRACT_SUFX " . +# " -V BUILD_DEPENDS -V RUN_DEPENDS -V LIB_DEPENDS -V FORBIDDEN -V BROKEN -V DEPRECATED -V IGNORE ". +# " -V MASTER_PORT -V LATEST_LINK -V NO_LATEST_LINK -V NO_PACKAGE -V PKGNAMEPREFIX -V PKGNAMESUFFIX -V PORTEPOCH " . +# " -V RESTRICTED -V NO_CDROM -V EXPIRATION_DATE -V IS_INTERACTIVE " . +# " -V ONLY_FOR_ARCHS -V NOT_FOR_ARCHS -V LICENSE -f $Makefile " . +# " DISTDIR=$FreshPorts::Constants::DISTDIR " . +# " PORTSDIR=$FreshPorts::Config::path_to_ports LOCALBASE=/nonexistentlocal 2>$TmpFile"; + + $makecommand = "/usr/local/bin/sudo /usr/sbin/chroot -u $FreshPorts::Config::JailUser $FreshPorts::Config::JailBaseDir $FreshPorts::Config::JailPortScript $this->{category}/$this->{name} 2>$TmpFile"; print "makecommand = $makecommand\n"; @@ -801,7 +803,7 @@ return $result; } -sub _FetchFilesNeedingRefresh { +sub _FetchFilesNeedingRefresh_DELETE_ME { # returns 0 for success, 1 for failure # a return of -1 indicates an error. @@ -858,7 +860,7 @@ my $makecommand = "make -V DESCR -f $SVNDIR/$SVNITEM PORTSDIR=$FreshPorts::Config::path_to_ports " . "LOCALBASE=/nonexistentlocal 2>$TmpFile"; - + print "makecommand = $makecommand\n"; my $MakeResults = `$makecommand`; my $Result = $?; @@ -1040,7 +1042,7 @@ } else { - $result = $this->_FetchFilesNeedingRefresh(); + die('I have no idea what I am doing here in RefreshFromFiles....'); } if ($result == -1) { $FetchAttempts = 0; Index: test-master-port.sh =================================================================== RCS file: /home/repositories/freshports-1/scripts/test-master-port.sh,v retrieving revision 1.5 diff -u -r1.5 test-master-port.sh --- test-master-port.sh 15 Aug 2012 11:48:47 -0000 1.5 +++ test-master-port.sh 29 Dec 2012 21:48:04 -0000 @@ -15,8 +15,7 @@ MASTER='sysutils/bacula-server' -cd ${PORTSDIR}/sysutils/bacula-client -COMMAND="make -V MASTER_PORT PORTSDIR=${PORTSDIR} LOCALBASE=/nonexistentlocal X11BASE=/nonexistentx" +COMMAND="/usr/local/bin/sudo /usr/sbin/chroot -u ${FRESHPORTS_JAIL_USER} ${FRESHPORTS_JAIL_BASE_DIR} ${FRESHPORTS_JAIL_MASTER_PORT_SCRIPT} sysutils/bacula-client" MASTER_PORT=`${COMMAND}` if [ "${MASTER_PORT}X" != "${MASTER}X" ]
Not shown are some changes to sample configuration files. They appear here:
--- scripts/config.sh.sample 2007/10/15 18:17:22 1.8 +++ scripts/config.sh.sample 2012/12/29 21:51:51 1.11 @@ -1,6 +1,6 @@ #!/bin/sh # -# $Id: config.sh.sample,v 1.8 2007/10/15 18:17:22 dan Exp $ +# $Id: config.sh.sample,v 1.11 2012/12/29 21:51:51 dan Exp $ # # this must always be defined and functional. @@ -71,3 +71,8 @@ fi # define your local cvsup host here FREEBSDCVSUPHOST="cvsup.unixathome.org" + +# scripts for the jail +FRESHPORTS_JAIL_BASE_DIR="/var/FreshPorts/jail" +FRESHPORTS_JAIL_MASTER_PORT_SCRIPT="/make-master-port-test.sh" +FRESHPORTS_JAIL_USER="freshports"
--- scripts/config.pm.sample 2012/09/26 19:32:03 1.22 +++ scripts/config.pm.sample 2012/12/29 21:51:50 1.24 @@ -1,5 +1,5 @@ # -# $Id: config.pm.sample,v 1.22 2012/09/26 19:32:03 dan Exp $ +# $Id: config.pm.sample,v 1.24 2012/12/29 21:51:50 dan Exp $ # # Copyright (c) 2001-2007 DVL Software # @@ -129,4 +129,11 @@ $FreshPorts::Config::DB_Root_Prefix_SRC $FreshPorts::Config::Ports_Default_Directory = $FreshPorts::Config::DB_Root_Prefix_PORTS . '/head'; +# scripts for the jail +$FreshPorts::Config::JailBaseDir = '/var/FreshPorts/jail' + +$FreshPorts::Config::JailCategoryDescrptionScript = '/make-category-comment.sh'; +$FreshPorts::Config::JailPortScript = '/make-port.sh'; +$FreshPorts::Config::JailUser = 'freshports'; + 1;
visudo
The command to run in the chroot environment uses sudo. To allow that to happen without passwords, I’ve added the following lines to sudoers:
freshports ALL=(ALL) NOPASSWD:/usr/sbin/chroot -u dan /wdc/dan/FreshPorts/ports-jail /make-port.sh * freshports ALL=(ALL) NOPASSWD:/usr/sbin/chroot -u dan /wdc/dan/FreshPorts/ports-jail /make-category-comment.sh * freshports ALL=(ALL) NOPASSWD:/usr/sbin/chroot -u dan /wdc/dan/FreshPorts/ports-jail /make-master-port-test.sh *
You will notice that I have used a wildcard at the end of the line. How big of a security risk is this? What could possibly go wrong there? The expected values are category names and port names (e.g. sysutils and sysutils/bacula-server, respectively). I guess I could make those more specific… Anyone want to take a try at that?
Left to do
- You can see I use the freshports user above. There is no such thing. I run these commands under my own user login. I should create a separate user.
- At present, this code is sitting in my development environment. I’ll check it in later.
- I need a new category to be created. Anyone got one ready to go? I guess I could test this by setting up my own SVN, committing to it, and using that for testing. One day… one day.
- All the ports need to refreshed now that we extract values from a jail. The script do to this exists. But it takes a long time to run it over all the ports.
This code has been committed and migrated to beta.