Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Jan 1999 02:35:16 -0800
From:      Don Lewis <Don.Lewis@tsc.tdk.com>
To:        Mark Newton <newton@atdot.dotat.org>, Don.Lewis@tsc.tdk.com (Don Lewis)
Cc:        robert+freebsd@cyrus.watson.org, newton@camtech.com.au, eivind@yes.no, casper@acc.am, freebsd-security@FreeBSD.ORG
Subject:   Re: About chroot
Message-ID:  <199901111035.CAA15251@salsa.gv.tsc.tdk.com>
In-Reply-To: Mark Newton <newton@atdot.dotat.org> "Re: About chroot" (Jan 11,  3:04pm)

next in thread | previous in thread | raw e-mail | index | archive | help
On Jan 11,  3:04pm, Mark Newton wrote:
} Subject: Re: About chroot
} Don Lewis wrote:
} 
}  > }  > > kern/9183
}  > }  >
}  > }  > It seems like a neat idea.  However, enabling vfs.hard_chroot may break
}  > }  > security in certain environments--in particular, environments where a
}  > }  > chroot is used as part of the system bootup, and where existing
}  > }  > services will try to use chroot to create sandboxes.
}  > } 
}  > } Agreed.  I figured those cases would make up a minority.
}  > 
}  > There's at least one place where I need two levels of chroot().  The hack
}  > that I'm currently using added another rdir-like entry to struct filedesc.
}  > I'm currently in the process of reimplementing this as a stack.  The main
}  > main problem I'm having is a lack of time to work on the code.
}  > One tricky thing is that once you allow more than one level of chroot(),
}  > you create the possibility of breaking out of the jail.  I've got some
}  > ideas on how to protect against this.
} 
} Care to share?

I'm hoping that I can post a patch in the next week or so.  The problem
is that I've been hoping the same thing for quite a while :-(

} Although multiple recursive levels of chroot() are one of those things
} that would be "nice to have", do you think the implementational
} complexity of an in-kernel root directory stack are worth it considering
} that people have been able to work around chroot() limitations for the
} last 20 years or so?

It's worthwhile for me.  The implementation isn't too bad.  Unfortunately
it requires some tweaks to fstat, lsof, etc.

} 
} [ ooooh, I'm gonna get it in the neck for that question... ]
} 
}  > } Of course -- But that's relatively easy:  The same check for
}  > } p_rdir that's used to work out whether chroot() should fail can also
}  > } be placed into mknod(2) and mount(2).  I wouldn't even need to 
}  > } unstaticize hard_chroot to make those changes happen.
}  > 
}  > I did something like this a couple years ago (don't forget about umount()).
}  > My current preference would be to set a flag in struct proc that disables
}  > access to these.  The process that puts the suspect process in jail would
}  > do the chroot() and set the flag.
} 
} I've modified my initial patch to vfs_syscalls.c;  It now affects the
} syscalls described below if the caller's root directory is not the 
} same as init's root directory AND vfs.hard_chroot != 0 AND if an additional
} supplementary condition evaluates to true, regardless of the uid of
} the caller:
} 
} system call               supplementary condition
} ------------------------------------------------------------------
} mount                     true (:-)
} umount                    true
} chroot                    true
} mknod                     true (only affects mknod(2);  FIFOs are still
}                                 allowed)
} chmod                     mode & S_ISUID
} lchmod                    mode & S_ISUID
} fchmod                    mode & S_ISUID
} 
} The last three are to prevent a chroot'ed user from making setuid 
} binaries of any kind regardless of who owns them.

Good idea.  I didn't need to do this because all the writeable areas
of my sandboxes are mounted noexec.  This could relax this to nosuid
if necessary.

} The vfs.hard_chroot test is performed by means of a macro called 
} FAIL_HARD_CHROOT() defined in the same place as the hard_chroot sysctl.
} It takes one parameter, which is the supplementary conditional used
} to fail the syscall.  FHC_ALWAYS is defined to 1 for the cases marked
} as "true" in the table above.
} 
}  > Even better would be finer grained access control.  It's too bad that POSIX
}  > wasn't able to standardize something.
} 
} <shrug>  IRIX, HP-UX and Solaris have ACLs.

I wasn't thinking of file ACLs, which would also be nice to have, but
rather a flag that controls whether or not you can mount(), etc.

What would be really cool is phk's sandbox stuff.

}  > } We'd probably also want to restrict a user's ability to access LKM/KLD
}  > } interfaces, assuming they're in the kernel in the first place.  reboot(2)
}  > } should also be restricted.  Are there any others? (deny bind()ing to 
}  > } privileged ports?  nah, that'd break ftpd, which is part of the
}  > } intended audience of the patch, with very few security benefits).
}  > 
}  > I disabled access to lkms, blocked access to processes outside the
}  > jail by kill() and ptrace().
} 
} On further reflection, the lkm (or kld) and ptrace cases are already
} covered by kern.securelevel.

You can't ptrace the init process when securelevel > 0, but I think
everything else is wide open.

} The kill case could be covered by unstaticizing hard_chroot, putting
} the FAIL_HARD_CHROOT() macro into a .h file, and putting something like
} the following (untested code) at the front of kill()/killpg()/etc in
} kern_sig.c:
} 
}     FAIL_HARD_CHROOT((pfind(uap->pid))->p_fd->fd_rdir != cp->p_fd->fd_rdir);
} 
} i.e.: fail the kill() operation if the root directory of the target
} is not the same as the root directory of the caller.  This would
} mean that processes in one jail couldn't kill processes in other
} jails on the same system too.

This is pretty much the same as what I implemented.

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message



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