[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 printk(KERN_ERR "audit: freed %d contexts\n", count); 611 } 612 613 static void audit_log_exit(struct audit_context *context) 614 { 615 int i; ··· 666 context->gid, 667 context->euid, context->suid, context->fsuid, 668 context->egid, context->sgid, context->fsgid); 669 audit_log_end(ab); 670 while (context->aux) { 671 struct audit_aux_data *aux;
··· 610 printk(KERN_ERR "audit: freed %d contexts\n", count); 611 } 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 + 640 static void audit_log_exit(struct audit_context *context) 641 { 642 int i; ··· 639 context->gid, 640 context->euid, context->suid, context->fsuid, 641 context->egid, context->sgid, context->fsgid); 642 + audit_log_task_info(ab); 643 audit_log_end(ab); 644 while (context->aux) { 645 struct audit_aux_data *aux;
-34
security/selinux/avc.c
··· 532 u16 tclass, u32 requested, 533 struct av_decision *avd, int result, struct avc_audit_data *a) 534 { 535 - struct task_struct *tsk = current; 536 struct inode *inode = NULL; 537 u32 denied, audited; 538 struct audit_buffer *ab; ··· 555 audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); 556 avc_dump_av(ab, tclass,audited); 557 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 if (a) { 592 switch (a->type) { 593 case AVC_AUDIT_DATA_IPC:
··· 532 u16 tclass, u32 requested, 533 struct av_decision *avd, int result, struct avc_audit_data *a) 534 { 535 struct inode *inode = NULL; 536 u32 denied, audited; 537 struct audit_buffer *ab; ··· 556 audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); 557 avc_dump_av(ab, tclass,audited); 558 audit_log_format(ab, " for "); 559 if (a) { 560 switch (a->type) { 561 case AVC_AUDIT_DATA_IPC: