⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audit.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (!ab) {		ab = kmalloc(sizeof(*ab), gfp_mask);		if (!ab)			goto err;	}	ab->skb = alloc_skb(AUDIT_BUFSIZ, gfp_mask);	if (!ab->skb)		goto err;	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;	return ab;err:	audit_buffer_free(ab);	return NULL;}/** * audit_serial - compute a serial number for the audit record * * Compute a serial number for the audit record.  Audit records are * written to user-space as soon as they are generated, so a complete * audit record may be written in several pieces.  The timestamp of the * record and this serial number are used by the user-space tools to * determine which pieces belong to the same audit record.  The * (timestamp,serial) tuple is unique for each syscall and is live from * syscall entry to syscall exit. * * NOTE: Another possibility is to store the formatted records off the * audit context (for those records that have a context), and emit them * all at syscall exit.  However, this could delay the reporting of * significant errors until syscall exit (or never, if the system * halts). */unsigned int audit_serial(void){	static DEFINE_SPINLOCK(serial_lock);	static unsigned int serial = 0;	unsigned long flags;	unsigned int ret;	spin_lock_irqsave(&serial_lock, flags);	do {		ret = ++serial;	} while (unlikely(!ret));	spin_unlock_irqrestore(&serial_lock, flags);	return ret;}static inline void audit_get_stamp(struct audit_context *ctx, 				   struct timespec *t, unsigned int *serial){	if (ctx)		auditsc_get_stamp(ctx, t, serial);	else {		*t = CURRENT_TIME;		*serial = audit_serial();	}}/* Obtain an audit buffer.  This routine does locking to obtain the * audit buffer, but then no locking is required for calls to * audit_log_*format.  If the tsk is a task that is currently in a * syscall, then the syscall is marked as auditable and an audit record * will be written at syscall exit.  If there is no associated task, tsk * should be NULL. *//** * audit_log_start - obtain an audit buffer * @ctx: audit_context (may be NULL) * @gfp_mask: type of allocation * @type: audit message type * * Returns audit_buffer pointer on success or NULL on error. * * Obtain an audit buffer.  This routine does locking to obtain the * audit buffer, but then no locking is required for calls to * audit_log_*format.  If the task (ctx) is a task that is currently in a * syscall, then the syscall is marked as auditable and an audit record * will be written at syscall exit.  If there is no associated task, then * task context (ctx) should be NULL. */struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,				     int type){	struct audit_buffer	*ab	= NULL;	struct timespec		t;	unsigned int		serial;	int reserve;	unsigned long timeout_start = jiffies;	if (!audit_initialized)		return NULL;	if (unlikely(audit_filter_type(type)))		return NULL;	if (gfp_mask & __GFP_WAIT)		reserve = 0;	else		reserve = 5; /* Allow atomic callers to go up to five 				entries over the normal backlog limit */	while (audit_backlog_limit	       && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) {		if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time		    && time_before(jiffies, timeout_start + audit_backlog_wait_time)) {			/* Wait for auditd to drain the queue a little */			DECLARE_WAITQUEUE(wait, current);			set_current_state(TASK_INTERRUPTIBLE);			add_wait_queue(&audit_backlog_wait, &wait);			if (audit_backlog_limit &&			    skb_queue_len(&audit_skb_queue) > audit_backlog_limit)				schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies);			__set_current_state(TASK_RUNNING);			remove_wait_queue(&audit_backlog_wait, &wait);			continue;		}		if (audit_rate_check())			printk(KERN_WARNING			       "audit: audit_backlog=%d > "			       "audit_backlog_limit=%d\n",			       skb_queue_len(&audit_skb_queue),			       audit_backlog_limit);		audit_log_lost("backlog limit exceeded");		audit_backlog_wait_time = audit_backlog_wait_overflow;		wake_up(&audit_backlog_wait);		return NULL;	}	ab = audit_buffer_alloc(ctx, gfp_mask, type);	if (!ab) {		audit_log_lost("out of memory in audit_log_start");		return NULL;	}	audit_get_stamp(ab->ctx, &t, &serial);	audit_log_format(ab, "audit(%lu.%03lu:%u): ",			 t.tv_sec, t.tv_nsec/1000000, serial);	return ab;}/** * audit_expand - expand skb in the audit buffer * @ab: audit_buffer * @extra: space to add at tail of the skb * * Returns 0 (no space) on failed expansion, or available space if * successful. */static inline int audit_expand(struct audit_buffer *ab, int extra){	struct sk_buff *skb = ab->skb;	int ret = pskb_expand_head(skb, skb_headroom(skb), extra,				   ab->gfp_mask);	if (ret < 0) {		audit_log_lost("out of memory in audit_expand");		return 0;	}	return skb_tailroom(skb);}/* * Format an audit message into the audit buffer.  If there isn't enough * room in the audit buffer, more room will be allocated and vsnprint * will be called a second time.  Currently, we assume that a printk * can't format message larger than 1024 bytes, so we don't either. */static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,			      va_list args){	int len, avail;	struct sk_buff *skb;	va_list args2;	if (!ab)		return;	BUG_ON(!ab->skb);	skb = ab->skb;	avail = skb_tailroom(skb);	if (avail == 0) {		avail = audit_expand(ab, AUDIT_BUFSIZ);		if (!avail)			goto out;	}	va_copy(args2, args);	len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args);	if (len >= avail) {		/* The printk buffer is 1024 bytes long, so if we get		 * here and AUDIT_BUFSIZ is at least 1024, then we can		 * log everything that printk could have logged. */		avail = audit_expand(ab,			max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));		if (!avail)			goto out;		len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);	}	if (len > 0)		skb_put(skb, len);out:	return;}/** * audit_log_format - format a message into the audit buffer. * @ab: audit_buffer * @fmt: format string * @...: optional parameters matching @fmt string * * All the work is done in audit_log_vformat. */void audit_log_format(struct audit_buffer *ab, const char *fmt, ...){	va_list args;	if (!ab)		return;	va_start(args, fmt);	audit_log_vformat(ab, fmt, args);	va_end(args);}/** * audit_log_hex - convert a buffer to hex and append it to the audit skb * @ab: the audit_buffer * @buf: buffer to convert to hex * @len: length of @buf to be converted * * No return value; failure to expand is silently ignored. * * This function will take the passed buf and convert it into a string of * ascii hex digits. The new string is placed onto the skb. */void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,		size_t len){	int i, avail, new_len;	unsigned char *ptr;	struct sk_buff *skb;	static const unsigned char *hex = "0123456789ABCDEF";	if (!ab)		return;	BUG_ON(!ab->skb);	skb = ab->skb;	avail = skb_tailroom(skb);	new_len = len<<1;	if (new_len >= avail) {		/* Round the buffer request up to the next multiple */		new_len = AUDIT_BUFSIZ*(((new_len-avail)/AUDIT_BUFSIZ) + 1);		avail = audit_expand(ab, new_len);		if (!avail)			return;	}	ptr = skb_tail_pointer(skb);	for (i=0; i<len; i++) {		*ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */		*ptr++ = hex[buf[i] & 0x0F];	  /* Lower nibble */	}	*ptr = 0;	skb_put(skb, len << 1); /* new string is twice the old string */}/* * Format a string of no more than slen characters into the audit buffer, * enclosed in quote marks. */static void audit_log_n_string(struct audit_buffer *ab, size_t slen,			       const char *string){	int avail, new_len;	unsigned char *ptr;	struct sk_buff *skb;	if (!ab)		return;	BUG_ON(!ab->skb);	skb = ab->skb;	avail = skb_tailroom(skb);	new_len = slen + 3;	/* enclosing quotes + null terminator */	if (new_len > avail) {		avail = audit_expand(ab, new_len);		if (!avail)			return;	}	ptr = skb_tail_pointer(skb);	*ptr++ = '"';	memcpy(ptr, string, slen);	ptr += slen;	*ptr++ = '"';	*ptr = 0;	skb_put(skb, slen + 2);	/* don't include null terminator */}/** * audit_log_n_unstrustedstring - log a string that may contain random characters * @ab: audit_buffer * @len: lenth of string (not including trailing null) * @string: string to be logged * * This code will escape a string that is passed to it if the string * contains a control character, unprintable character, double quote mark, * or a space. Unescaped strings will start and end with a double quote mark. * Strings that are escaped are printed in hex (2 digits per char). * * The caller specifies the number of characters in the string to log, which may * or may not be the entire string. */const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,					const char *string){	const unsigned char *p = string;	while (*p) {		if (*p == '"' || *p < 0x21 || *p > 0x7f) {			audit_log_hex(ab, string, len);			return string + len + 1;		}		p++;	}	audit_log_n_string(ab, len, string);	return p + 1;}/** * audit_log_unstrustedstring - log a string that may contain random characters * @ab: audit_buffer * @string: string to be logged * * Same as audit_log_n_unstrustedstring(), except that strlen is used to * determine string length. */const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string){	return audit_log_n_untrustedstring(ab, strlen(string), string);}/* This is a helper-function to print the escaped d_path */void audit_log_d_path(struct audit_buffer *ab, const char *prefix,		      struct dentry *dentry, struct vfsmount *vfsmnt){	char *p, *path;	if (prefix)		audit_log_format(ab, " %s", prefix);	/* We will allow 11 spaces for ' (deleted)' to be appended */	path = kmalloc(PATH_MAX+11, ab->gfp_mask);	if (!path) {		audit_log_format(ab, "<no memory>");		return;	}	p = d_path(dentry, vfsmnt, path, PATH_MAX+11);	if (IS_ERR(p)) { /* Should never happen since we send PATH_MAX */		/* FIXME: can we save some information here? */		audit_log_format(ab, "<too long>");	} else 		audit_log_untrustedstring(ab, p);	kfree(path);}/** * audit_log_end - end one audit record * @ab: the audit_buffer * * The netlink_* functions cannot be called inside an irq context, so * the audit buffer is placed on a queue and a tasklet is scheduled to * remove them from the queue outside the irq context.  May be called in * any context. */void audit_log_end(struct audit_buffer *ab){	if (!ab)		return;	if (!audit_rate_check()) {		audit_log_lost("rate limit exceeded");	} else {		if (audit_pid) {			struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);			nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);			skb_queue_tail(&audit_skb_queue, ab->skb);			ab->skb = NULL;			wake_up_interruptible(&kauditd_wait);		} else {			printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));		}	}	audit_buffer_free(ab);}/** * audit_log - Log an audit record * @ctx: audit context * @gfp_mask: type of allocation * @type: audit message type * @fmt: format string to use * @...: variable parameters matching the format string * * This is a convenience function that calls audit_log_start, * audit_log_vformat, and audit_log_end.  It may be called * in any context. */void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, 	       const char *fmt, ...){	struct audit_buffer *ab;	va_list args;	ab = audit_log_start(ctx, gfp_mask, type);	if (ab) {		va_start(args, fmt);		audit_log_vformat(ab, fmt, args);		va_end(args);		audit_log_end(ab);	}}EXPORT_SYMBOL(audit_log_start);EXPORT_SYMBOL(audit_log_end);EXPORT_SYMBOL(audit_log_format);EXPORT_SYMBOL(audit_log);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -