diff options
author | Thomas Liu <tliu@redhat.com> | 2009-07-14 12:14:09 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-08-16 18:37:18 -0400 |
commit | 2bf49690325b62480a42f7afed5e9f164173c570 (patch) | |
tree | bc8525f6a45ea3ffaed9449084df7644bcd4e3c2 /security/selinux/avc.c | |
parent | f322abf83feddc3c37c3a91794e0c5aece4af18e (diff) |
SELinux: Convert avc_audit to use lsm_audit.h
Convert avc_audit in security/selinux/avc.c to use lsm_audit.h,
for better maintainability.
- changed selinux to use common_audit_data instead of
avc_audit_data
- eliminated code in avc.c and used code from lsm_audit.h instead.
Had to add a LSM_AUDIT_NO_AUDIT to lsm_audit.h so that avc_audit
can call common_lsm_audit and do the pre and post callbacks without
doing the actual dump. This makes it so that the patched version
behaves the same way as the unpatched version.
Also added a denied field to the selinux_audit_data private space,
once again to make it so that the patched version behaves like the
unpatched.
I've tested and confirmed that AVCs look the same before and after
this patch.
Signed-off-by: Thomas Liu <tliu@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r-- | security/selinux/avc.c | 197 |
1 files changed, 41 insertions, 156 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 236aaa2ea86d..e3d19014259b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -492,23 +492,35 @@ 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 | audit_log_format(ab, "avc: %s ", |
501 | if (port) | 505 | ad->selinux_audit_data.denied ? "denied" : "granted"); |
502 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 506 | avc_dump_av(ab, ad->selinux_audit_data.tclass, |
507 | ad->selinux_audit_data.audited); | ||
508 | audit_log_format(ab, " for "); | ||
503 | } | 509 | } |
504 | 510 | ||
505 | static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | 511 | /** |
506 | __be16 port, char *name1, char *name2) | 512 | * avc_audit_post_callback - SELinux specific information |
513 | * will be called by generic audit code | ||
514 | * @ab: the audit buffer | ||
515 | * @a: audit_data | ||
516 | */ | ||
517 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | ||
507 | { | 518 | { |
508 | if (addr) | 519 | struct common_audit_data *ad = a; |
509 | audit_log_format(ab, " %s=%pI4", name1, &addr); | 520 | audit_log_format(ab, " "); |
510 | if (port) | 521 | avc_dump_query(ab, ad->selinux_audit_data.ssid, |
511 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 522 | ad->selinux_audit_data.tsid, |
523 | ad->selinux_audit_data.tclass); | ||
512 | } | 524 | } |
513 | 525 | ||
514 | /** | 526 | /** |
@@ -532,13 +544,10 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | |||
532 | */ | 544 | */ |
533 | void avc_audit(u32 ssid, u32 tsid, | 545 | void avc_audit(u32 ssid, u32 tsid, |
534 | u16 tclass, u32 requested, | 546 | u16 tclass, u32 requested, |
535 | struct av_decision *avd, int result, struct avc_audit_data *a) | 547 | struct av_decision *avd, int result, struct common_audit_data *a) |
536 | { | 548 | { |
537 | struct task_struct *tsk = current; | 549 | struct common_audit_data stack_data; |
538 | struct inode *inode = NULL; | ||
539 | u32 denied, audited; | 550 | u32 denied, audited; |
540 | struct audit_buffer *ab; | ||
541 | |||
542 | denied = requested & ~avd->allowed; | 551 | denied = requested & ~avd->allowed; |
543 | if (denied) { | 552 | if (denied) { |
544 | audited = denied; | 553 | audited = denied; |
@@ -551,144 +560,20 @@ void avc_audit(u32 ssid, u32 tsid, | |||
551 | if (!(audited & avd->auditallow)) | 560 | if (!(audited & avd->auditallow)) |
552 | return; | 561 | return; |
553 | } | 562 | } |
554 | 563 | if (!a) { | |
555 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); | 564 | a = &stack_data; |
556 | if (!ab) | 565 | memset(a, 0, sizeof(*a)); |
557 | return; /* audit_panic has been called */ | 566 | a->type = LSM_AUDIT_NO_AUDIT; |
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 | } | 567 | } |
689 | audit_log_format(ab, " "); | 568 | a->selinux_audit_data.tclass = tclass; |
690 | avc_dump_query(ab, ssid, tsid, tclass); | 569 | a->selinux_audit_data.requested = requested; |
691 | audit_log_end(ab); | 570 | a->selinux_audit_data.ssid = ssid; |
571 | a->selinux_audit_data.tsid = tsid; | ||
572 | a->selinux_audit_data.audited = audited; | ||
573 | a->selinux_audit_data.denied = denied; | ||
574 | a->lsm_pre_audit = avc_audit_pre_callback; | ||
575 | a->lsm_post_audit = avc_audit_post_callback; | ||
576 | common_lsm_audit(a); | ||
692 | } | 577 | } |
693 | 578 | ||
694 | /** | 579 | /** |
@@ -956,7 +841,7 @@ out: | |||
956 | * another -errno upon other errors. | 841 | * another -errno upon other errors. |
957 | */ | 842 | */ |
958 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 843 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, |
959 | u32 requested, struct avc_audit_data *auditdata) | 844 | u32 requested, struct common_audit_data *auditdata) |
960 | { | 845 | { |
961 | struct av_decision avd; | 846 | struct av_decision avd; |
962 | int rc; | 847 | int rc; |