| @@ -139,6 +139,15 @@ static struct task_struct *kauditd_task; · 138 unmodified lines |
| 139 | 139 | static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); |
| 140 | 140 | static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); |
| 141 | 141 | |
| 142 | +static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION, |
| 143 | + .mask = -1, |
| 144 | + .features = 0, |
| 145 | + .lock = 0,}; |
| 146 | + |
| 147 | +static char *audit_feature_names[0] = { |
| 148 | +}; |
| 149 | + |
| 150 | + |
| 142 | 151 | /* Serialize requests from userspace. */ |
| 143 | 152 | DEFINE_MUTEX(audit_cmd_mutex); |
| 144 | 153 | |
| @@ -583,6 +592,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type) · 438 unmodified lines |
| 583 | 592 | return -EOPNOTSUPP; |
| 584 | 593 | case AUDIT_GET: |
| 585 | 594 | case AUDIT_SET: |
| 595 | + case AUDIT_GET_FEATURE: |
| 596 | + case AUDIT_SET_FEATURE: |
| 586 | 597 | case AUDIT_LIST_RULES: |
| 587 | 598 | case AUDIT_ADD_RULE: |
| 588 | 599 | case AUDIT_DEL_RULE: |
| @@ -627,6 +638,94 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type) · 38 unmodified lines |
| 627 | 638 | return rc; |
| 628 | 639 | } |
| 629 | 640 | |
| 641 | +int is_audit_feature_set(int i) |
| 642 | +{ |
| 643 | + return af.features & AUDIT_FEATURE_TO_MASK(i); |
| 644 | +} |
| 645 | + |
| 646 | + |
| 647 | +static 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 | + |
| 659 | +static 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 | + |
| 671 | +static 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 | + |
| 630 | 729 | static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| 631 | 730 | { |
| 632 | 731 | u32 seq; |
| @@ -698,6 +797,16 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) · 65 unmodified lines |
| 698 | 797 | if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) |
| 699 | 798 | err = audit_set_backlog_limit(status_get->backlog_limit); |
| 700 | 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 | 810 | case AUDIT_USER: |
| 702 | 811 | case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: |
| 703 | 812 | case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: |