tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: In-kernel process exit hooks?



On Sat, Jan 09, 2016 at 08:25:05AM +0100, Mateusz Guzik wrote:
> On Sat, Jan 09, 2016 at 02:25:02PM +0800, Paul Goyette wrote:
> > On Sat, 9 Jan 2016, Mateusz Guzik wrote:
> > 
> > >While I don't know all the details, it is clear that the purpose would
> > >be much better served by ktrace and I would argue efforts should be
> > >spent there.
> > 
> > filemon's purpose is somewhat different than that of ktrace.  There
> > is a limited set of events that filemon captures, and it only
> > captures successful operations.  Its output is quite simple and easy
> > to parse by a human of shell script.
> > 
> 
> ktrace already have limited support for specifying what events are
> wanted. One can add a special filemon-like mode.
> 
> The output of kdump is definitely less friendly for scripts, but it is
> way easier to write a script formatting it than it is to fix filemon.
> 
> > >>From usability perspective what seems to be needed is few hacks to
> > >ktrace to only log the stuff make is interested in and parsing code for
> > >bmake to translate to what looks like current filemon format for
> > >aformentioned copying.
> > 
> > Perhaps.  But filemon is also a run-time loadable module (and it is
> > preferred that it NOT be built-in to any kernels).  If I remember
> > correctly, ktrace has hooks all over the system and does not readily
> > lend itself to modularization.
> > 
> 
> I doubt that compiling in ktrace on a which can handle filemon is an
> issue, and even then it should outweight hops around filemon.
> 
> For correct of a minimalistic safe filemon module the kernel would
> already have to grow hooks in few places (see below).
> 
> 
> > >Filemon monitors stuff at syscall level, stores the fd and remembers
> > >pids.
> > 
> > The fd is no longer being stored...  :)  But yes, it does still
> > remember pids, so it can determine if an event belongs to a monitored
> > process tree.  Again IIRC, ktrace is somewhat more intrusive, in that
> > it manipulates various process flags which can affect behavior of the
> > target (monitored) process.
> 
> It has a dedicated field in struct proc which is the only sensible way
> of implementing this I can think of.
> 
> > >>               error = kauth_authorize_process(curproc->p_cred,
> > >>                   KAUTH_PROCESS_CANSEE, tp,
> > >>                   KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
> > >
> > >Now that the check is pased the process could have executed something
> > >setuid.
> > 
> > Which process could have executed something setuid?  How would that
> > matter?  (I will confess I haven't checked, but I would be surprised
> > if "executing something setuid" would change the result of kauth()
> > check. But I could be wrong here.)
> > 
> 
> You start monitoring given process and proceed to execve a setuid file,
> which gives you information what it is doing, even though the
> kauth_authorize_process check would fail. This is basically what you
> yourself stated below about pid reuse.
> 
> So this either needs to prevent processes from changing credentials when
> traced or stop tracing when such a change occurs. The former seems like
> a rather bad idea and latter is already done by ktrace.
> 
> > >I'm somewhat surprised this code is here. Should not
> > >kauth_authorize_process assert that tp has stable credentials in some
> > >way, in effect just crashing filemon consumers?
> > >
> > >>               if (!error) {
> > >>                       filemon->fm_pid = tp->p_pid;
> > >>               }
> > 
> > Why does the target process need stable credentials?  It's not doing
> > anything for filemon.
> > 
> 
> See below.
> 
> > >Pid is stored, but tp is not held. What if the 'traced' process exits?
> > >grep only reveals the following bit in filemon_wrapper_sys_exit:
> > >
> > >>               if (filemon->fm_pid == curproc->p_pid)
> > >>                       filemon_printf(filemon, "# Bye bye\n");
> > >
> > >So filemon will continue tracing anything which happened to reuse the
> > >pid.
> > 
> > Yes, this is an outstanding issue.  More particularly, the new user
> > of the pid might not be accessible by the monitoring process (ie, it
> > would fail the earlier kauth() check).  But holding the pointer to
> > the proc isn't really the answer either - although less likely it is
> > entirely possible that the address could have been reused.
> > 
> 
> What you need is the ability to clear tracing bits on process exit.
> ktrace definitely has relevant bits in place already.
> 
> > (It's too bad we don't have "generation numbers" on the pid, which
> > would easily detect reuse.)
> 
> That would require struct proc to be type stable, which seems wasteful.
> 
> > >>                       lp = p;
> > >>                       p = p->p_pptr;
> > >>                       rw_exit(&lp->p_reflock);
> > >
> > >I guess the lock is needed to read the pointer to the parent.
> > 
> > Correct.
> > 
> > >Nothing was done to keep the parent around, which means it could have
> > >exited and be freed by now. Which in turn makes the second loop
> > >iteration a use-after-free.
> > 
> > Hmmm, this code used to work.  Looks like the locking got messed up
> > somewhere.  It should do (in pseudo code - I'm too lazy to write it
> > all out!)
> > 
> > 	lock(p)
> > 	while (p != NULL) {
> > 		TAILQ_FOREACH(filemon) {
> > 			if (p->p_pid == filemon->fm_pid) {
> > 				release(p);
> > 				return filemon;
> > 			}
> > 		}
> > 		last_p = p;
> > 		p = p->pptr;
> > 		if (p != NULL)
> > 			lock(p);
> > 		release(last_p);
> > 	}
> > 
> > We should lock the new (parent) process before releasing the initial
> > lock.
> > 
> > I will fix this.
> > 
> 
> Just locking the parent like that looks like a deadlock potential.
> 
> I just checked both ptrace and exit code. The parent<->child
> relationship is protected with proc_lock and p_lock. p_reflock happens
> to be held in exit1 and also cover the area, but is not held in ptrace.
> 
> Unclear what's the protocol here without proc_lock held. If the sample
> from ptrace is to be trusted, it's locking the lower address first (and
> thus trylocking the lower address if we already got the higher one).
> 
> The sample from sys_ptrace:
> 
> >		struct proc *parent = t->p_pptr;
> >
> >		if (parent->p_lock < t->p_lock) {
> >			if (!mutex_tryenter(parent->p_lock)) {
> >				mutex_exit(t->p_lock);
> >				mutex_enter(parent->p_lock);
> 
> As a side note this looks like a bug. t->p_lock is not relocked, so the
> code ends up without the lock held. There is a similar sample in fork1.
> 
> >			}
> >		} else if (parent->p_lock > t->p_lock) {
> >			mutex_enter(parent->p_lock);
> >		}
> >		parent->p_slflag |= PSL_CHTRACED;
> >		proc_reparent(t, p);
> >		if (parent->p_lock != t->p_lock)
> >			mutex_exit(parent->p_lock);
> >
> 
> That said, even if following p_pptr was the right thing to do, I don't
> think this would get away without hacks or holding proc_lock.
> 
> While the first iteration uses curproc and could reliably lock the
> parent despite possible relocking, the need to keep lower < higher order
> may meen you need to temporarily unlock the process, but for that to not
> be a problem you need to hold the process and/or restart the loop
> possibly with proc_mutex held. Looks very hairy.
> 
> With a dedicated pointer stored in struct proc (like with ktrace) there
> is no need to do any lookups in the first place, so probles like this
> don't arose.
> 
> > >
> > >The first iteration is safe if the argument is curproc (which it is), as
> > >it clearly cannot disappear.
> > >
> > >Turns out this traversal is even more wrong since p_pptr does not have
> > >to be the process you are looking for - ptrace is reparenting tracees.
> > 
> > If the process has been reparented, then its activity will no longer
> > be monitored and reported by filemon.
> > 
> 
> Sorry, I forgot to state the corner case. I can't test it, but if NetBSD
> allows you to trace your parent, the loop above becomes infinite.
> 
> Also you can get surprise events from ptrace tracees.
> 
> So again, I highly doubt filemon in its current form can be made safe to
> use while preserving any advantage over ktrace.
> 
> The thing is there is filemon and bmake in FreeBSD as well. While I
> don't have the time to modify ktrace for this purpose, I would definitely
> help both projects if bmake started moving away from filemon.
> 

Interesting typo. I meant to write: it would help both projects, not that I
would do it.

Still, I'm happy to rant.

> However, this is just my $0,03 as I don't contribute to this project.
> 

-- 
Mateusz Guzik <mjguzik gmail.com>



Home | Main Index | Thread Index | Old Index