[PATCH] SELinux: fix deadlock on dcache lock

This fixes a deadlock on the dcache lock detected during testing at IBM
by moving the logging of the current executable information from the
SELinux avc_audit function to audit_log_exit (via an audit_log_task_info
helper) for processing upon syscall exit.

For consistency, the patch also removes the logging of other
task-related information from avc_audit, deferring handling to
audit_log_exit instead.

This allows simplification of the avc_audit code, allows the exe
information to be obtained more reliably, always includes the comm
information (useful for scripts), and avoids including bogus task
information for checks performed from irq or softirq.

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Stephen Smalley and committed by
Linus Torvalds
219f0817 865108d1

+28 -34
+28
kernel/auditsc.c
··· 610 610 printk(KERN_ERR "audit: freed %d contexts\n", count); 611 611 } 612 612 613 + static void audit_log_task_info(struct audit_buffer *ab) 614 + { 615 + char name[sizeof(current->comm)]; 616 + struct mm_struct *mm = current->mm; 617 + struct vm_area_struct *vma; 618 + 619 + get_task_comm(name, current); 620 + audit_log_format(ab, " comm=%s", name); 621 + 622 + if (!mm) 623 + return; 624 + 625 + down_read(&mm->mmap_sem); 626 + vma = mm->mmap; 627 + while (vma) { 628 + if ((vma->vm_flags & VM_EXECUTABLE) && 629 + vma->vm_file) { 630 + audit_log_d_path(ab, "exe=", 631 + vma->vm_file->f_dentry, 632 + vma->vm_file->f_vfsmnt); 633 + break; 634 + } 635 + vma = vma->vm_next; 636 + } 637 + up_read(&mm->mmap_sem); 638 + } 639 + 613 640 static void audit_log_exit(struct audit_context *context) 614 641 { 615 642 int i; ··· 666 639 context->gid, 667 640 context->euid, context->suid, context->fsuid, 668 641 context->egid, context->sgid, context->fsgid); 642 + audit_log_task_info(ab); 669 643 audit_log_end(ab); 670 644 while (context->aux) { 671 645 struct audit_aux_data *aux;
-34
security/selinux/avc.c
··· 532 532 u16 tclass, u32 requested, 533 533 struct av_decision *avd, int result, struct avc_audit_data *a) 534 534 { 535 - struct task_struct *tsk = current; 536 535 struct inode *inode = NULL; 537 536 u32 denied, audited; 538 537 struct audit_buffer *ab; ··· 555 556 audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); 556 557 avc_dump_av(ab, tclass,audited); 557 558 audit_log_format(ab, " for "); 558 - if (a && a->tsk) 559 - tsk = a->tsk; 560 - if (tsk && tsk->pid) { 561 - struct mm_struct *mm; 562 - struct vm_area_struct *vma; 563 - audit_log_format(ab, " pid=%d", tsk->pid); 564 - if (tsk == current) 565 - mm = current->mm; 566 - else 567 - mm = get_task_mm(tsk); 568 - if (mm) { 569 - if (down_read_trylock(&mm->mmap_sem)) { 570 - vma = mm->mmap; 571 - while (vma) { 572 - if ((vma->vm_flags & VM_EXECUTABLE) && 573 - vma->vm_file) { 574 - audit_log_d_path(ab, "exe=", 575 - vma->vm_file->f_dentry, 576 - vma->vm_file->f_vfsmnt); 577 - break; 578 - } 579 - vma = vma->vm_next; 580 - } 581 - up_read(&mm->mmap_sem); 582 - } else { 583 - audit_log_format(ab, " comm=%s", tsk->comm); 584 - } 585 - if (tsk != current) 586 - mmput(mm); 587 - } else { 588 - audit_log_format(ab, " comm=%s", tsk->comm); 589 - } 590 - } 591 559 if (a) { 592 560 switch (a->type) { 593 561 case AVC_AUDIT_DATA_IPC: