aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2013-05-22 12:54:49 -0400
committerEric Paris <eparis@redhat.com>2013-11-05 11:07:30 -0500
commitb0fed40214ce79ef70d97584ebdf13f89786da0e (patch)
treefc912434e03f4a300942e809e376e2e4ec2cb837 /kernel
parent42f74461a5b60cf6b42887e6d2ff5b7be4abf1ca (diff)
audit: implement generic feature setting and retrieving
The audit_status structure was not designed with extensibility in mind. Define a new AUDIT_SET_FEATURE message type which takes a new structure of bits where things can be enabled/disabled/locked one at a time. This structure should be able to grow in the future while maintaining forward and backward compatibility (based loosly on the ideas from capabilities and prctl) This does not actually add any features, but is just infrastructure to allow new on/off types of audit system features. Signed-off-by: Eric Paris <eparis@redhat.com> Signed-off-by: Richard Guy Briggs <rgb@redhat.com> Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index 74550ff3644f..29ee6a421c6c 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -139,6 +139,15 @@ static struct task_struct *kauditd_task;
139static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); 139static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
140static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); 140static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
141 141
142static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION,
143 .mask = -1,
144 .features = 0,
145 .lock = 0,};
146
147static char *audit_feature_names[0] = {
148};
149
150
142/* Serialize requests from userspace. */ 151/* Serialize requests from userspace. */
143DEFINE_MUTEX(audit_cmd_mutex); 152DEFINE_MUTEX(audit_cmd_mutex);
144 153
@@ -583,6 +592,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
583 return -EOPNOTSUPP; 592 return -EOPNOTSUPP;
584 case AUDIT_GET: 593 case AUDIT_GET:
585 case AUDIT_SET: 594 case AUDIT_SET:
595 case AUDIT_GET_FEATURE:
596 case AUDIT_SET_FEATURE:
586 case AUDIT_LIST_RULES: 597 case AUDIT_LIST_RULES:
587 case AUDIT_ADD_RULE: 598 case AUDIT_ADD_RULE:
588 case AUDIT_DEL_RULE: 599 case AUDIT_DEL_RULE:
@@ -627,6 +638,94 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
627 return rc; 638 return rc;
628} 639}
629 640
641int is_audit_feature_set(int i)
642{
643 return af.features & AUDIT_FEATURE_TO_MASK(i);
644}
645
646
647static int audit_get_feature(struct sk_buff *skb)
648{
649 u32 seq;
650
651 seq = nlmsg_hdr(skb)->nlmsg_seq;
652
653 audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
654 &af, sizeof(af));
655
656 return 0;
657}
658
659static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature,
660 u32 old_lock, u32 new_lock, int res)
661{
662 struct audit_buffer *ab;
663
664 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
665 audit_log_format(ab, "feature=%s new=%d old=%d old_lock=%d new_lock=%d res=%d",
666 audit_feature_names[which], !!old_feature, !!new_feature,
667 !!old_lock, !!new_lock, res);
668 audit_log_end(ab);
669}
670
671static int audit_set_feature(struct sk_buff *skb)
672{
673 struct audit_features *uaf;
674 int i;
675
676 BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > sizeof(audit_feature_names)/sizeof(audit_feature_names[0]));
677 uaf = nlmsg_data(nlmsg_hdr(skb));
678
679 /* if there is ever a version 2 we should handle that here */
680
681 for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
682 u32 feature = AUDIT_FEATURE_TO_MASK(i);
683 u32 old_feature, new_feature, old_lock, new_lock;
684
685 /* if we are not changing this feature, move along */
686 if (!(feature & uaf->mask))
687 continue;
688
689 old_feature = af.features & feature;
690 new_feature = uaf->features & feature;
691 new_lock = (uaf->lock | af.lock) & feature;
692 old_lock = af.lock & feature;
693
694 /* are we changing a locked feature? */
695 if ((af.lock & feature) && (new_feature != old_feature)) {
696 audit_log_feature_change(i, old_feature, new_feature,
697 old_lock, new_lock, 0);
698 return -EPERM;
699 }
700 }
701 /* nothing invalid, do the changes */
702 for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
703 u32 feature = AUDIT_FEATURE_TO_MASK(i);
704 u32 old_feature, new_feature, old_lock, new_lock;
705
706 /* if we are not changing this feature, move along */
707 if (!(feature & uaf->mask))
708 continue;
709
710 old_feature = af.features & feature;
711 new_feature = uaf->features & feature;
712 old_lock = af.lock & feature;
713 new_lock = (uaf->lock | af.lock) & feature;
714
715 if (new_feature != old_feature)
716 audit_log_feature_change(i, old_feature, new_feature,
717 old_lock, new_lock, 1);
718
719 if (new_feature)
720 af.features |= feature;
721 else
722 af.features &= ~feature;
723 af.lock |= new_lock;
724 }
725
726 return 0;
727}
728
630static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 729static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
631{ 730{
632 u32 seq; 731 u32 seq;
@@ -698,6 +797,16 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
698 if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) 797 if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
699 err = audit_set_backlog_limit(status_get->backlog_limit); 798 err = audit_set_backlog_limit(status_get->backlog_limit);
700 break; 799 break;
800 case AUDIT_GET_FEATURE:
801 err = audit_get_feature(skb);
802 if (err)
803 return err;
804 break;
805 case AUDIT_SET_FEATURE:
806 err = audit_set_feature(skb);
807 if (err)
808 return err;
809 break;
701 case AUDIT_USER: 810 case AUDIT_USER:
702 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: 811 case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
703 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: 812 case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: