[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freebsd-jail
Subject:    Auto-jailing of services - 2nd implementation
From:       Alexander Leidinger <Alexander () leidinger ! net>
Date:       2022-04-03 19:48:42
Message-ID: 20220403214842.Horde.vlwSVh0KOZ6sL7aDfgA9KKL () webmail ! leidinger ! net
[Download RAW message or body]

This message is in MIME format and has been PGP signed.

[Attachment #2 (multipart/mixed)]
This message is in MIME format.


Hi,

attached is a new implementation of service jails (auto-jailing of  
services). This one now supports rc command prefixes (e.g. onestart)  
and I tested it in nested jails. The benefit of auto-jailing services  
is, that you can apply some restrictions to services (and what other  
processes it may see). If your service requires access to network but  
not sysvipc, and it doesn't run as root, it can be limited to network  
access with or without raw sockets, filesystem-permitted files, and  
doesn't see other processes on the system.

For a few services I have added the required "svcj-config" in the  
start scripts (e.g. network access for syslog by setting  
syslogd_svj_options=net_basic).

Possible svcj config options for service jails:
+				netv4)
+					_svcj_cmd_options="ip4=inherit allow.reserved_ports  
${_svcj_cmd_options}"
+					;;
+				netv6)
+					_svcj_cmd_options="ip6=inherit allow.reserved_ports  
${_svcj_cmd_options}"
+					;;
+				net_basic)
+					_svcj_cmd_options="ip4=inherit ip6=inherit allow.reserved_ports  
${_svcj_cmd_options}"
+					;;
+				net_raw)
+					_svcj_cmd_options="allow.raw_sockets ${_svcj_cmd_options}"
+					;;
+				net_all)
+					_svcj_cmd_options="allow.socket_af allow.raw_sockets  
allow.reserved_ports ip4=inherit ip6=inherit ${_svcj_cmd_options}"
+					;;
+				sysvipc)
+					_svcj_cmd_options="sysvmsg=inherit sysvsem=inherit  
sysvshm=inherit  ${_svcj_cmd_options}"
+					;;
+				mlock)
+					_svcj_cmd_options="allow.mlock ${_svcj_cmd_options}"
+					;;
+				vmm)
+					_svcj_cmd_options="allow.vmm ${_svcj_cmd_options}"

By setting syslogd_svcj="YES" in rc.conf your syslogd will be started  
in a jail which inherits the full filesystem and the ipv4 and ipv6  
addresses of the parent.

It would be nice if interested people could experiment a little bit  
with this, e.g. adding name_svcj_options="X Y" from above and  
name_svcj="YES" into rc.conf and see if it works. Note, doing that for  
sshd doesn't make sense in the generic case, it wouldn't see your  
jails. It may make sense for services.

Any kind of feedback and tested name_svcj_options submissions welcome...

Bye,
Alexander.

-- 
http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF
http://www.FreeBSD.org    netchild@FreeBSD.org  : PGP 0x8F31830F9F2772BF

["svcj.diff" (text/diff)]

diff --git a/libexec/rc/rc.d/auditdistd b/libexec/rc/rc.d/auditdistd
index 13cb5d5b69d..3218bd35755 100755
--- a/libexec/rc/rc.d/auditdistd
+++ b/libexec/rc/rc.d/auditdistd
@@ -19,4 +19,7 @@ required_files="/etc/security/${name}.conf"
 extra_commands="reload"
 
 load_rc_config $name
+
+: ${auditdistd_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/ftpd b/libexec/rc/rc.d/ftpd
index dc623ea5943..a04c7ce5ee2 100755
--- a/libexec/rc/rc.d/ftpd
+++ b/libexec/rc/rc.d/ftpd
@@ -23,4 +23,7 @@ ftpd_prestart()
 }
 
 load_rc_config $name
+
+: ${ftpd_svcj_options:="net_all"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/inetd b/libexec/rc/rc.d/inetd
index aa8ac20aeae..8cf7be5d91e 100755
--- a/libexec/rc/rc.d/inetd
+++ b/libexec/rc/rc.d/inetd
@@ -18,4 +18,7 @@ required_files="/etc/${name}.conf"
 extra_commands="reload"
 
 load_rc_config $name
+
+: ${inetd_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/kadmind b/libexec/rc/rc.d/kadmind
index 773b2d0e499..1bdd420e415 100755
--- a/libexec/rc/rc.d/kadmind
+++ b/libexec/rc/rc.d/kadmind
@@ -26,4 +26,7 @@ kadmind_start_precmd()
 }
 
 load_rc_config $name
+
+: ${kadmind_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/kdc b/libexec/rc/rc.d/kdc
index c2747ae08ca..11205d6e092 100755
--- a/libexec/rc/rc.d/kdc
+++ b/libexec/rc/rc.d/kdc
@@ -26,4 +26,7 @@ kdc_start_precmd()
 }
 
 load_rc_config $name
+
+: ${kdc_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/kpasswdd b/libexec/rc/rc.d/kpasswdd
index a2875bf1515..af7b7a6b9aa 100755
--- a/libexec/rc/rc.d/kpasswdd
+++ b/libexec/rc/rc.d/kpasswdd
@@ -26,4 +26,7 @@ kpasswdd_start_precmd()
 }
 
 load_rc_config $name
+
+: ${kapsswd_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/local_unbound b/libexec/rc/rc.d/local_unbound
index 19cb9a6c5c0..7436034495f 100755
--- a/libexec/rc/rc.d/local_unbound
+++ b/libexec/rc/rc.d/local_unbound
@@ -34,6 +34,7 @@ load_rc_config $name
 : ${local_unbound_anchor:=${local_unbound_workdir}/root.key}
 : ${local_unbound_forwarders:=}
 : ${local_unbound_tls:=}
+: ${local_unbound_svcj_options:="net_basic"}
 
 do_as_unbound()
 {
diff --git a/libexec/rc/rc.d/lpd b/libexec/rc/rc.d/lpd
index fc8180cb221..725adda9072 100755
--- a/libexec/rc/rc.d/lpd
+++ b/libexec/rc/rc.d/lpd
@@ -25,4 +25,7 @@ chkprintcap()
 }
 
 load_rc_config $name
+
+: ${lpd_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.d/syslogd b/libexec/rc/rc.d/syslogd
index 2351c086212..95d2b156b88 100755
--- a/libexec/rc/rc.d/syslogd
+++ b/libexec/rc/rc.d/syslogd
@@ -71,4 +71,7 @@ set_socketlist()
 	echo $_socketargs
 }
 load_rc_config $name
+
+: ${syslogd_svcj_options:="net_basic"}
+
 run_rc_command "$1"
diff --git a/libexec/rc/rc.subr b/libexec/rc/rc.subr
index dc4f49612c2..f339738c0a3 100644
--- a/libexec/rc/rc.subr
+++ b/libexec/rc/rc.subr
@@ -51,6 +51,9 @@ PROTECT="/usr/bin/protect"
 ID="/usr/bin/id"
 IDCMD="if [ -x $ID ]; then $ID -un; fi"
 PS="/bin/ps -ww"
+SERVICE=/usr/sbin/service
+JAIL_CMD=/usr/sbin/jail
+_svcj_generic_params="path=/ mount.nodevfs host=inherit"
 JID=0
 # rc_service provides the path to the service script that we are executing.
 # This is not being set here in an execution context, necessarily, so it's
@@ -368,6 +371,16 @@ _find_processes()
 		    $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})"|"[${_procnamebn}]")'
  fi
 
+	if checkyesno ${name}_svcj; then
+		JID=$(/usr/sbin/jls -j svcj-${name} jid)
+
+		case ${JID} in
+		''|*[!0-9]*)
+			# svj-jail doesn't exist, fallback to host-check
+			JID=0
+			;;
+		esac
+	fi
 	_proccheck="\
 		$PS 2>/dev/null -o pid= -o jid= -o command= $_psargs"' |
 		while read _npid _jid '"$_fp_args"'; do
@@ -959,6 +972,18 @@ run_rc_command()
 	_pidcmd=
 	_procname=${procname:-${command}}
 
+	# If a specifc jail has a specific svcj request, honor it (YES/NO).
+	# If not (variable empty), evaluate the global svcj catch-call.
+	# A global YES can be overriden by a specific NO, and a global NO is overriden
+	# by a specific YES.
+	eval _svcj=\$${name}_svcj
+	if [ -z "$_svcj" ]; then
+		_svcj=${svcj_all_enable}
+		if [ -z "$_svcj" ]; then
+			eval ${name}_svcj=NO
+		fi
+	fi
+
 					# setup pid check command
 	if [ -n "$_procname" ]; then
 		if [ -n "$pidfile" ]; then
@@ -994,7 +1019,7 @@ run_rc_command()
 	    _fib=\$${name}_fib		_env=\$${name}_env \
 	    _prepend=\$${name}_prepend	_login_class=\${${name}_login_class:-daemon} \
 	    _limits=\$${name}_limits    _oomprotect=\$${name}_oomprotect \
-	    _env_file=\$${name}_env_file
+	    _env_file=\$${name}_env_file _svcj_options=\$${name}_svcj_options
 
 	if [ -n "$_env_file" ] && [ -r "${_env_file}" ]; then	# load env from file
 		set -a
@@ -1008,6 +1033,42 @@ run_rc_command()
 		fi
 	fi
 
+	if [ -n "$_svcj_options" ]; then	# translate service jail options
+		_svcj_cmd_options=""
+
+		for _svcj_option in $_svcj_options; do
+			case "$_svcj_option" in
+				netv4)
+					_svcj_cmd_options="ip4=inherit allow.reserved_ports ${_svcj_cmd_options}"
+					;;
+				netv6)
+					_svcj_cmd_options="ip6=inherit allow.reserved_ports ${_svcj_cmd_options}"
+					;;
+				net_basic)
+					_svcj_cmd_options="ip4=inherit ip6=inherit allow.reserved_ports \
${_svcj_cmd_options}" +					;;
+				net_raw)
+					_svcj_cmd_options="allow.raw_sockets ${_svcj_cmd_options}"
+					;;
+				net_all)
+					_svcj_cmd_options="allow.socket_af allow.raw_sockets allow.reserved_ports \
ip4=inherit ip6=inherit ${_svcj_cmd_options}" +					;;
+				sysvipc)
+					_svcj_cmd_options="sysvmsg=inherit sysvsem=inherit sysvshm=inherit  \
${_svcj_cmd_options}" +					;;
+				mlock)
+					_svcj_cmd_options="allow.mlock ${_svcj_cmd_options}"
+					;;
+				vmm)
+					_svcj_cmd_options="allow.vmm ${_svcj_cmd_options}"
+					;;
+				*)
+					echo ${name}: unknown service jail option: $_svcj_option
+					;;
+			esac
+		done
+	fi
+
 	[ -z "$autoboot" ] && eval $_pidcmd	# determine the pid if necessary
 
 	for _elem in $_keywords; do
@@ -1053,9 +1114,50 @@ run_rc_command()
 			if [ -n "$_env" ]; then
 				eval "export -- $_env"
 			fi
-			_run_rc_precmd || return 1
-			_run_rc_doit "$_cmd $rc_extra_args" || return 1
-			_run_rc_postcmd
+
+			if [ "${_rc_svcj}" != jailing ]; then
+				_run_rc_precmd || return 1
+			fi
+			if ! checkyesno ${name}_svcj; then
+				_run_rc_doit "$_cmd $rc_extra_args" || return 1
+			else
+				case "$rc_arg" in
+				start)
+					if [ "${_rc_svcj}" != jailing ]; then
+						_return=1
+						$JAIL_CMD -c $_svcj_generic_params $_svcj_cmd_options \
+						    exec.start="export _rc_svcj=jailing; for d in /etc/rc.d $local_startup; do \
[ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}start $rc_extra_args && break; done" \ \
+						    exec.stop="export _rc_svcj=jailing; for d in /etc/rc.d $local_startup; do \
[ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}stop $rc_extra_args && break; done" \ \
+						    exec.consolelog="/var/log/svcj_${name}_console.log" \ +						    \
name=svcj-${name} && _return=0 +					else
+						_run_rc_doit "$_cmd $rc_extra_args" || _return=1
+					fi
+					;;
+				stop)
+					if [ "${_rc_svcj}" != jailing ]; then
+						$SERVICE -j svcj-${name} ${name} ${_rc_prefix}stop $rc_extra_args || _return=1
+						$JAIL_CMD -r svcj-${name} 2>/dev/null
+					else
+						_run_rc_doit "$_cmd $rc_extra_args" || _return=1
+					fi
+					;;
+				restart|status) ;; # no special case needed for svcj or handled somewhere else
+				*)
+if checkyesno ${name}_svcj; then
+echo XXX: check if \"$rc_arg\" needs to be executed in the jail or outside
+fi
+#					if [ "${_rc_svcj}" != jailing ]; then
+#						$SERVICE -j svcj-${name} ${name} ${_rc_prefix}${rc_arg} $rc_extra_args || \
_return=1 +#					else
+						_run_rc_doit "$_cmd $rc_extra_args" || _return=1
+#					fi
+					;;
+				esac
+			fi
+			if [ "${_rc_svcj}" != jailing ]; then
+				_run_rc_postcmd
+			fi
 			return $_return
 		fi
 
@@ -1113,9 +1215,21 @@ run_rc_command()
 				return 1
 			fi
 
-			if ! _run_rc_precmd; then
-				warn "failed precmd routine for ${name}"
-				return 1
+			if [ "${_rc_svcj}" != jailing ]; then
+				if ! _run_rc_precmd; then
+					warn "failed precmd routine for ${name}"
+					return 1
+				fi
+			fi
+
+			if checkyesno ${name}_svcj; then
+				if [ "${_rc_svcj}" != jailing ]; then
+					$JAIL_CMD -c $_svcj_generic_params $_svcj_cmd_options\
+					    exec.start="export _rc_svcj=jailing; for d in /etc/rc.d $local_startup; do \
[ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}start $rc_extra_args && break; done" \ \
+					    exec.stop="export _rc_svcj=jailing; for d in /etc/rc.d $local_startup; do [ \
-x \$d/${name} ] && \$d/${name} ${_rc_prefix}stop $rc_extra_args && break; done" \ \
+					    exec.consolelog="/var/log/svcj_${name}_console.log" \ +					    \
name=svcj-${name} || return 1 +				fi
 			fi
 
 					# setup the full command to run
@@ -1152,16 +1266,28 @@ $command $rc_flags $command_args"
 					# Prepend default limits
 			_doit="$_cd limits -C $_login_class $_limits $_doit"
 
+
+			local _really_run_it=true
+			if checkyesno ${name}_svcj; then
+				if [ "${_rc_svcj}" != jailing ]; then
+					_really_run_it=false
+				fi
+			fi
+
+			if [ "$_really_run_it" = true ]; then
 					# run the full command
 					#
-			if ! _run_rc_doit "$_doit"; then
-				warn "failed to start ${name}"
-				return 1
+				if ! _run_rc_doit "$_doit"; then
+					warn "failed to start ${name}"
+					return 1
+				fi
 			fi
 
+			if [ "${_rc_svcj}" != jailing ]; then
 					# finally, run postcmd
 					#
-			_run_rc_postcmd
+				_run_rc_postcmd
+			fi
 			;;
 
 		stop)
@@ -1183,6 +1309,11 @@ $command $rc_flags $command_args"
 					# and run postcmd.
 			wait_for_pids $rc_pid
 
+			if checkyesno ${name}_svcj; then
+				# remove service jail
+				$JAIL_CMD -r svcj-${name} 2>/dev/null
+			fi
+
 			_run_rc_postcmd
 			;;
 


[Attachment #6 (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic