# /etc/rc ignores MAC label in "daemon" login class?



## ta0kira (Mar 13, 2013)

I have the following definition for the "daemon" class in /etc/login.conf:

```
daemon:\
        :label=biba/[B][U]equal[/U][/B](low-high),mls/low(low-[B][U]low[/U][/B]),partition/[B][U]1[/U][/B]:\
        :tc=default:
```
I've compiled it with [CMD=""]cap_mkdb[/CMD], and when I restart (FreeBSD 9.1 amd64), all of the services have a process MAC label of "biba/*high*(low-high),mls/low(low-*high*),partition/*0*" (that's the same label that init has, and it doesn't correspond to any label in /etc/login.conf.) In contrast, I have labels in the other login classes, which are set properly when users log in (both normal users and root.) Obviously, the problem is either that /etc/rc doesn't try to change the login class, it can't change the login class, or the the label is inherited from the calling process rather than being taken from /etc/login.conf.

Has anyone else had a similar problem? Is it possible that I'm missing a setting somewhere?

It's also worth noting that su seems to ignore the "label" spec in the login class, e.g. the command [CMD=""]sudo su -c daemon `id -un` -c getpmac[/CMD] (set the login class to "daemon" and show the new process' MAC label) shows the same MAC label as the current shell. I can also see that /etc/rc.subr (subroutines used by /etc/rc) uses su, but it doesn't set the login class.

Thanks!

Kevin Barry

edit: I looked at the source for /sbin/init and it looks like it only sets the priority and the resource limits when calling /etc/rc. I tried a few hacks, (added flags to the setusercontext call, changed that call to setclasscontext) which didn't change the outcome.

edit2: the "-s" option for su will enforce the user's MAC label, which I didn't know until I looked at the source for su.


----------



## ta0kira (Mar 13, 2013)

Here is the "solution", i.e. what I did to make it work. As far as I can tell, it's caused by the design of /sbin/init, which I modified to make it work. I'd like to hear what other people have to say about it, since this might not be a solution worthy of pushing upward.
Apply this patch:
	
	



```
--- /usr/src/sbin/init/init.c.orig      2013-03-13 15:21:33.000000000 -0400
+++ /usr/src/sbin/init/init.c   2013-03-13 17:09:13.000000000 -0400
@@ -1739,10 +1739,12 @@
 setprocresources(const char *cname)
 {
        login_cap_t *lc;
+       struct passwd *pwd = getpwnam(cname);
        if ((lc = login_getclassbyname(cname, NULL)) != NULL) {
-               setusercontext(lc, (struct passwd*)NULL, 0,
-                   LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
+         setusercontext(lc, pwd, pwd? pwd->pw_uid : 0,
+                   LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETMAC | LOGIN_SETLOGINCLASS);
                login_close(lc);
        }
+       endpwent();
 }
 #endif
```

Set the login class of "daemon" to "daemon" with the pw utility (might not be necessary.)
I think 2 issues lead to the MAC label not being set:
No passwd entry was specified and the root uid was passed, which must cause setusercontext to ignore the MAC label.
The original call to setusercontext didn't use LOGIN_SETMAC and LOGIN_SETLOGINCLASS.
Unfortunately, my MAC label for "daemon" doesn't allow me to log in via ssh unless I restart sshd manually, but that's another issue. Getting it to work and using it properly are definitely two different topics.

Thanks!

Kevin Barry

PS Maybe this should be moved to a different forum?

edit: I suppose it would make more sense to leave /sbin/init alone and modify /etc/rc.subr to set the login class.


----------



## ta0kira (Mar 13, 2013)

Here is a better (and hopefully safer) solution.
Leave /sbin/init alone.
Apply the following patch:
	
	



```
--- /etc/rc.subr.orig   2013-02-08 20:04:21.967179000 -0500
+++ /etc/rc.subr        2013-03-14 13:13:39.000000000 -0400
@@ -50,6 +50,15 @@
 IDCMD="if [ -x $ID ]; then $ID -un; fi"
 PS="/bin/ps -ww"
 JID=`$PS -p $$ -o jid=`
+unset PMAC
+PMAC="$([ -x /usr/sbin/getpmac ] && /usr/sbin/getpmac 2> /dev/null)"
+RC_EXEMPT="/etc/rc.exempt"
+RC_EXEMPT="$([ -f "$RC_EXEMPT" ] && [ -r "$RC_EXEMPT" ] && \
+       /usr/bin/stat -f%Lp,%u,%g "$RC_EXEMPT" 2> /dev/null | \
+       /usr/bin/grep -q '0,0,0$' && echo "$RC_EXEMPT")"
+EXEMPT_CLASS="default"
+DAEMON_CLASS="daemon"
+EXEMPT_CMD="/usr/bin/egrep -Fxq"
 
 #
 #      functions
@@ -1024,7 +1033,13 @@
                ;;
        *)                              # run in subshell
                if [ -x $_file ]; then
-                       if [ -n "$rc_fast_and_loose" ]; then
+                       if [ -n "$PMAC" ] && [ -n "$DAEMON_CLASS" ]; then
+                               unset class
+                               class=$DAEMON_CLASS
+                               [ -n "$RC_EXEMPT" ] && [ -n "$EXEMPT_CLASS" ] && [ -n "$EXEMPT_CMD" ] && \
+                                 $EXEMPT_CMD "$_file" "$RC_EXEMPT" 2> /dev/null && class=$EXEMPT_CLASS
+                               su -c "$class" -m -s "$($ID -un || echo 0)" -c "sh $_file $_arg"
+                       elif [ -n "$rc_fast_and_loose" ]; then
                                set $_arg; . $_file
                        else
                                ( trap "echo Script $_file interrupted >&2 ; kill -QUIT $$" 3
```

Add full rc script names (e.g. /etc/rc.d/sshd) to a new file /etc/rc.exempt to allow those services to remain in the "default" login class. Everything else will be run in the "daemon" class.
Kevin Barry


----------



## SirDice (Mar 14, 2013)

ta0kira said:
			
		

> Here is the "solution", i.e. what I did to make it work. As far as I can tell, it's caused by the design of /sbin/init, which I modified to make it work. I'd like to hear what other people have to say about it, since this might not be a solution worthy of pushing upward.


I think it's best to ask this on the mailing lists. There aren't a lot of developers on this forum. Not sure which list though, but I'd start with @freebsd-questions.


----------



## ta0kira (Mar 24, 2013)

Here's a better patch, which allows the new file /etc/rc.exempt to list an optional login class for the service, e.g. a line 
	
	



```
/etc/rc.d/sshd:root
```
 will start sshd with the MAC label specified for the "root" login class. I realized I needed to use more than just "daemon" and "default" login classes for specific security reasons.
	
	



```
--- /etc/rc.subr.orig   2013-02-08 20:04:21.967179000 -0500
+++ /etc/rc.subr        2013-03-24 16:29:15.000000000 -0400
@@ -50,6 +50,25 @@
 IDCMD="if [ -x $ID ]; then $ID -un; fi"
 PS="/bin/ps -ww"
 JID=`$PS -p $$ -o jid=`
+unset PMAC
+PMAC="$([ -x /usr/sbin/getpmac ] && /usr/sbin/getpmac 2> /dev/null)"
+RC_EXEMPT="/etc/rc.exempt"
+RC_EXEMPT="$([ -f "$RC_EXEMPT" ] && [ -r "$RC_EXEMPT" ] && \
+       /usr/bin/stat -f%Lp,%u,%g "$RC_EXEMPT" 2> /dev/null | \
+       /usr/bin/grep -q '0,0,0$' && echo "$RC_EXEMPT")"
+EXEMPT_CLASS="default"
+DAEMON_CLASS="daemon"
+EXEMPT_CMD="check_exempt"
+
+check_exempt()
+{
+       if ! /usr/bin/grep -Eq "^$1(:|$)" "$2"; then
+               echo "$DAEMON_CLASS"
+       else
+               class=$(/usr/bin/grep -E "$1(:|$)" "$2" | cut -d: -f2 -s)
+               [ -n "$class" ] && echo "$class" || echo "$EXEMPT_CLASS"
+       fi
+}
 
 #
 #      functions
@@ -1024,7 +1043,14 @@
                ;;
        *)                              # run in subshell
                if [ -x $_file ]; then
-                       if [ -n "$rc_fast_and_loose" ]; then
+                       if [ -n "$PMAC" ]; then
+                               unset class
+                               if [ -n "$RC_EXEMPT" ] && [ -n "$EXEMPT_CMD" ]; then
+                                       class=$($EXEMPT_CMD "$_file" "$RC_EXEMPT" 2> /dev/null)
+                               fi
+                               [ -n "$class" ] || class=$DAEMON_CLASS
+                               su -c "$class" -m -s "$($ID -un || echo 0)" -c "sh $_file $_arg"
+                       elif [ -n "$rc_fast_and_loose" ]; then
                                set $_arg; . $_file
                        else
                                ( trap "echo Script $_file interrupted >&2 ; kill -QUIT $$" 3
```
Kevin Barry


----------



## ta0kira (Apr 7, 2013)

Here is another solution, which doesn't involve setting the login class (which may or may not be appropriate):
http://www.freebsd.org/cgi/query-pr.cgi?pr=conf/145009


----------

