dynamic context transitions
Luke Kenneth Casson Leighton
lkcl at lkcl.net
Sun Nov 14 21:43:48 GMT 2004
On Sun, Nov 14, 2004 at 05:26:55PM +0100, Simo Sorce wrote:
i apologise in advance for this being a particularly lengthy
message: writing a summary afterwards, for those with little
time, basically it says that samba tng's architecture, which
has all the separate services which people think of as "a
samba" split out into separate daemons - appx twelve separate
daemons, is much better suited to securing with selinux than
yes, there are that _and_ more separate services in "a samba"!
[btw - to date, five or six years on, i still have not received
a satisfactory response as to why samba still has a monolithic
> In samba4 we have process, single AND thread model and a operations are
> async so this will not be a problem anymore.
> Btw, from tests seem that in threaded model performance suck anyway :)
i like that - threads are supposed to be All The Rage.
... what do you think is going wrong?
> > > but even if we get that (and perhaps the 'terminal server' case will
> > > cause such a proxy to be written), we still have the problem of needing
> > > to become root for some operations.
> > well (as you and others are in a position to appreciate)
> > i really don't want to get into this in detail but i think
> > you will find that if you follow the tng architecture -
> > namely to split services out into separate daemons - then
> > that problem goes away.
> Not at all, there are operations that we must be able to do and that
> posix allow only for root, so unlike you propose to run always as root,
> we need to go root and back from time to time.
> Look at smbd sources and grep for become_root() and you'll find out why.
[for those people who are not familiar with the circumstances
under which become_root is used]
okay, i think i see what you're getting at: you are saying
that not all circumstances under which seteuid() is used can
be replaced by a [simple] redesign, yes?
... why is that?
> > from an selinux security perspective, the tng architecture
> > is much more amenable to being "locked down". each service
> > (e.g. spoolssd) can be given access to ONLY the required
> > commands (e.g. lpr) it needs to execute to do its job, ONLY
> > the files it needs (e.g. /var/spool/).
> > the point of selinux is to give programs the absolute minimum required
> > policy to operate.
> Yes, but samba need to do a lot of things, and a mere split down in
> daemons doesn't make it any better from this point of view, smbd will
> still need to go root and back, unless you want to break compatibility.
i believe that you are assuming that there is an incompatibility
between selinux and "going to root and back".
or that there is some association between the use of seteuid, or
perhaps i should clarify, starting with selinux, and the concerns over
the new functionality being added, which will give you a better handle onto
why doing separate processes per service is so much more preferable,
and _then_ go on to describe where become_root() and friends would still
be needed - but as a separate and distinct issue from the one of
doing separate processes per service.
selinux works a bit like that tracing thing - the one which
monitors system calls, builds up a profile of the calls
being used, and then you switch "mode" and only _allow_ those
system calls to do what you originally profiled that they do.
when i say "a bit like" i am in fact lying: it's a lot more
than "just" allowing system calls to do pre-vetted things.
it's worth bearing in mind that the old argument of "if you
are root, then it's impossible to improve the situation" no
longer applies when selinux is involved - you only have to
look at the test sites that people are setting up where they
offer a root password and invite you to mess about with it.
firstly, you get assistance from the kernel rather than userspace.
secondly, as a linux security module (LSM), the "normal"
unix permissions and capabilities are checked first: only if
those succeed does the LSM framework call the selinux security
module: only if _those_ succeed is the function call allowed.
this saves processing cycles [on failed accesses].
thirdly, each process (well, in fact, linux kernel thread,
but nobody actually at present goes to the extreme extent
of writing policy for individual threads) can have its own
"vetting" list of operations it is allowed to perform, and
each "vetting" list is given a name (by the policy writer)
called a "domain".
fourthly, and this is the crucial bit, there is a means to "transition"
between domains automatically.
AT PRESENT the only way to transition between domains is to "exec()" a
the discussion on the selinux mailing list was to add a NEW
means to change to a different domain - one that works in a
similar way to seteuid. namely, that you call a function e.g.
selinux_change_domain() and bang, you're in a new domain.
there are some quite grave concerns about adding this seteuid-like
function in selinux.
the first one is that it is considered bad security practice to use
i assume that you are familiar with the potential for
things going horribly wrong - just as an example, how about
accidentally opening a file handle as root and forgetting to
close it before doing the seteuid to another user.
now, whilst that may appear at first sight to be fine ("my
program had a security audit, i am a first-rate programmer,
i made sure that wasn't possible to happen in my code!")
if you bring in a hostile attack against your program into
the mix, then you cannot guarantee that your program cannot
here's where selinux _can_ start to make such guarantees
possible _and_ you can prove it with policy analysis tools.
... but NOT if you're using the newly proposed yet-to-be-written
that might need some explanation.
if you allow a _program_ to make a domain transition [i.e. to move from
being allowed to do one set of POSIX operations with access to certain
resources to being allowed to do a totally different set with access to
completely different resources] then you still don't have control over
_when_ that transition occurs, and in addition you are _still_ passing
over a hell of a lot more resources between the two "domains".
vetting and auditing those resources is going to be
... well... hair-raising at best.
it's best explained like this: with exec(), you _know_ that
the two programs (the exec()er and the exec()ed) share very
little information between them, such that you have to design
and use a communication mechanism - if you need it - and that
communication mechanism can be audited by selinux policy.
so, basically, from a security perspective, using seteuid()
is a bit of a nightmare: in the case of smbd, you have
a single process which carries resources over from a
"user-like"-privileged domain to a "root-like"-privileged domain,
such that if smbd is compromised...
... but if say... spoolssd (samba-tng printer server program)
is compromised, wow big deal, so the attacker can call lpr,
gosh, shock horror.
now i should address the uses for become_root() and friends.
smbd starts off as root until an SMB user is authenticated, then there
are circumstances under which it is necessary to a) switch to a new
SMB user context (a different SMB VUID+UID+TID tuple) b) switch to root
temporarily - e.g. for access to protected databases.
under samba tng's daemon-per-service scheme, the use of become_root and
become_user is, i believe, reduced. yes, with the file serving, a)
above is still necessary. the number of occurences b) however is far
well, let's take authentication as an example. in smbd,
authentication is done by doing a become_root(), reading
the smbpasswd file or tdb database, and then doing an
all authentication in samba tng is done NOT by the daemons
themselves (smbd included) but instead by contacting the
netlogond daemon, which in turn contacts samrd (asking it
for the user's password).
so right there you have an example whereby selinux could
make a big contribution: netlogond's selinux domain could be
pretty heavily restricted (bare-bones), and samrd's domain
could be likewise heavily restricted but it requires access
to the user account database.
and samrd is the _only_ process requiring access to the user account
database (SAM database).
any program - even one with root privileges - that even
ATTEMPTS to access the SAM database would find it banned and
an audit message would be logged.
with the present monolithic design of smbd, the same policy that
specifies access to user files must also have granted to it the right
to access the SAM database (smbpasswd) file.
... can you see that there is something wrong with this picture?
so, whilst programs like spoolssd may still require
become_root() and friends - for example to oh i dunno read
printer queues as root or something - they certainly don't
require become_root() to access the smbpasswd file/database.
More information about the samba-technical