分类: LINUX
2010-01-27 10:55:44
1)auditd
启用方法:service auditd start(auditd)
禁用方法:service auditd stop
2)内核审计功能,消息获取部分
启用方法:启动参数audit=1;auditctl -e 1
禁用方法:auditctl -e 0
1) 定义
/* The audit_buffer is used when formatting an audit record. The caller
* locks briefly to get the record off the freelist or to allocate the
* buffer, and locks briefly to send the buffer to the netlink layer or
* to place it on a transmit queue. Multiple audit_buffers can be in
* use simultaneously. */
struct audit_buffer {
struct list_head list;
struct sk_buff *skb; /* formatted skb ready to send */
struct audit_context *ctx; /* NULL or associated context */
gfp_t gfp_mask;
};
2) 说明
审计缓冲区。包含了sk_buff描述的套接字缓冲区。套接字缓冲区用来存储审计消息。
1) 定义
/* The audit_freelist is a list of pre-allocated audit buffers (if more
* than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
* being placed on the freelist). */
static DEFINE_SPINLOCK(audit_freelist_lock);
static int audit_freelist_count;
static LIST_HEAD(audit_freelist);
/* AUDIT_MAXFREE is the number of empty audit_buffers we keep on the
* audit_freelist. Doing so eliminates many kmalloc/kfree calls. */
#define AUDIT_MAXFREE (2*NR_CPUS)
2) 说明
当使用audit_buffer_alloc()申请新的审计缓冲区时,如果audit_freelist存在空闲的,直接取下使用;否则分配。
当使用audit_buffer_free()释放审计缓冲区时,如果audit_freelist_count > AUDIT_MAXFREE,释放。否则audit_freelist_count++;并且加入空闲链表:list_add(&ab->list, &audit_freelist);
1) 定义
static struct sk_buff_head audit_skb_queue;
2) 说明
用于存放审计消息的具体内容。
链表的长度存在限制。当超过长度限制时,不能往里面加入新的sk_buff,需要等待内核线程kauditd将至少一个sk_buff发送到用户空间。
1) 定义
/* Audit filter lists, defined in
struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
LIST_HEAD_INIT(audit_filter_list[0]),
LIST_HEAD_INIT(audit_filter_list[1]),
LIST_HEAD_INIT(audit_filter_list[2]),
LIST_HEAD_INIT(audit_filter_list[3]),
LIST_HEAD_INIT(audit_filter_list[4]),
LIST_HEAD_INIT(audit_filter_list[5]),
#if AUDIT_NR_FILTERS != 6
#error Fix audit_filter_list initialiser
#endif
};
struct audit_entry {
struct list_head list;
struct rcu_head rcu;
struct audit_krule rule;
};
struct audit_krule {
int vers_ops;
u32 flags;
u32 listnr; // AUDIT_FILTER_USER等
u32 action; // AUDIT_NEVER || AUDIT_ALWAYS
u32 mask[AUDIT_BITMASK_SIZE];
u32 buflen; /* for data alloc on list rules */
u32 field_count; // audit_field的个数
char *filterkey; /* ties events to rules */
struct audit_field *fields;
struct audit_field *arch_f; /* quick access to arch field */
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct audit_tree *tree; /* associated watched tree */
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
};
struct audit_field {
u32 type; //事件类型,参考audit_filter_user_rules
u32 val; //设置的值,被比较
u32 op; //操作符
char *se_str;
struct selinux_audit_rule *se_rule;
};
2) 说明
6条链表,分别对应6种事件。
1) 说明
如果不为0,限制每秒发送的审计记录个数。防止DOS攻击。
1) 定义
static atomic_t audit_lost = ATOMIC_INIT(0);
2) 说明
丢失的审计记录数。造成丢失的途径:
0) [suppressed in audit_alloc]
1) out of memory in audit_log_start [kmalloc of struct audit_buffer]
2) out of memory in audit_log_move [alloc_skb]
3) suppressed due to audit_rate_limit
4) suppressed due to audit_backlog_limit
1) 定义
/* Hash for inode-based rules */
struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
#define AUDIT_INODE_BUCKETS 32
2) 说明
貌似不重要
1) 说明
调用netlink_kernel_create(),创建netlink套接字,注册接受函数:
audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive, THIS_MODULE);
初始化套接字链表:
skb_queue_head_init(&audit_skb_queue);
注册SELinux回调函数:
selinux_audit_set_callback(&selinux_audit_rule_update);
如果定义了CONFIG_AUDITSYSCALL,注册inotify操作函数集:
audit_ih = inotify_init(&audit_inotify_ops);
[用法?]于节点的规则的hash表:
INIT_LIST_HEAD(&audit_inode_hash[i]);
1) 说明
audit_receive() -> audit_receive_skb() -> audit_receive_msg(skb, nlh)
audit_receive_msg()中根据不同的msg_type = nlh->nlmsg_type;进行检查后。
第一次接受消息时,创建内核线程kauditd:
if (!kauditd_task)
kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
根据msg_type进行不同的处理:
switch (msg_type) {
case AUDIT_GET:
audit_send_reply //发送Audit状态信息
case AUDIT_SET:
audit_set_enabled audit_set_failure audit_set_rate_limit audit_set_backlog_limit //设置Audit参数
case AUDIT_USER:
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
audit_filter_user; //调用audit_filter_user_rules,[后面介绍]
case AUDIT_ADD:
case AUDIT_DEL:
case AUDIT_LIST:
audit_receive_filter
case AUDIT_ADD_RULE:
case AUDIT_DEL_RULE:
case AUDIT_LIST_RULES:
audit_receive_filter
case AUDIT_TRIM:
audit_trim_trees();
case AUDIT_MAKE_EQUIV:
audit_tag_tree
case AUDIT_SIGNAL_INFO:
audit_send_reply
1) 说明
kauditd_thread()
取下一个skb,唤醒audit_backlog_wait队列上的等待者。
如果存在audit_pid,发送netlink_unicast(audit_sock, skb, audit_pid, 0);否则printk
如果audit_skb_queue为空,加入kauditd_wait队列等待。
1) 定义
static inline int audit_rate_check(void)
2) 说明
返回1表示没有超过速率限制;返回0表示速率过快。
如果audit_rate_limit等于0,表示不限速(默认),返回1。
如果发送的审计记录数不小于audit_rate_limit,在<=1秒,那么返回0。
被audit_log_start[audit_skb_queue长度超限]和audit_log_end调用。
1) 定义
/**
* audit_log_lost - conditionally log lost audit message event
* @message: the message stating reason for lost audit message
*
* Emit at least 1 message per second, even if audit_rate_check is
* throttling.
* Always increment the lost messages counter.
*/
void audit_log_lost(const char *message)
2) 说明
首先增加atomic_inc(&audit_lost);
然后判断要不要进行处理print = (audit_failure == AUDIT_FAIL_PANIC || !audit_rate_limit);
如果设置了audit_failure == AUDIT_FAIL_PANIC;或者不限速audit_rate_limit==0;那么需要处理。
如果限速,那么如果自打上次处理以来超过1秒了,就要处理。如果不超过1秒,就不处理。
根据处理标志print,调用audit_panic进行lost时的处理。
1) 定义
struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type)
2) 说明
首先调用audit_filter_type,检查根据audit_filter_list[AUDIT_FILTER_TYPE],不想要的事件类型将不继续处理。
如果套接字缓冲区列表超过长度限制,那么可能会1)加入等待队列audit_backlog_wait。2)报错返回NULL(检查发送的速率)
如果不超长,ab = audit_buffer_alloc(ctx, gfp_mask, type);申请audit_buffer。
分配成功的话,获得时间戳和序列号,调用audit_log_format(ab, "audit(%lu.%03lu:%u): ", t.tv_sec, t.tv_nsec/1000000, serial);
之后返回ab。
type=SYSCALL msg=audit(1208941951.177:520792):
1) 定义
static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, gfp_t gfp_mask, int type)
2) 说明
申请并填充audit_buffer。优先从audit_freelist上寻找有无空闲audit_buffer。没有的话ab = kmalloc(sizeof(*ab), gfp_mask);
之后:
ab->skb = alloc_skb(AUDIT_BUFSIZ, gfp_mask);
#define AUDIT_BUFSIZ 1024
填充的方法如下:
ab->ctx = ctx;
ab->gfp_mask = gfp_mask;
nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0));
nlh->nlmsg_type = type;
nlh->nlmsg_flags = 0;
nlh->nlmsg_pid = 0;
nlh->nlmsg_seq = 0;
1) 定义
void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args)
2) 说明
audit_log_format()调用audit_log_vformat()。
按照参数fmt,添加信息到skb->tail,并增加skb->tail。
1) 定义
void audit_log_end(struct audit_buffer *ab)
2) 说明
挂接到套接字缓冲区链表尾,或直接printk。
首先检查速率audit_rate_check,否则如果audit_pid存在,那么挂接skb_queue_tail(&audit_skb_queue, ab->skb);并唤醒等待队列kauditd_wait :wake_up_interruptible(&kauditd_wait);
否则的话查看printk_ratelimit(),没有问题就printk:printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));有问题的话,audit_log_lost()。
最后,无论如何,都要audit_buffer_free(ab);