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

I have the following definition for the "daemon" class in /etc/login.conf:
Code:
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.
 
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.
  1. Apply this patch:
    Code:
    --- /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
  2. 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:
  1. No passwd entry was specified and the root uid was passed, which must cause setusercontext to ignore the MAC label.
  2. 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.
 
Here is a better (and hopefully safer) solution.
  1. Leave /sbin/init alone.
  2. Apply the following patch:
    Code:
    --- /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
  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
 
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.
 
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
Code:
/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.
Code:
--- /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
 
Back
Top