diff options
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r-- | security/selinux/avc.c | 218 |
1 files changed, 48 insertions, 170 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 236aaa2ea86d..d9fd22488ef8 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -492,23 +492,50 @@ out: | |||
492 | return node; | 492 | return node; |
493 | } | 493 | } |
494 | 494 | ||
495 | static inline void avc_print_ipv6_addr(struct audit_buffer *ab, | 495 | /** |
496 | struct in6_addr *addr, __be16 port, | 496 | * avc_audit_pre_callback - SELinux specific information |
497 | char *name1, char *name2) | 497 | * will be called by generic audit code |
498 | * @ab: the audit buffer | ||
499 | * @a: audit_data | ||
500 | */ | ||
501 | static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | ||
498 | { | 502 | { |
499 | if (!ipv6_addr_any(addr)) | 503 | struct common_audit_data *ad = a; |
500 | audit_log_format(ab, " %s=%pI6", name1, addr); | 504 | struct av_decision *avd = ad->selinux_audit_data.avd; |
501 | if (port) | 505 | u32 requested = ad->selinux_audit_data.requested; |
502 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 506 | int result = ad->selinux_audit_data.result; |
507 | u32 denied, audited; | ||
508 | denied = requested & ~avd->allowed; | ||
509 | if (denied) { | ||
510 | audited = denied; | ||
511 | if (!(audited & avd->auditdeny)) | ||
512 | return; | ||
513 | } else if (result) { | ||
514 | audited = denied = requested; | ||
515 | } else { | ||
516 | audited = requested; | ||
517 | if (!(audited & avd->auditallow)) | ||
518 | return; | ||
519 | } | ||
520 | audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); | ||
521 | avc_dump_av(ab, ad->selinux_audit_data.tclass, | ||
522 | ad->selinux_audit_data.audited); | ||
523 | audit_log_format(ab, " for "); | ||
503 | } | 524 | } |
504 | 525 | ||
505 | static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | 526 | /** |
506 | __be16 port, char *name1, char *name2) | 527 | * avc_audit_post_callback - SELinux specific information |
528 | * will be called by generic audit code | ||
529 | * @ab: the audit buffer | ||
530 | * @a: audit_data | ||
531 | */ | ||
532 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | ||
507 | { | 533 | { |
508 | if (addr) | 534 | struct common_audit_data *ad = a; |
509 | audit_log_format(ab, " %s=%pI4", name1, &addr); | 535 | audit_log_format(ab, " "); |
510 | if (port) | 536 | avc_dump_query(ab, ad->selinux_audit_data.ssid, |
511 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 537 | ad->selinux_audit_data.tsid, |
538 | ad->selinux_audit_data.tclass); | ||
512 | } | 539 | } |
513 | 540 | ||
514 | /** | 541 | /** |
@@ -532,163 +559,14 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | |||
532 | */ | 559 | */ |
533 | void avc_audit(u32 ssid, u32 tsid, | 560 | void avc_audit(u32 ssid, u32 tsid, |
534 | u16 tclass, u32 requested, | 561 | u16 tclass, u32 requested, |
535 | struct av_decision *avd, int result, struct avc_audit_data *a) | 562 | struct av_decision *avd, int result, struct common_audit_data *a) |
536 | { | 563 | { |
537 | struct task_struct *tsk = current; | 564 | a->selinux_audit_data.avd = avd; |
538 | struct inode *inode = NULL; | 565 | a->selinux_audit_data.tclass = tclass; |
539 | u32 denied, audited; | 566 | a->selinux_audit_data.requested = requested; |
540 | struct audit_buffer *ab; | 567 | a->lsm_pre_audit = avc_audit_pre_callback; |
541 | 568 | a->lsm_post_audit = avc_audit_post_callback; | |
542 | denied = requested & ~avd->allowed; | 569 | common_lsm_audit(a); |
543 | if (denied) { | ||
544 | audited = denied; | ||
545 | if (!(audited & avd->auditdeny)) | ||
546 | return; | ||
547 | } else if (result) { | ||
548 | audited = denied = requested; | ||
549 | } else { | ||
550 | audited = requested; | ||
551 | if (!(audited & avd->auditallow)) | ||
552 | return; | ||
553 | } | ||
554 | |||
555 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); | ||
556 | if (!ab) | ||
557 | return; /* audit_panic has been called */ | ||
558 | audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); | ||
559 | avc_dump_av(ab, tclass, audited); | ||
560 | audit_log_format(ab, " for "); | ||
561 | if (a && a->tsk) | ||
562 | tsk = a->tsk; | ||
563 | if (tsk && tsk->pid) { | ||
564 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
565 | audit_log_untrustedstring(ab, tsk->comm); | ||
566 | } | ||
567 | if (a) { | ||
568 | switch (a->type) { | ||
569 | case AVC_AUDIT_DATA_IPC: | ||
570 | audit_log_format(ab, " key=%d", a->u.ipc_id); | ||
571 | break; | ||
572 | case AVC_AUDIT_DATA_CAP: | ||
573 | audit_log_format(ab, " capability=%d", a->u.cap); | ||
574 | break; | ||
575 | case AVC_AUDIT_DATA_FS: | ||
576 | if (a->u.fs.path.dentry) { | ||
577 | struct dentry *dentry = a->u.fs.path.dentry; | ||
578 | if (a->u.fs.path.mnt) { | ||
579 | audit_log_d_path(ab, "path=", | ||
580 | &a->u.fs.path); | ||
581 | } else { | ||
582 | audit_log_format(ab, " name="); | ||
583 | audit_log_untrustedstring(ab, dentry->d_name.name); | ||
584 | } | ||
585 | inode = dentry->d_inode; | ||
586 | } else if (a->u.fs.inode) { | ||
587 | struct dentry *dentry; | ||
588 | inode = a->u.fs.inode; | ||
589 | dentry = d_find_alias(inode); | ||
590 | if (dentry) { | ||
591 | audit_log_format(ab, " name="); | ||
592 | audit_log_untrustedstring(ab, dentry->d_name.name); | ||
593 | dput(dentry); | ||
594 | } | ||
595 | } | ||
596 | if (inode) | ||
597 | audit_log_format(ab, " dev=%s ino=%lu", | ||
598 | inode->i_sb->s_id, | ||
599 | inode->i_ino); | ||
600 | break; | ||
601 | case AVC_AUDIT_DATA_NET: | ||
602 | if (a->u.net.sk) { | ||
603 | struct sock *sk = a->u.net.sk; | ||
604 | struct unix_sock *u; | ||
605 | int len = 0; | ||
606 | char *p = NULL; | ||
607 | |||
608 | switch (sk->sk_family) { | ||
609 | case AF_INET: { | ||
610 | struct inet_sock *inet = inet_sk(sk); | ||
611 | |||
612 | avc_print_ipv4_addr(ab, inet->rcv_saddr, | ||
613 | inet->sport, | ||
614 | "laddr", "lport"); | ||
615 | avc_print_ipv4_addr(ab, inet->daddr, | ||
616 | inet->dport, | ||
617 | "faddr", "fport"); | ||
618 | break; | ||
619 | } | ||
620 | case AF_INET6: { | ||
621 | struct inet_sock *inet = inet_sk(sk); | ||
622 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | ||
623 | |||
624 | avc_print_ipv6_addr(ab, &inet6->rcv_saddr, | ||
625 | inet->sport, | ||
626 | "laddr", "lport"); | ||
627 | avc_print_ipv6_addr(ab, &inet6->daddr, | ||
628 | inet->dport, | ||
629 | "faddr", "fport"); | ||
630 | break; | ||
631 | } | ||
632 | case AF_UNIX: | ||
633 | u = unix_sk(sk); | ||
634 | if (u->dentry) { | ||
635 | struct path path = { | ||
636 | .dentry = u->dentry, | ||
637 | .mnt = u->mnt | ||
638 | }; | ||
639 | audit_log_d_path(ab, "path=", | ||
640 | &path); | ||
641 | break; | ||
642 | } | ||
643 | if (!u->addr) | ||
644 | break; | ||
645 | len = u->addr->len-sizeof(short); | ||
646 | p = &u->addr->name->sun_path[0]; | ||
647 | audit_log_format(ab, " path="); | ||
648 | if (*p) | ||
649 | audit_log_untrustedstring(ab, p); | ||
650 | else | ||
651 | audit_log_n_hex(ab, p, len); | ||
652 | break; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | switch (a->u.net.family) { | ||
657 | case AF_INET: | ||
658 | avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, | ||
659 | a->u.net.sport, | ||
660 | "saddr", "src"); | ||
661 | avc_print_ipv4_addr(ab, a->u.net.v4info.daddr, | ||
662 | a->u.net.dport, | ||
663 | "daddr", "dest"); | ||
664 | break; | ||
665 | case AF_INET6: | ||
666 | avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr, | ||
667 | a->u.net.sport, | ||
668 | "saddr", "src"); | ||
669 | avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr, | ||
670 | a->u.net.dport, | ||
671 | "daddr", "dest"); | ||
672 | break; | ||
673 | } | ||
674 | if (a->u.net.netif > 0) { | ||
675 | struct net_device *dev; | ||
676 | |||
677 | /* NOTE: we always use init's namespace */ | ||
678 | dev = dev_get_by_index(&init_net, | ||
679 | a->u.net.netif); | ||
680 | if (dev) { | ||
681 | audit_log_format(ab, " netif=%s", | ||
682 | dev->name); | ||
683 | dev_put(dev); | ||
684 | } | ||
685 | } | ||
686 | break; | ||
687 | } | ||
688 | } | ||
689 | audit_log_format(ab, " "); | ||
690 | avc_dump_query(ab, ssid, tsid, tclass); | ||
691 | audit_log_end(ab); | ||
692 | } | 570 | } |
693 | 571 | ||
694 | /** | 572 | /** |
@@ -956,7 +834,7 @@ out: | |||
956 | * another -errno upon other errors. | 834 | * another -errno upon other errors. |
957 | */ | 835 | */ |
958 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 836 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, |
959 | u32 requested, struct avc_audit_data *auditdata) | 837 | u32 requested, struct common_audit_data *auditdata) |
960 | { | 838 | { |
961 | struct av_decision avd; | 839 | struct av_decision avd; |
962 | int rc; | 840 | int rc; |