Skip to content
Snippets Groups Projects
audit.c 30.9 KiB
Newer Older
 * All the work is done in audit_log_vformat.
 */
Linus Torvalds's avatar
Linus Torvalds committed
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,
	int i, avail, new_len;
	unsigned char *ptr;
	struct sk_buff *skb;
	static const unsigned char *hex = "0123456789ABCDEF";

	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;
	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 */
/**
 * audit_log_unstrustedstring - log a string that may contain random characters
 * @ab: audit_buffer
 * @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).
 */
Al Viro's avatar
Al Viro committed
const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
	const unsigned char *p = string;
Al Viro's avatar
Al Viro committed
	size_t len = strlen(string);
		if (*p == '"' || *p < 0x21 || *p > 0x7f) {
Al Viro's avatar
Al Viro committed
			audit_log_hex(ab, string, len);
			return string + len + 1;
		}
		p++;
	}
	audit_log_format(ab, "\"%s\"", string);
Al Viro's avatar
Al Viro committed
	return p + 1;
/* This is a helper-function to print the escaped d_path */
Linus Torvalds's avatar
Linus Torvalds committed
void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
		      struct dentry *dentry, struct vfsmount *vfsmnt)
{
	char *p, *path;
Linus Torvalds's avatar
Linus Torvalds committed

	if (prefix)
		audit_log_format(ab, " %s", prefix);
Linus Torvalds's avatar
Linus Torvalds committed

	/* 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;
Linus Torvalds's avatar
Linus Torvalds committed
	}
	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
Linus Torvalds's avatar
Linus Torvalds committed
 * remove them from the queue outside the irq context.  May be called in
void audit_log_end(struct audit_buffer *ab)
Linus Torvalds's avatar
Linus Torvalds committed
{
	if (!ab)
		return;
	if (!audit_rate_check()) {
		audit_log_lost("rate limit exceeded");
	} else {
		if (audit_pid) {
			struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
			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));
Linus Torvalds's avatar
Linus Torvalds committed
	}
/**
 * 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.
 */
Al Viro's avatar
Al Viro committed
void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, 
Linus Torvalds's avatar
Linus Torvalds committed
{
	struct audit_buffer *ab;
	va_list args;

	ab = audit_log_start(ctx, gfp_mask, type);
Linus Torvalds's avatar
Linus Torvalds committed
	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);