Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 03 Apr 2022 21:48:42 +0200
From:      Alexander Leidinger <Alexander@leidinger.net>
To:        security@freebsd.org, jail@freebsd.org
Subject:   Auto-jailing of services - 2nd implementation
Message-ID:  <20220403214842.Horde.vlwSVh0KOZ6sL7aDfgA9KKL@webmail.leidinger.net>

next in thread | raw e-mail | index | archive | help
This message is in MIME format and has been PGP signed.

--=_YVfRcdE_UVp6rdkJjuoW1Qz
Content-Type: multipart/mixed; boundary="=_w3-e5ke9RnnaZj37w0YmaYo"

This message is in MIME format.

--=_w3-e5ke9RnnaZj37w0YmaYo
Content-Type: text/plain; charset=utf-8; format=flowed; DelSp=Yes
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi,

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

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

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

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

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

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

Bye,
Alexander.

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

--=_w3-e5ke9RnnaZj37w0YmaYo
Content-Type: text/diff; charset=utf-8; name=svcj.diff
Content-Disposition: attachment; size=9845; filename=svcj.diff
Content-Transfer-Encoding: quoted-printable

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=3D"/etc/security/${name}.conf"
 extra_commands=3D"reload"
=20
=20load_rc_config $name
+
+: ${auditdistd_svcj_options:=3D"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()
 }
=20
=20load_rc_config $name
+
+: ${ftpd_svcj_options:=3D"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=3D"/etc/${name}.conf"
 extra_commands=3D"reload"
=20
=20load_rc_config $name
+
+: ${inetd_svcj_options:=3D"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()
 }
=20
=20load_rc_config $name
+
+: ${kadmind_svcj_options:=3D"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()
 }
=20
=20load_rc_config $name
+
+: ${kdc_svcj_options:=3D"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()
 }
=20
=20load_rc_config $name
+
+: ${kapsswd_svcj_options:=3D"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:=3D${local_unbound_workdir}/root.key}
 : ${local_unbound_forwarders:=3D}
 : ${local_unbound_tls:=3D}
+: ${local_unbound_svcj_options:=3D"net_basic"}
=20
=20do_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()
 }
=20
=20load_rc_config $name
+
+: ${lpd_svcj_options:=3D"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:=3D"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=3D"/usr/bin/protect"
 ID=3D"/usr/bin/id"
 IDCMD=3D"if [ -x $ID ]; then $ID -un; fi"
 PS=3D"/bin/ps -ww"
+SERVICE=3D/usr/sbin/service
+JAIL_CMD=3D/usr/sbin/jail
+_svcj_generic_params=3D"path=3D/ mount.nodevfs host=3Dinherit"
 JID=3D0
 # 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})"|"[${_proc=
namebn}]")'
 	fi
=20
+=09if checkyesno ${name}_svcj; then
+		JID=3D$(/usr/sbin/jls -j svcj-${name} jid)
+
+		case ${JID} in
+		''|*[!0-9]*)
+			# svj-jail doesn't exist, fallback to host-check
+			JID=3D0
+			;;
+		esac
+	fi
 	_proccheck=3D"\
 		$PS 2>/dev/null -o pid=3D -o jid=3D -o command=3D $_psargs"' |
 		while read _npid _jid '"$_fp_args"'; do
@@ -959,6 +972,18 @@ run_rc_command()
 	_pidcmd=3D
 	_procname=3D${procname:-${command}}
=20
+=09# 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 over=
riden
+	# by a specific YES.
+	eval _svcj=3D\$${name}_svcj
+	if [ -z "$_svcj" ]; then
+		_svcj=3D${svcj_all_enable}
+		if [ -z "$_svcj" ]; then
+			eval ${name}_svcj=3DNO
+		fi
+	fi
+
 					# setup pid check command
 	if [ -n "$_procname" ]; then
 		if [ -n "$pidfile" ]; then
@@ -994,7 +1019,7 @@ run_rc_command()
 	    _fib=3D\$${name}_fib		_env=3D\$${name}_env \
 	    _prepend=3D\$${name}_prepend	_login_class=3D\${${name}_login_class:-d=
aemon} \
 	    _limits=3D\$${name}_limits    _oomprotect=3D\$${name}_oomprotect \
-	    _env_file=3D\$${name}_env_file
+	    _env_file=3D\$${name}_env_file _svcj_options=3D\$${name}_svcj_options
=20
=20	if [ -n "$_env_file" ] && [ -r "${_env_file}" ]; then	# load env from f=
ile
 		set -a
@@ -1008,6 +1033,42 @@ run_rc_command()
 		fi
 	fi
=20
+=09if [ -n "$_svcj_options" ]; then	# translate service jail options
+		_svcj_cmd_options=3D""
+
+		for _svcj_option in $_svcj_options; do
+			case "$_svcj_option" in
+				netv4)
+					_svcj_cmd_options=3D"ip4=3Dinherit allow.reserved_ports ${_svcj_cmd_o=
ptions}"
+					;;
+				netv6)
+					_svcj_cmd_options=3D"ip6=3Dinherit allow.reserved_ports ${_svcj_cmd_o=
ptions}"
+					;;
+				net_basic)
+					_svcj_cmd_options=3D"ip4=3Dinherit ip6=3Dinherit allow.reserved_ports=
 ${_svcj_cmd_options}"
+					;;
+				net_raw)
+					_svcj_cmd_options=3D"allow.raw_sockets ${_svcj_cmd_options}"
+					;;
+				net_all)
+					_svcj_cmd_options=3D"allow.socket_af allow.raw_sockets allow.reserved=
_ports ip4=3Dinherit ip6=3Dinherit ${_svcj_cmd_options}"
+					;;
+				sysvipc)
+					_svcj_cmd_options=3D"sysvmsg=3Dinherit sysvsem=3Dinherit sysvshm=3Din=
herit  ${_svcj_cmd_options}"
+					;;
+				mlock)
+					_svcj_cmd_options=3D"allow.mlock ${_svcj_cmd_options}"
+					;;
+				vmm)
+					_svcj_cmd_options=3D"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
=20
=20	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}" !=3D 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}" !=3D jailing ]; then
+						_return=3D1
+						$JAIL_CMD -c $_svcj_generic_params $_svcj_cmd_options \
+						    exec.start=3D"export _rc_svcj=3Djailing; for d in /etc/rc.d $loc=
al_startup; do [ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}start $rc_ext=
ra_args && break; done" \
+						    exec.stop=3D"export _rc_svcj=3Djailing; for d in /etc/rc.d $loca=
l_startup; do [ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}stop $rc_extra=
_args && break; done" \
+						    exec.consolelog=3D"/var/log/svcj_${name}_console.log" \
+						    name=3Dsvcj-${name} && _return=3D0
+					else
+						_run_rc_doit "$_cmd $rc_extra_args" || _return=3D1
+					fi
+					;;
+				stop)
+					if [ "${_rc_svcj}" !=3D jailing ]; then
+						$SERVICE -j svcj-${name} ${name} ${_rc_prefix}stop $rc_extra_args ||=
 _return=3D1
+						$JAIL_CMD -r svcj-${name} 2>/dev/null
+					else
+						_run_rc_doit "$_cmd $rc_extra_args" || _return=3D1
+					fi
+					;;
+				restart|status) ;; # no special case needed for svcj or handled somewh=
ere 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}" !=3D jailing ]; then
+#						$SERVICE -j svcj-${name} ${name} ${_rc_prefix}${rc_arg} $rc_extra_a=
rgs || _return=3D1
+#					else
+						_run_rc_doit "$_cmd $rc_extra_args" || _return=3D1
+#					fi
+					;;
+				esac
+			fi
+			if [ "${_rc_svcj}" !=3D jailing ]; then
+				_run_rc_postcmd
+			fi
 			return $_return
 		fi
=20
@@=20-1113,9 +1215,21 @@ run_rc_command()
 				return 1
 			fi
=20
-=09		if ! _run_rc_precmd; then
-				warn "failed precmd routine for ${name}"
-				return 1
+			if [ "${_rc_svcj}" !=3D 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}" !=3D jailing ]; then
+					$JAIL_CMD -c $_svcj_generic_params $_svcj_cmd_options\
+					    exec.start=3D"export _rc_svcj=3Djailing; for d in /etc/rc.d $loca=
l_startup; do [ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}start $rc_extr=
a_args && break; done" \
+					    exec.stop=3D"export _rc_svcj=3Djailing; for d in /etc/rc.d $local=
_startup; do [ -x \$d/${name} ] && \$d/${name} ${_rc_prefix}stop $rc_extra_=
args && break; done" \
+					    exec.consolelog=3D"/var/log/svcj_${name}_console.log" \
+					    name=3Dsvcj-${name} || return 1
+				fi
 			fi
=20
=20					# setup the full command to run
@@ -1152,16 +1266,28 @@ $command $rc_flags $command_args"
 					# Prepend default limits
 			_doit=3D"$_cd limits -C $_login_class $_limits $_doit"
=20
+
+=09		local _really_run_it=3Dtrue
+			if checkyesno ${name}_svcj; then
+				if [ "${_rc_svcj}" !=3D jailing ]; then
+					_really_run_it=3Dfalse
+				fi
+			fi
+
+			if [ "$_really_run_it" =3D 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
=20
+=09		if [ "${_rc_svcj}" !=3D jailing ]; then
 					# finally, run postcmd
 					#
-			_run_rc_postcmd
+				_run_rc_postcmd
+			fi
 			;;
=20
=20		stop)
@@ -1183,6 +1309,11 @@ $command $rc_flags $command_args"
 					# and run postcmd.
 			wait_for_pids $rc_pid
=20
+=09		if checkyesno ${name}_svcj; then
+				# remove service jail
+				$JAIL_CMD -r svcj-${name} 2>/dev/null
+			fi
+
 			_run_rc_postcmd
 			;;
=20

--=_w3-e5ke9RnnaZj37w0YmaYo--

--=_YVfRcdE_UVp6rdkJjuoW1Qz
Content-Type: application/pgp-signature
Content-Description: Digitale PGP-Signatur
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQIzBAABCAAdFiEER9UlYXp1PSd08nWXEg2wmwP42IYFAmJJ+hkACgkQEg2wmwP4
2IYpnA//WhZ/G/sLzATWcHOtHntm3S1hVQNJCUy9dHKbtkpyXSWHkfenSTDlLqeb
2k3VlnH5qmHvcg0bT67Za53o9uqm3TwdX4/L7SOAwL4EgsgzHMBIuuG+A8UIkUiP
KOk0XFTFKdkRe1VSH09Xf8ol2EeLZ/fpIsKGTLq0L32CUhbcl+P616RVrxrz6GJW
Pze2YlTK885T0jWGqCFkJ3MtycOiId9HJP1K+4eCuQoWjfvzXQVpnueKt+jEQJEM
xzcp9VMlOOrLxEdpjyMxCoyfu4czQG9aeEznoAww6npSUmjcQanXnVi/fkOjeXbM
/Y4tnSK0mEHa4w1n/YIdcUTElbzUOF2qy4JdTfaRrgdumWF/2wV+GQ9YFEmR6MSZ
I0ORHT/r684dAxbRLzk2g4yL9wrvRPUSrYru4n+bxaqDH79sCodzpjOM3wgN2fGy
o7yRNuAexv7X+ROcDan/hbWs2YdXBz1qJ/ofepf4K/HxUtElsruL8tBATZDzXg0y
Prk1TSUSIQXEauSG/FoQxMnXidVFCvIbUHxZs2UzH8yBVKPk1zsWmWZwOYzsnU5R
uqyOZfxhzvgZO3g0dQ4uf7aBGvS+riTUFiBAVe4yt21AP6WvY3NFTLB4fH7C11z5
wYz0BAWpAHY8BNG+gPqK1631yrelC070bPFw9S3LoPwhUbzke44=
=2g/S
-----END PGP SIGNATURE-----

--=_YVfRcdE_UVp6rdkJjuoW1Qz--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20220403214842.Horde.vlwSVh0KOZ6sL7aDfgA9KKL>