Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 9 Jul 1999 12:42:52 -0400 (EDT)
From:      Robert Watson <robert@cyrus.watson.org>
To:        Nate Williams <nate@mt.sri.com>
Cc:        Darren Reed <avalon@coombs.anu.edu.au>, Ben Gras <ben@nl.euro.net>, freebsd-security@FreeBSD.ORG
Subject:   Re: how to keep track of root users?
Message-ID:  <Pine.BSF.3.96.990709123354.24202J-100000@fledge.watson.org>
In-Reply-To: <199907091609.KAA06341@mt.sri.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 9 Jul 1999, Nate Williams wrote:

> > #ifdef POSIX_AUD
> > 	/* allocate the record */
> > 	if (!audrec = k_aud_new_record())
> > 		return(...appropriate error...)
> 
> Or not.  No being able to create an audit record should not cause the
> syscall to fail, but that's another discussion in itself. :)

Indeed it is--offhand I see two choices: 1) you don't let a syscall
succeed unless you can audit it, as otherwise you won't set off your IDS
as they can overload the system, or 2) an IDS module recognizes that a
congested audit system may be an attack.  Blocking for an available record
might be a problem if it results in deadlock...

> > The problem raised here again, of course, is the copyin of string
> > arguments.
> 
> I don't see any way around this, given the audit record needs to exist
> as a discrete record that has a lifetime outside of the syscall, so the
> information must be copied in.  Yes, it does mean that it will have to
> be copied in to stored in the kernel, and then copied out, but given
> that the time difference between in/out could be long (in terms of
> computer time) I can't think of another solution.
> 
> Does anyone else have any ideas?

My concern was that it was being copied in twice, as opposed to that it
was being copied in.  I'm tempted to pull the copyin out of namei and
instead pass in a string buffer to namei, stored in kernel space.

> > Another problem is error-handling: at any possible exit point
> > from the syscall, we need to commit an audit record describing the exit
> > (in error, success, etc).
> 
> Again, I am in total agreement with you.  Especially given that we have
> already agreed that the type of information gathered is already
> syscall specific.  Adding exit hooks isn't that much more difficult.

I did something like this to add speculative process execution to
FreeBSD/i386 a few months ago (that is, generating disk prefetch hints
based on speculatively executing a sandboxed process copy), and it proved
quite straightforward.  However, I believe the architecture-dependent code
is what sits directly below the syscall code: we should perhaps insert
another architecture-independent layer that wraps the syscall, where
things like this can be placed.  Similarly, auditing signal delivery would
need to happen the same way: currently signal deliver lives in
architecture-dependent-land, and we'd want the auditing wrapper to sit
somewhere independent of architecture, I suspect.

> > This suggests instead making auditing to some
> > extent implicit to the syscall: a record is created associated with the
> > process structure (or thread or whatevr) when entering kernel mode, and
> > committed when returning to userland (or explicitely committed if we are
> > never going to return, i.e., the process called _exit).  Kernel code in
> > the syscall may optionally add additional information about the kernel
> > entry point using a set of calls that automatically modify the implicit
> > audit record state associated with the proc, meaning no need to allocate
> > an audrec or pass it into all the routines, as it might be in
> > p->p_curaudrec.
> > 
> > #ifdef POSIX_AUD
> > 	AUD_SET_SYSCALL(AUD_AEV_CHMOD);
> > 	AUD_ADD_ARG(AUD_PATHNAME, ...);
> > 	AUD_ADD_ARG(AUD_MODE, SC(args, mdoe));
> > 	...
> > #endif
> 
> I don't think this will work, simply because how do we differentiate
> between different syscall that will eventually be running in parallel in
> the kernel?

As Garrett mentions, there will still be a context record from somewhere
that could be extended to carry an active audit record for the activities
of that context.  Presumably that is the place to put it?

> > Information like credentials, pid, return code, syscall number would
> > automatically be inserted when available by the syscall handler.
> 
> Why not just add it at the entry point to the syscall?  We're going to
> have to instrument them all anyway, so why not make things consistant by
> instrumenting at the syscall entry/exit points?

Yes.

> > Syscall
> > number could be overriden by an explicit call.  This still leaves us with
> > dealing with the arguments, especially pathnames and arrays of strings
> > (e.g., argv[] or env[]).
> 
> See above.  We can properly deal with the arguments if we have the
> context of these arguments, which of course we do at particular syscall
> entry point (execve, chmod, link, etc...)

But we do have to know what the syscall is, otherwise we don't understand
the arguments.  I think the argument sniffing should happen inside the
current syscall code so that it's obvious to people changing the syscall
that they need to update the auditing behavior--otherwise we have
inconsistent sources of argument data?  (perhaps this could go in
syscalls.master and be assembled as part of that?)

> > The difference
> > between "some auditing" and "all auditing" is more challenging: to what
> > degree is filtering of records in the kernel appropriate, and to what
> > degree should that be done by a userland audit daemon or audit record
> > manager?  A large volume stream of records in the kernel bloats the kernel
> > and cuts into preemptible execution time.  But adding too much filtering
> > in kernel is costly also, and requires a lot more bloat in the kernel.
> 
> I believe there is a trade-off that allows us to somehow 'reduce'
> creation of records with a simple filtering scheme that should be much
> more effecient than generating records that the benefits are easily
> seen.
> 
> However, this is probably not needed for IDS-V1. :)

I agree.  Currently I have a userland matching mechanism, but it's not
very efficient as this is really just an initial exploration.  My feeling
is that some very simple limiting mechanisms would be quite sufficient to
block the majority of the unneeded record generation.  For example,
per-syscall-number and per-pid, per-uid, etc, plus a per-process enable
flag on auditing.  This can be caught quite early, and all submissions
become no-ops on the record.

> > POSIX.1E only defines a way to tell whether auditing is turned on or off
> > for a specific process, and to toggle that (so that, for example, the
> > audit daemon can turn off auditing so as to prevent feedback on audit
> > record delivery).  This seems to broad to me.  Suppose active IDS modules
> > only require fork(), exec() and exit() tracing--then delivering the
> > 20,000 calls to gettimeofday() is a waste of resources.
> 
> See above.  However, building a truly generic filtering mechanism would
> be 'hard to do', so for now I think we can live with no filtering, or a
> very simple filtering scheme.  But, will the FreeBSD kernel maintainers
> allow this is another story. :(

See above: simple stuff in kernel may be the optimum approach, and I
suspect a little bit of simple goes a long way.

> Nate
> 
> ps. I'm on vacation all next week, so I'll be away from email.

Have a great time.

  Robert N M Watson 

robert@fledge.watson.org              http://www.watson.org/~robert/
PGP key fingerprint: AF B5 5F FF A6 4A 79 37  ED 5F 55 E9 58 04 6A B1
TIS Labs at Network Associates, Computing Laboratory at Cambridge University
Safeport Network Services



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?Pine.BSF.3.96.990709123354.24202J-100000>