From 7fd24086946f90347adc59a61beec621b555bdd7 Mon Sep 17 00:00:00 2001 From: cryx Date: Mon, 28 Dec 2009 22:09:17 +0000 Subject: Support for setting and using jail-bound ZFS datasets, cpuset(1) and setfib(1). Jail-bound ZFS datasets still need the usual zfs+jail stuff like security.jail.mount_allowed=1 and security.jail.enforce_statfs=0 as well as "add path zfs unhide" in the devfs.rules for the jail. The setfib utility requires FIBs to be enabled via kernel-config. All features need at least FreeBSD 7.1-RELEASE. --- ezjail-admin | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- ezjail.sh | 16 +++++++++ 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/ezjail-admin b/ezjail-admin index 1ba7fc9..b0fb6f8 100755 --- a/ezjail-admin +++ b/ezjail-admin @@ -46,7 +46,7 @@ ezjail_usage_install="Usage: ${ezjail_admin} install [-mMpPsS] [-h host] [-r rel ezjail_usage_create="Usage: ${ezjail_admin} create [-xbi] [-f flavour] [-r jailroot] [-s size] [-c bde|eli|zfs] [-C args] [-a archive] jailname jailip" ezjail_usage_delete="Usage: ${ezjail_admin} delete [-w] jailname" ezjail_usage_update="Usage: ${ezjail_admin} update [-s sourcetree] [-p] (-b|-i|-u|-P)" -ezjail_usage_config="Usage: ${ezjail_admin} config [-r run|norun] [-n newname] [-i attach|detach|fsck] jailname" +ezjail_usage_config="Usage: ${ezjail_admin} config [-r run|norun] [-n newname] [-c cpuset] [-z zfs-datasets] [-f fib] [-i attach|detach|fsck] jailname" ezjail_usage_console="Usage: ${ezjail_admin} console [-f] [-e command] jailname" ezjail_usage_archive="Usage: ${ezjail_admin} archive [-Af] [-a archive] [-d archivedir] jailname [jailname...]" ezjail_usage_restore="Usage: ${ezjail_admin} restore [-f] [-d archivedir] (archive|jailname)..." @@ -170,6 +170,9 @@ fetchjailinfo () { eval ezjail_attachparams=\"\$jail_${ezjail_safename}_attachparams\" eval ezjail_attachblocking=\"\$jail_${ezjail_safename}_attachblocking\" eval ezjail_forceblocking=\"\$jail_${ezjail_safename}_forceblocking\" + eval ezjail_zfs_datasets=\"\$jail_${ezjail_safename}_zfs_datasets\" + eval ezjail_cpuset=\"\$jail_${ezjail_safename}_cpuset\" + eval ezjail_fib=\"\$jail_${ezjail_safename}_fib\" ezjail_softlink=${ezjail_jaildir}/`basename -- "${ezjail_rootdir}"` ezjail_devicelink="${ezjail_rootdir}.device" @@ -615,6 +618,9 @@ create) echo export jail_${ezjail_safename}_attachparams=\"${ezjail_attachparams}\" echo export jail_${ezjail_safename}_attachblocking=\"${ezjail_attachblocking}\" echo export jail_${ezjail_safename}_forceblocking=\"${ezjail_forceblocking}\" + echo export jail_${ezjail_safename}_zfs_datasets=\"${ezjail_zfs_datasets}\" + echo export jail_${ezjail_safename}_cpuset=\"${ezjail_cpuset}\" + echo export jail_${ezjail_safename}_fib=\"${ezjail_fib}\" ) > "${ezjail_config}" # Final steps for flavour installation @@ -1142,12 +1148,15 @@ restore) ######################## ezjail-admin CONFIG ######################## config) # Clean variables, prevent polution - unset ezjail_setrunnable ezjail_imageaction ezjail_new_name + unset ezjail_setrunnable ezjail_imageaction ezjail_new_name ezjail_new_zfs_datasets ezjail_new_cpuset ezjail_new_fib - shift; while getopts :r:i:n: arg; do case ${arg} in + shift; while getopts :r:i:n:z:c:f: arg; do case ${arg} in i) ezjail_imageaction=${OPTARG};; r) ezjail_setrunnable=${OPTARG};; n) ezjail_new_name=${OPTARG};; + z) ezjail_new_zfs_datasets=${OPTARG};; + c) ezjail_new_cpuset=${OPTARG};; + f) ezjail_new_fib=${OPTARG};; ?) exerr ${ezjail_usage_config};; esac; done; shift $(( ${OPTIND} - 1 )) @@ -1160,7 +1169,7 @@ config) [ "${ezjail_config}" ] || exerr "Error: Nothing known about jail ${ezjail_name}." # Nothing to be configured? - [ "${ezjail_setrunnable}" -o "${ezjail_new_name}" -o "${ezjail_imageaction}" ] || echo "Warning: No config option specified." + [ "${ezjail_setrunnable}" -o "${ezjail_new_name}" -o "${ezjail_imageaction}" -o "${ezjail_new_zfs_datasets}" -o "${ezjail_new_cpuset}" -o "${ezjail_new_fib}" ] || echo "Warning: No config option specified." # Do we want a new name for our jail? if [ "${ezjail_new_name}" ]; then @@ -1190,12 +1199,15 @@ config) eval ezjail_new_attachblocking=\"\$jail_${ezjail_safename}_attachblocking\" eval ezjail_new_forceblocking=\"\$jail_${ezjail_safename}_forceblocking\" eval ezjail_new_imagetype=\"\$jail_${ezjail_safename}_imagetype\" + eval ezjail_new_zfs_datasets=\"\$jail_${ezjail_safename}_zfs_datasets\" + eval ezjail_new_cpuset=\"\$jail_${ezjail_safename}_cpuset\" + eval ezjail_new_fib=\"\$jail_${ezjail_safename}_fib\" # This scenario really will only lead to real troubles in the 'fulljail' # case, but I should still explain this to the user and not claim that # "an ezjail would already exist" case ${ezjail_new_hostname} in basejail|newjail|fulljail|flavours|ezjailtemp) exerr "Error: ezjail needs the ${ezjail_new_hostname} directory for its own administrative purposes.\n Please chose another name.";; esac - + # jail names may lead to identical configs, eg. foo.bar.com == foo-bar.com # so check, whether we might be running into problems [ -e "${ezjail_new_config}" -o -e "${ezjail_new_config}.norun" ] && exerr "Error: An ezjail config already exists at ${ezjail_new_config}.\n Please chose another name." @@ -1264,6 +1276,9 @@ config) echo export jail_${ezjail_new_safename}_attachparams=\"${ezjail_new_attachparams}\" echo export jail_${ezjail_new_safename}_attachblocking=\"${ezjail_new_attachblocking}\" echo export jail_${ezjail_new_safename}_forceblocking=\"${ezjail_new_forceblocking}\" + echo export jail_${ezjail_new_safename}_zfs_datasets=\"${ezjail_new_zfs_datasets}\" + echo export jail_${ezjail_new_safename}_cpuset=\"${ezjail_new_cpuset}\" + echo export jail_${ezjail_new_safename}_fib=\"${ezjail_new_fib}\" ) > "${ezjail_new_config}" # remove old config @@ -1278,6 +1293,97 @@ config) fetchjailinfo ${ezjail_new_safename} fi + if [ "${ezjail_new_zfs_datasets}" ]; then + # if jail is still running, refuse to go any further + [ "${ezjail_id}" ] && exerr "Error: Jail appears to be still running.\n '${ezjail_admin} stop ${ezjail_name}' it first ." + + # write new config file, preserve comments + ( + grep -e ^\# "${ezjail_config}" + echo + echo export jail_${ezjail_safename}_hostname=\"${ezjail_hostname}\" + echo export jail_${ezjail_safename}_ip=\"${ezjail_ip}\" + echo export jail_${ezjail_safename}_rootdir=\"${ezjail_rootdir}\" + echo export jail_${ezjail_safename}_exec=\"${ezjail_exec}\" + echo export jail_${ezjail_safename}_mount_enable=\"${ezjail_mount_enable}\" + echo export jail_${ezjail_safename}_devfs_enable=\"${ezjail_devfs_enable}\" + echo export jail_${ezjail_safename}_devfs_ruleset=\"${ezjail_devfs_ruleset}\" + echo export jail_${ezjail_safename}_procfs_enable=\"${ezjail_procfs_enable}\" + echo export jail_${ezjail_safename}_fdescfs_enable=\"${ezjail_fdescfs_enable}\" + echo export jail_${ezjail_safename}_image=\"${ezjail_image}\" + echo export jail_${ezjail_safename}_imagetype=\"${ezjail_imagetype}\" + echo export jail_${ezjail_safename}_attachparams=\"${ezjail_attachparams}\" + echo export jail_${ezjail_safename}_attachblocking=\"${ezjail_attachblocking}\" + echo export jail_${ezjail_safename}_forceblocking=\"${ezjail_forceblocking}\" + echo export jail_${ezjail_safename}_zfs_datasets=\"${ezjail_new_zfs_datasets}\" + echo export jail_${ezjail_safename}_cpuset=\"${ezjail_cpuset}\" + echo export jail_${ezjail_safename}_fib=\"${ezjail_fib}\" + ) > "${ezjail_config}_" + mv "${ezjail_config}_" "${ezjail_config}" + fi + + if [ "${ezjail_new_cpuset}" ]; then + # configure the new cpuset if the jail is currently running + [ "${ezjail_id}" ] && /usr/bin/cpuset -l ${ezjail_new_cpuset} -j ${ezjail_id} || exerr "Error: The defined cpuset is malformed" + + # write new config file, preserve comments + ( + grep -e ^\# "${ezjail_config}" + echo + echo export jail_${ezjail_safename}_hostname=\"${ezjail_hostname}\" + echo export jail_${ezjail_safename}_ip=\"${ezjail_ip}\" + echo export jail_${ezjail_safename}_rootdir=\"${ezjail_rootdir}\" + echo export jail_${ezjail_safename}_exec=\"${ezjail_exec}\" + echo export jail_${ezjail_safename}_mount_enable=\"${ezjail_mount_enable}\" + echo export jail_${ezjail_safename}_devfs_enable=\"${ezjail_devfs_enable}\" + echo export jail_${ezjail_safename}_devfs_ruleset=\"${ezjail_devfs_ruleset}\" + echo export jail_${ezjail_safename}_procfs_enable=\"${ezjail_procfs_enable}\" + echo export jail_${ezjail_safename}_fdescfs_enable=\"${ezjail_fdescfs_enable}\" + echo export jail_${ezjail_safename}_image=\"${ezjail_image}\" + echo export jail_${ezjail_safename}_imagetype=\"${ezjail_imagetype}\" + echo export jail_${ezjail_safename}_attachparams=\"${ezjail_attachparams}\" + echo export jail_${ezjail_safename}_attachblocking=\"${ezjail_attachblocking}\" + echo export jail_${ezjail_safename}_forceblocking=\"${ezjail_forceblocking}\" + echo export jail_${ezjail_safename}_zfs_datasets=\"${ezjail_zfs_datasets}\" + echo export jail_${ezjail_safename}_cpuset=\"${ezjail_new_cpuset}\" + echo export jail_${ezjail_safename}_fib=\"${ezjail_fib}\" + ) > "${ezjail_config}_" + mv "${ezjail_config}_" "${ezjail_config}" + + fi + + if [ "${ezjail_new_fib}" ]; then + # if jail is still running, refuse to go any further + [ "${ezjail_id}" ] && exerr "Error: Jail appears to be still running.\n '${ezjail_admin} stop ${ezjail_name}' it first ." + [ "${ezjail_new_fib}" -ge "0" ] && exerr "Error: fib number has to be an integer." + + # write new config file, preserve comments + ( + grep -e ^\# "${ezjail_config}" + echo + echo export jail_${ezjail_safename}_hostname=\"${ezjail_hostname}\" + echo export jail_${ezjail_safename}_ip=\"${ezjail_ip}\" + echo export jail_${ezjail_safename}_rootdir=\"${ezjail_rootdir}\" + echo export jail_${ezjail_safename}_exec=\"${ezjail_exec}\" + echo export jail_${ezjail_safename}_mount_enable=\"${ezjail_mount_enable}\" + echo export jail_${ezjail_safename}_devfs_enable=\"${ezjail_devfs_enable}\" + echo export jail_${ezjail_safename}_devfs_ruleset=\"${ezjail_devfs_ruleset}\" + echo export jail_${ezjail_safename}_procfs_enable=\"${ezjail_procfs_enable}\" + echo export jail_${ezjail_safename}_fdescfs_enable=\"${ezjail_fdescfs_enable}\" + echo export jail_${ezjail_safename}_image=\"${ezjail_image}\" + echo export jail_${ezjail_safename}_imagetype=\"${ezjail_imagetype}\" + echo export jail_${ezjail_safename}_attachparams=\"${ezjail_attachparams}\" + echo export jail_${ezjail_safename}_attachblocking=\"${ezjail_attachblocking}\" + echo export jail_${ezjail_safename}_forceblocking=\"${ezjail_forceblocking}\" + echo export jail_${ezjail_safename}_zfs_datasets=\"${ezjail_zfs_datasets}\" + echo export jail_${ezjail_safename}_cpuset=\"${ezjail_cpuset}\" + echo export jail_${ezjail_safename}_fib=\"${ezjail_new_fib}\" + ) > "${ezjail_config}_" + mv "${ezjail_config}_" "${ezjail_config}" + + fi + + case "${ezjail_setrunnable}" in run) [ "${ezjail_config}" = "${ezjail_config%.norun}" ] || mv "${ezjail_config}" "${ezjail_config%.norun}";; norun) [ "${ezjail_config}" = "${ezjail_config%.norun}" ] && mv "${ezjail_config}" "${ezjail_config}.norun" ;; diff --git a/ezjail.sh b/ezjail.sh index 6df6358..eb5e251 100755 --- a/ezjail.sh +++ b/ezjail.sh @@ -65,6 +65,8 @@ do_cmd() eval ezjail_attachparams=\"\$jail_${ezjail}_attachparams\" eval ezjail_attachblocking=\"\$jail_${ezjail}_attachblocking\" eval ezjail_forceblocking=\"\$jail_${ezjail}_forceblocking\" + eval ezjail_zfs_datasets=\"\$jail_${ezjail}_zfs_datasets\" + eval ezjail_cpuset=\"\$jail_${ezjail}_cpuset\" # Do we still have a root to run in? [ ! -d "${ezjail_rootdir}" ] && echo " Warning: root directory ${ezjail_rootdir} of ${ezjail} does not exist." && continue @@ -88,6 +90,20 @@ do_cmd() # Pass control to jail script which does the actual work [ "${ezjail_pass}" ] && sh /etc/rc.d/jail one${action%crypto} ${ezjail_pass} + if [ "${action}" = "start" ]; then + ezjail_safename=`echo -n "${ezjail}" | tr -c '[:alnum:]' _` + # Get the JID of the jail + [ -f "/var/run/jail_${ezjail_safename}.id" ] && ezjail_id=`cat /var/run/jail_${ezjail_safename}.id` || return + + # Attach ZFS-datasets to the jail + for zfs in ${ezjail_zfs_datasets}; do + /sbin/zfs jail ${ezjail_id} ${zfs} ||Êecho -n "Error: ${zfs} could not be configured" + done + + # Configure processor sets for the jail via cpuset(1) + [ "${ezjail_cpuset}" ] && /usr/bin/cpuset -l ${ezjail_cpuset} -j ${ezjail_id} || echo -n "Error: The defined cpuset is malformed" + fi + # Can only detach after unmounting (from fstab.JAILNAME in /etc/rc.d/jail) attach_detach_post } -- cgit v1.2.3