Subject: bin/13647: Incoherence between init(8) and /etc/rc.d/securelevel about kernel security level check.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <nomos@tiscalinet.it>
List: netbsd-bugs
Date: 08/07/2001 02:25:40
>Number:         13647
>Category:       bin
>Synopsis:       Incoherence between init(8) and /etc/rc.d/securelevel about kernel security level check.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 07 02:22:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Francesco Cristiano
>Release:        1.5
>Organization:
>Environment:
NetBSD  1.5 NetBSD 1.5 (GENERIC) #1: Sun Nov 19 21:42:11 MET 2000     fvdl@sushi:/work/trees/netbsd-1-5/sys/arch/i386/compile/GENERIC i386
>Description:
There are some incoherencies about init(8)'s kernel security level check  and 
/etc/rc.d/securelevel. Briefly init(8)'s kernel security level algorithmic is:

	if [ current security kernel level is set to 0]
	then
		set it to 0
	fi

Instead /etc/rc.d/securelevel's kernel security level algorithmic is:

	if [ the variable $securelevel is set to any value ]
	then 
		set current security kernel level to this value
	else
		set this variable to the current security kernel level
		and after execute init(8)'s kernel security level algorithmic
	fi

This different way of doing could create a series of contrasts. 

>How-To-Repeat:
Problem 1)
This problem consists of false and redundant messages  during the boot caused by
 /etc/rc.d/securelevel.

False messages)
If super-user set the variable $securelevel to 0 and after reboot the system via reboot(8), and
if  kernel is a "GENERIC" kernel compiled with option INSECURE enabled (that is the
default condition for 1.5 version), /etc/rc.d/securelevel  will print:

			"Setting securelevel: kern.securelevel  -1 -> 0"

and, before to execute getty(8), init(8) will print:

		 "<the date> init: Kernel security level changed from 0 to 1"

So the current kernel security level is 1 not 0, in other words the first message could be avoided, or 
replaced by a message as:
			 
			"Kernel security level changed from 0 to 1"

with no init(8)'s intervention.

Redundant message)
If super-user set the variable $securelevel to 1 and after reboot the system via /etc/rc.shutdown 
followed by /etc/rc, if  kernel  is a "GENERIC" kernel compiled with option INSECURE enabled
 (that is the default condition for 1.5 version), /etc/rc.d/securelevel  will  print:
		
			"Setting securelevel: kern.securelevel 1 -> 1"

so kernel security level is never modified by /etc/rc.d/securelevel  but it is always the same, in other
words this message is redundant and could be avoided.,

Problem 2)
This problem consists of a different behaviour, followed by  init(8) and /etc/rc.d/securelevel, about
 kernel security level, when it is set to 0, with a  "GENERIC" kernel compiled with option 
INSECURE  enabled  (that is the default condition for 1.5 version). 
To see this difference a double method to reboot the system  is considered: via reboot(8) and
via /etc/rc.shutdown followed by  /etc/rc.
Step by step is:

	/etc/rc's behaviour 					init(8)'s behaviour
1)system starts with default installation's		1)system starts with default installation's
   conditions (for a 1.5 version).			   conditions (for a 1.5 version).

2)root log in						2)root log in

3)set in /etc/defaults/rc.conf:				3)set in /etc/defaults/rc.conf:
	securelevel="0"					       securelevel="0"

4)reboot the system typing:				4)reboot the system typing:
	#sh  /etc/rc.shutdown					#reboot		
   followed by:
	#sh /etc/rc

		          5)at the next start up, /etc/rc.d/securelevel will print:
			         "Setting securelevel: kern.securelevel  -1 -> 0"

6)so the system now runs with kernel		6)before to execute getty(8), init(8) will check
   security level set to 0		          kernel security level and will print:
							       "Kernel security level changed from 0 to 1"
					          so the system now runs with kernel security
					          set to 1.

 Problem 3)
There are no control about the value assigned to $securelevel. This brings two sub-problems

1 sub-problem)
Every time that $securelevel is sets to a value less than the current kernel security level, for each
 kind of reboot (via reboot or also via /etc/rc.shutdown followed  by /etc/rc ) and with or without
a kernel with option INSECURE enabled, there is:

option INSECURE enabled				         option INSECURE disabled

1)system starts with default installation's		1)system starts with default installation's
   conditions (for a 1.5 version).			   conditions (for a 1.5 version).

2)root log in						2)root log in

3)modify kernel security level typing:		        3)because kernel have been compiled with
        #sysctl -w kern.securelevel=1		          option insecure disabled, now the current
							   value of kernel security level is 1.

4)set in /etc/defaults/rc.conf:				4)set in /etc/defaults/rc.conf:
	securelevel="0"					      securelevel="0"

5)reboot the system whether typing:			5)reboot the system whether typing:
	#sh /etc/rc.shutdown					#sh /etc/rc.shutdown
   followed by:						   followed by:
	#sh /etc/rc						#sh /etc/rc
   or typing:						   or typing:
	#reboot						        #reboot

			6)at the next start up, /etc/rc.d/securelevel will print:
"Setting securelevel: sysctl: sysctl() for kern.securelevel failed: operation not permitted"

I think that's better something as:
"Warning you tried to lower security kernel level please check your rc.conf file"

2 sub-problem)
In rc.conf(5) man page is written:
"If a variable that /etc/rc expects to  be set is not set, or the value is not of the allowed values, a
 warning will be printed"
and in init(8) man page is written:
"The kernel runs with four different levels of security" (-1, 0, 1, 2)
Step by step there is:

1)system starts with default installation's
   conditions (for a 1.5 version).

2)root log in

3)set in /etc/defaults/rc.conf:
	securelevel="1000"

4)reboot the system whether typing
#sh /etc/rc.shutdown
   followed by:
	#sh /etc/rc
   or typing:
	#reboot

5) at the next start up, /etc/rc.d/securelevel will print out:
	"Setting securelevel: kern.securelevel  -1 -> 1000"
I think that's better something as:
"Warning $securelevel is set to 1000 the system set it to 2"

>Fix:
Well, because I don't know the intentions of whom has implemented /etc/rc.d/securelevel, the
 question is:
"shall /etc/rc.d/securelevel be coherence with init(8) as regards the kernel security level's check?"
If the answer is positive then, to resolve all these problems, is enough to replace 
/etc/rc.d/securelevel with this new version:

#!/bin/sh
#
# $NetBSD: securelevel,v 2 2001/08/06 11:00:07 modified by Francesco Cristiano
#

# PROVIDE: securelevel
# REQUIRE: aftermountlkm ipnat mountd

. /etc/rc.subr

name="securelevel"
start_cmd="securelevel_start"
stop_cmd=":"


check_securelevel()
{
			case x$securelevel in 	
			x`sysctl -n kern.securelevel`) 
			#if $securelevel is equal to the current security level then make
			#nothing; (for example in a reboot sec. lev. could be equal to itself).
				if [ x$securelevel = x0 ]             
				#if super-user changes the security level to 0 using sysctl(8) and 
				#after reboot the system using rc.shutdown followed by rc(8).
				then
				echo -n "Kernel security level changed from 0 to 1: 0 -> "
				sysctl -n -w kern.securelevel=1
				fi
				;; 
			x0)     
				#it upgrades the security level to 0 and uses the variable 
				#xywjk to suppress some messages (e.g. -1 -> 0 ).
				xywjk=`sysctl -w kern.securelevel=0`   
				unset xywjk
				echo -n "Kernel security level changed from 0 to 1: 0 -> "
				sysctl -n -w kern.securelevel=1
				;;
	    		*)
              			echo -n "Setting securelevel: "
				sysctl -w kern.securelevel=$securelevel
				;;
			esac
}

check_value()
{
	if [ `sysctl -n kern.securelevel` -gt 2 -o `sysctl -n kern.securelevel` -lt -1 ]; then
	#if the current sec. kernel lev. is set to an abnormal value then 
	#print out only a warning message	
		echo " "
		echo "Warning current security kernel level is set to `sysctl -n kern.securelevel`"
		{ [ `sysctl -n kern.securelevel` -gt 2 ] && echo "the maximum value allowed is 2"; } \
					 		 || echo "the minimum value allowed is -1"
		echo " "
	
	elif [ $securelevel -lt -1 ]; then
		ex_securelevel=$securelevel
		securelevel=-1
			if [ $securelevel -lt `sysctl -n kern.securelevel` ]; then
				if [ `sysctl -n kern.securelevel` -eq 0 ]; then
				#for example $securelevel is set to -10 curr. sec. lev.
				#is set to 2 and user type "kill -15 1" when system will
				#come back in multi-user mode during boot curr. sec. lev. is set to 0
					securelevel=0
					echo "Warning you tried to lower security kernel level to $ex_securelevel"
					echo "current value is `sysctl -n kern.securelevel` please check your rc.conf file"
					echo " "
					check_securelevel
					unset ex_securelevel
				else
					echo "Warning you tried to lower security kernel level to $ex_securelevel"
					echo "current value is `sysctl -n kern.securelevel` please check your rc.conf file"
					echo " "
					unset ex_securelevel
				fi
			else	
				echo "Warning \$securelevel is set to $ex_securelevel the system set it to $securelevel"
				unset ex_securelevel
				check_securelevel
			fi
	elif [ $securelevel -gt 2 ]; then
		ex_securelevel=$securelevel
		securelevel=2
			if [ $securelevel -lt `sysctl -n kern.securelevel` ]; then
				echo "Warning you tried to lower security kernel level to $ex_securelevel"
				echo "current value is `sysctl -n kern.securelevel` please check your rc.conf file"
				echo " "
				unset ex_securelevel
			else	
				echo "Warning \$securelevel is set to $ex_securelevel the system set it to $securelevel"
				unset ex_securelevel
				check_securelevel
			fi
	elif [ $securelevel -lt `sysctl -n kern.securelevel` ]; then	
		#the only way to arrive here is setting $securelevel, in rc.conf file, to a value allowed  but
		#less than current sec. lev. and after reboot the system (also via rc.shutdown followed by rc(8))
		echo "Warning you tried to lower security kernel level to $securelevel"
		echo "current value is `sysctl -n kern.securelevel` please check your rc.conf file"
		echo " "
	else
			check_securelevel
	fi
}



securelevel_start()
{
	if [ -n "$securelevel" ]; then
		check_value
	else
		securelevel=`sysctl -n kern.securelevel`
		check_value
	fi
}

load_rc_config $name
run_rc_command "$1"




If /etc/rc.d/securelevel has been implemented to give more flexibility to the system, as regards the
 kernel security level management, and to circumvented init(8)'s limits, for example:

"to keep security kernel level always to the same value during any kind of reboot"

then I've also implemented the code for this, which works also for reboot invoked by
reboot(8) and $securelevel set to 0, but it's more long than the source code upon.
Because I'd like to contribute to NetBSD, responsible person can contact me everyday
at every time.


 
>Release-Note:
>Audit-Trail:
>Unformatted: