Re: [PATCH v2.1] audit: Only use the syscall slowpath when syscall audit rules exist

2014-02-05 Thread Eric Paris
On Mon, 2014-02-03 at 11:11 -0800, Andy Lutomirski wrote:

 +void audit_inc_n_rules()
 +{
 + struct task_struct *p, *g;
 + unsigned long flags;
 +
 + read_lock_irqsave(tasklist_lock, flags);
 + if (audit_n_rules++ == 0) {

I know it's right, but it's too clever for me  :)  If we do end up
adding something like this Can we just do:
   if (!audit_n_rules) {}
   audit_n_rules++

I like dumb code   :)

 + do_each_thread(g, p) {
 + if (p-audit_context)
 + set_tsk_thread_flag(p, TIF_SYSCALL_AUDIT);
 + } while_each_thread(g, p);
 + }
 + read_unlock_irqrestore(tasklist_lock, flags);
 +}

--
Linux-audit mailing list
Linux-audit@redhat.com
https://www.redhat.com/mailman/listinfo/linux-audit


Re: [PATCH v2.1] audit: Only use the syscall slowpath when syscall audit rules exist

2014-02-04 Thread Oleg Nesterov
On 02/03, Andy Lutomirski wrote:

 +void audit_inc_n_rules()
 +{
 + struct task_struct *p, *g;
 + unsigned long flags;
 +
 + read_lock_irqsave(tasklist_lock, flags);

Confused... read_lock(tasklist) doesn't need to disable irqs.

(ftrace does this for no reason too, perhaps I should resend the patch)

 + if (audit_n_rules++ == 0) {

probably this can be done outside of read_lock?

 + do_each_thread(g, p) {

for_each_process_thread ;) do_each_thread will die, I hope.

 +void audit_dec_n_rules()
 +{
 + struct task_struct *p, *g;
 + unsigned long flags;
 +
 + read_lock_irqsave(tasklist_lock, flags);
 +
 + --audit_n_rules;
 + BUG_ON(audit_n_rules  0);
 +
 + if (audit_n_rules == 0) {
 + do_each_thread(g, p) {
 + clear_tsk_thread_flag(p, TIF_SYSCALL_AUDIT);
 + } while_each_thread(g, p);
 + }

The same, and...

On a second thought it seems that audit_dec_n_rules() has a problem.
Note the BUG_ON(context-in_syscall) in __audit_syscall_entry().

Suppose that audit_dec_n_rules() clears TIF_SYSCALL_AUDIT when a task
runs a syscall. In this case (afaics) __audit_syscall_exit() won't be
called. The next audit_inc_n_rules() can set TIF_SYSCALL_AUDIT and
trigger another __audit_syscall_entry() which will hit this BUG_ON().

And in general it doesn't look safe although I know almost nothing
about audit. I mean, currently __audit_syscall_entry() or
__audit_log_bprm_fcaps() assume that __audit_syscall_exit() or
__audit_free() will cleanup -audit_context, perhaps we should not
break the rules?

Once again, I do not pretend I understand this code, this is the
question, not the comment.

But if I am right, then TIF_SYSCALL_AUDIT should be cleared in
__audit_syscall_exit() as you suggested before.

Oleg.

--
Linux-audit mailing list
Linux-audit@redhat.com
https://www.redhat.com/mailman/listinfo/linux-audit


Re: [PATCH v2.1] audit: Only use the syscall slowpath when syscall audit rules exist

2014-02-04 Thread Andy Lutomirski
On Tue, Feb 4, 2014 at 8:50 AM, Oleg Nesterov o...@redhat.com wrote:
 On 02/03, Andy Lutomirski wrote:

 +void audit_inc_n_rules()
 +{
 + struct task_struct *p, *g;
 + unsigned long flags;
 +
 + read_lock_irqsave(tasklist_lock, flags);

 Confused... read_lock(tasklist) doesn't need to disable irqs.

 (ftrace does this for no reason too, perhaps I should resend the patch)

Is this because there are no interrupt handlers that write_lock(tasklist)?


 + if (audit_n_rules++ == 0) {

 probably this can be done outside of read_lock?

I don't think so.  I'm cheating and using the tasklist_lock to prevent
audit_sync_flags from racing against this increment, so this needs to
be inside the lock.  I'll add a comment.


 + do_each_thread(g, p) {

 for_each_process_thread ;) do_each_thread will die, I hope.


Sorry, forgot to mention: where is this mythical
for_each_process_thread?  Either it only exists in a kernel version
I'm not looking at, my grepping skills aren't up to the task, or you
just hate do_each_thread so much that you imagined up an alternative
:)

 +void audit_dec_n_rules()
 +{
 + struct task_struct *p, *g;
 + unsigned long flags;
 +
 + read_lock_irqsave(tasklist_lock, flags);
 +
 + --audit_n_rules;
 + BUG_ON(audit_n_rules  0);
 +
 + if (audit_n_rules == 0) {
 + do_each_thread(g, p) {
 + clear_tsk_thread_flag(p, TIF_SYSCALL_AUDIT);
 + } while_each_thread(g, p);
 + }

 The same, and...

 On a second thought it seems that audit_dec_n_rules() has a problem.
 Note the BUG_ON(context-in_syscall) in __audit_syscall_entry().

 Suppose that audit_dec_n_rules() clears TIF_SYSCALL_AUDIT when a task
 runs a syscall. In this case (afaics) __audit_syscall_exit() won't be
 called. The next audit_inc_n_rules() can set TIF_SYSCALL_AUDIT and
 trigger another __audit_syscall_entry() which will hit this BUG_ON().


Egads!

 And in general it doesn't look safe although I know almost nothing
 about audit. I mean, currently __audit_syscall_entry() or
 __audit_log_bprm_fcaps() assume that __audit_syscall_exit() or
 __audit_free() will cleanup -audit_context, perhaps we should not
 break the rules?

 Once again, I do not pretend I understand this code, this is the
 question, not the comment.

 But if I am right, then TIF_SYSCALL_AUDIT should be cleared in
 __audit_syscall_exit() as you suggested before.

I think I'll wait for Eric to chime in.  I suspect that the real
solution is to simplify all this stuff by relying on the fact that the
syscall nr and args are saved by the (fast path and slow path) entry
code, so the audit entry hook may be entirely unnecessary.  Or maybe a
new TIF flag would be needed to make it work.

Anyway, *grumble*.  My only real interest in this stuff is to get rid
of the overhead.  I don't actually want syscall auditing on any of my
boxes (in contrast to avc auditing, which is useful but (mostly)
independent).

--Andy

--
Linux-audit mailing list
Linux-audit@redhat.com
https://www.redhat.com/mailman/listinfo/linux-audit


Re: [PATCH v2.1] audit: Only use the syscall slowpath when syscall audit rules exist

2014-02-04 Thread Oleg Nesterov
On 02/04, Andy Lutomirski wrote:

 On Tue, Feb 4, 2014 at 8:50 AM, Oleg Nesterov o...@redhat.com wrote:
  On 02/03, Andy Lutomirski wrote:
 
  +void audit_inc_n_rules()
  +{
  + struct task_struct *p, *g;
  + unsigned long flags;
  +
  + read_lock_irqsave(tasklist_lock, flags);
 
  Confused... read_lock(tasklist) doesn't need to disable irqs.
 
  (ftrace does this for no reason too, perhaps I should resend the patch)

 Is this because there are no interrupt handlers that write_lock(tasklist)?

Yes.

 
  + if (audit_n_rules++ == 0) {
 
  probably this can be done outside of read_lock?

 I don't think so.  I'm cheating and using the tasklist_lock to prevent
 audit_sync_flags

Ah, yes, you are right.

  + do_each_thread(g, p) {
 
  for_each_process_thread ;) do_each_thread will die, I hope.
 

 Sorry, forgot to mention: where is this mythical
 for_each_process_thread?

In Linus's tree, please see 0c740d0afc3bff.

 or you
 just hate do_each_thread so much that you imagined up an alternative
 :)

sort of ;)

 I think I'll wait for Eric to chime in.  I suspect that the real
 solution is to simplify all this stuff by relying on the fact that the
 syscall nr and args are saved by the (fast path and slow path) entry
 code, so the audit entry hook may be entirely unnecessary.

Perhaps... but even in this case we need to do something with, say,
__audit_log_bprm_fcaps().

At least this list should not grow indefinitely if the task skips
__audit_syscall_exit(). Although at first glance this can be probably
cleanuped too.

Oleg.

--
Linux-audit mailing list
Linux-audit@redhat.com
https://www.redhat.com/mailman/listinfo/linux-audit


Re: [PATCH v2.1] audit: Only use the syscall slowpath when syscall audit rules exist

2014-02-04 Thread Andy Lutomirski
On Tue, Feb 4, 2014 at 11:11 AM, Oleg Nesterov o...@redhat.com wrote:
 On 02/04, Andy Lutomirski wrote:
 On Tue, Feb 4, 2014 at 8:50 AM, Oleg Nesterov o...@redhat.com wrote:
  On 02/03, Andy Lutomirski wrote:
 Sorry, forgot to mention: where is this mythical
 for_each_process_thread?

 In Linus's tree, please see 0c740d0afc3bff.

 or you
 just hate do_each_thread so much that you imagined up an alternative
 :)

 sort of ;)

Aha -- it probably got merged just after I pulled Linus' tree and
looked for it.  Or something.


 I think I'll wait for Eric to chime in.  I suspect that the real
 solution is to simplify all this stuff by relying on the fact that the
 syscall nr and args are saved by the (fast path and slow path) entry
 code, so the audit entry hook may be entirely unnecessary.

 Perhaps... but even in this case we need to do something with, say,
 __audit_log_bprm_fcaps().

 At least this list should not grow indefinitely if the task skips
 __audit_syscall_exit(). Although at first glance this can be probably
 cleanuped too.

OK, here's a thought: let's change the semantics of TIF_SYSCALL_AUDIT.
 New semantics:

TIF_SYSCALL_AUDIT is set if (the task is eligible for syscall auditing
and n_rules != 0 *or* something has started writing an audit record).
TIF_SYSCALL_AUDIT is *never* cleared by anything other than
copy_process or __audit_syscall_exit.

This means that, if there's a pending audit record, then
TIF_SYSCALL_AUDIT will be set.  That, in turn, means that
__audit_syscall_exit will be called, which avoids the BUGs you pointed
out.

Now we get rid of __audit_syscall_entry.  (This speeds up even the
auditing-is-on case.)  Instead we have __audit_start_record, which
does more or less the same thing, except that (a) it doesn't BUG if
in_syscall and (b) it *sets* TIF_SYSCALL_AUDIT.  This relies on the
fact that syscall_get_nr and syscall_get_arguments are reliable on
x86_64.  I suspect that they're reliable everywhere else, too.  The
idea is that there's nothing wrong with calling __audit_start_record
more than once.  (Maybe it should be called
__audit_record_this_syscall.)

To finish the job, we change __audit_syscall_exit to clear
TIF_SYSCALL_AUDIT if n_rules==0.  inc_n_rules can set
TIF_SYSCALL_AUDIT (without even needing to worry about races, I
think).  dec_n_rules doesn't need to do anything special.

Benefits:
 - Removing the syscall entry hook speeds everyone up.  Even silly
people who use exit rules :)
 - There's no need to think about mismatched entry/exit hook calls,
since there is no entry hook.
 - The same mechanism could be reused for non-audit purposes.  Any
code could say, at any point hey, this syscall is interesting.  let's
record it.

Disadvantages:
 - Need to check other architectures to make sure that syscall_get_xyz
works reliably for fast path syscalls.
 - For the full performance boost, all architectures need to avoid
checking TIF_SYSCALL_AUDIT in the entry path.  I prefer not to mess
with non-x86 assembly, so I won't do that part, since it's not
required for correctness.

Eric, any thoughts?

--Andy

--
Linux-audit mailing list
Linux-audit@redhat.com
https://www.redhat.com/mailman/listinfo/linux-audit