Commit fd76a74d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull audit updates from Paul Moore:
 "Aside from some smaller bug fixes, here are the highlights:

   - add a new backlog wait metric to the audit status message, this is
     intended to help admins determine how long processes have been
     waiting for the audit backlog queue to clear

   - generate audit records for nftables configuration changes

   - generate CWD audit records for for the relevant LSM audit records"

* tag 'audit-pr-20200803' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
  audit: report audit wait metric in audit status reply
  audit: purge audit_log_string from the intra-kernel audit API
  audit: issue CWD record to accompany LSM_AUDIT_DATA_* records
  audit: use the proper gfp flags in the audit_log_nfcfg() calls
  audit: remove unused !CONFIG_AUDITSYSCALL __audit_inode* stubs
  audit: add gfp parameter to audit_log_nfcfg
  audit: log nftables configuration change events
  audit: Use struct_size() helper in alloc_chunk
parents 49e917de b43870c7
Loading
Loading
Loading
Loading
+29 −17
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <uapi/linux/audit.h>
#include <uapi/linux/netfilter/nf_tables.h>

#define AUDIT_INO_UNSET ((unsigned long)-1)
#define AUDIT_DEV_UNSET ((dev_t)-1)
@@ -98,6 +99,23 @@ enum audit_nfcfgop {
	AUDIT_XT_OP_REGISTER,
	AUDIT_XT_OP_REPLACE,
	AUDIT_XT_OP_UNREGISTER,
	AUDIT_NFT_OP_TABLE_REGISTER,
	AUDIT_NFT_OP_TABLE_UNREGISTER,
	AUDIT_NFT_OP_CHAIN_REGISTER,
	AUDIT_NFT_OP_CHAIN_UNREGISTER,
	AUDIT_NFT_OP_RULE_REGISTER,
	AUDIT_NFT_OP_RULE_UNREGISTER,
	AUDIT_NFT_OP_SET_REGISTER,
	AUDIT_NFT_OP_SET_UNREGISTER,
	AUDIT_NFT_OP_SETELEM_REGISTER,
	AUDIT_NFT_OP_SETELEM_UNREGISTER,
	AUDIT_NFT_OP_GEN_REGISTER,
	AUDIT_NFT_OP_OBJ_REGISTER,
	AUDIT_NFT_OP_OBJ_UNREGISTER,
	AUDIT_NFT_OP_OBJ_RESET,
	AUDIT_NFT_OP_FLOWTABLE_REGISTER,
	AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
	AUDIT_NFT_OP_INVALID,
};

extern int is_audit_feature_set(int which);
@@ -274,7 +292,7 @@ extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
extern void __audit_syscall_exit(int ret_success, long ret_value);
extern struct filename *__audit_reusename(const __user char *uptr);
extern void __audit_getname(struct filename *name);

extern void __audit_getcwd(void);
extern void __audit_inode(struct filename *name, const struct dentry *dentry,
				unsigned int flags);
extern void __audit_file(const struct file *);
@@ -333,6 +351,11 @@ static inline void audit_getname(struct filename *name)
	if (unlikely(!audit_dummy_context()))
		__audit_getname(name);
}
static inline void audit_getcwd(void)
{
	if (unlikely(audit_context()))
		__audit_getcwd();
}
static inline void audit_inode(struct filename *name,
				const struct dentry *dentry,
				unsigned int aflags) {
@@ -386,7 +409,7 @@ extern void __audit_fanotify(unsigned int response);
extern void __audit_tk_injoffset(struct timespec64 offset);
extern void __audit_ntp_log(const struct audit_ntp_data *ad);
extern void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
			      enum audit_nfcfgop op);
			      enum audit_nfcfgop op, gfp_t gfp);

static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
@@ -524,10 +547,10 @@ static inline void audit_ntp_log(const struct audit_ntp_data *ad)

static inline void audit_log_nfcfg(const char *name, u8 af,
				   unsigned int nentries,
				   enum audit_nfcfgop op)
				   enum audit_nfcfgop op, gfp_t gfp)
{
	if (audit_enabled)
		__audit_log_nfcfg(name, af, nentries, op);
		__audit_log_nfcfg(name, af, nentries, op, gfp);
}

extern int audit_n_rules;
@@ -561,13 +584,7 @@ static inline struct filename *audit_reusename(const __user char *name)
}
static inline void audit_getname(struct filename *name)
{ }
static inline void __audit_inode(struct filename *name,
					const struct dentry *dentry,
					unsigned int flags)
{ }
static inline void __audit_inode_child(struct inode *parent,
					const struct dentry *dentry,
					const unsigned char type)
static inline void audit_getcwd(void)
{ }
static inline void audit_inode(struct filename *name,
				const struct dentry *dentry,
@@ -665,7 +682,7 @@ static inline void audit_ptrace(struct task_struct *t)

static inline void audit_log_nfcfg(const char *name, u8 af,
				   unsigned int nentries,
				   enum audit_nfcfgop op)
				   enum audit_nfcfgop op, gfp_t gfp)
{ }

#define audit_n_rules 0
@@ -677,9 +694,4 @@ static inline bool audit_loginuid_set(struct task_struct *tsk)
	return uid_valid(audit_get_loginuid(tsk));
}

static inline void audit_log_string(struct audit_buffer *ab, const char *buf)
{
	audit_log_n_string(ab, buf, strlen(buf));
}

#endif
+11 −7
Original line number Diff line number Diff line
@@ -341,6 +341,7 @@ enum {
#define AUDIT_STATUS_BACKLOG_LIMIT		0x0010
#define AUDIT_STATUS_BACKLOG_WAIT_TIME		0x0020
#define AUDIT_STATUS_LOST			0x0040
#define AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL	0x0080

#define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT	0x00000001
#define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME	0x00000002
@@ -467,6 +468,9 @@ struct audit_status {
		__u32	feature_bitmap;	/* bitmap of kernel audit features */
	};
	__u32		backlog_wait_time;/* message queue wait timeout */
	__u32           backlog_wait_time_actual;/* time spent waiting while
						  * message limit exceeded
						  */
};

struct audit_features {
+27 −12
Original line number Diff line number Diff line
@@ -136,6 +136,11 @@ u32 audit_sig_sid = 0;
*/
static atomic_t	audit_lost = ATOMIC_INIT(0);

/* Monotonically increasing sum of time the kernel has spent
 * waiting while the backlog limit is exceeded.
 */
static atomic_t audit_backlog_wait_time_actual = ATOMIC_INIT(0);

/* Hash for inode-based rules */
struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];

@@ -1212,6 +1217,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
		s.backlog		   = skb_queue_len(&audit_queue);
		s.feature_bitmap	   = AUDIT_FEATURE_BITMAP_ALL;
		s.backlog_wait_time	   = audit_backlog_wait_time;
		s.backlog_wait_time_actual = atomic_read(&audit_backlog_wait_time_actual);
		audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
		break;
	}
@@ -1315,6 +1321,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
			audit_log_config_change("lost", 0, lost, 1);
			return lost;
		}
		if (s.mask == AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL) {
			u32 actual = atomic_xchg(&audit_backlog_wait_time_actual, 0);

			audit_log_config_change("backlog_wait_time_actual", 0, actual, 1);
			return actual;
		}
		break;
	}
	case AUDIT_GET_FEATURE:
@@ -1826,12 +1838,15 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
			/* sleep if we are allowed and we haven't exhausted our
			 * backlog wait limit */
			if (gfpflags_allow_blocking(gfp_mask) && (stime > 0)) {
				long rtime = stime;

				DECLARE_WAITQUEUE(wait, current);

				add_wait_queue_exclusive(&audit_backlog_wait,
							 &wait);
				set_current_state(TASK_UNINTERRUPTIBLE);
				stime = schedule_timeout(stime);
				stime = schedule_timeout(rtime);
				atomic_add(rtime - stime, &audit_backlog_wait_time_actual);
				remove_wait_queue(&audit_backlog_wait, &wait);
			} else {
				if (audit_rate_check() && printk_ratelimit())
@@ -2079,13 +2094,13 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
	/* We will allow 11 spaces for ' (deleted)' to be appended */
	pathname = kmalloc(PATH_MAX+11, ab->gfp_mask);
	if (!pathname) {
		audit_log_string(ab, "<no_memory>");
		audit_log_format(ab, "\"<no_memory>\"");
		return;
	}
	p = d_path(path, pathname, PATH_MAX+11);
	if (IS_ERR(p)) { /* Should never happen since we send PATH_MAX */
		/* FIXME: can we save some information here? */
		audit_log_string(ab, "<too_long>");
		audit_log_format(ab, "\"<too_long>\"");
	} else
		audit_log_untrustedstring(ab, p);
	kfree(pathname);
+1 −3
Original line number Diff line number Diff line
@@ -188,11 +188,9 @@ static struct fsnotify_mark *alloc_mark(void)
static struct audit_chunk *alloc_chunk(int count)
{
	struct audit_chunk *chunk;
	size_t size;
	int i;

	size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
	chunk = kzalloc(size, GFP_KERNEL);
	chunk = kzalloc(struct_size(chunk, owners, count), GFP_KERNEL);
	if (!chunk)
		return NULL;

+38 −7
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@
#include <linux/uaccess.h>
#include <linux/fsnotify_backend.h>
#include <uapi/linux/limits.h>
#include <uapi/linux/netfilter/nf_tables.h>

#include "audit.h"

@@ -136,9 +137,26 @@ struct audit_nfcfgop_tab {
};

static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
	{ AUDIT_XT_OP_REGISTER,		"register"	},
	{ AUDIT_XT_OP_REPLACE,		"replace"	},
	{ AUDIT_XT_OP_UNREGISTER,	"unregister"	},
	{ AUDIT_XT_OP_REGISTER,			"xt_register"		   },
	{ AUDIT_XT_OP_REPLACE,			"xt_replace"		   },
	{ AUDIT_XT_OP_UNREGISTER,		"xt_unregister"		   },
	{ AUDIT_NFT_OP_TABLE_REGISTER,		"nft_register_table"	   },
	{ AUDIT_NFT_OP_TABLE_UNREGISTER,	"nft_unregister_table"	   },
	{ AUDIT_NFT_OP_CHAIN_REGISTER,		"nft_register_chain"	   },
	{ AUDIT_NFT_OP_CHAIN_UNREGISTER,	"nft_unregister_chain"	   },
	{ AUDIT_NFT_OP_RULE_REGISTER,		"nft_register_rule"	   },
	{ AUDIT_NFT_OP_RULE_UNREGISTER,		"nft_unregister_rule"	   },
	{ AUDIT_NFT_OP_SET_REGISTER,		"nft_register_set"	   },
	{ AUDIT_NFT_OP_SET_UNREGISTER,		"nft_unregister_set"	   },
	{ AUDIT_NFT_OP_SETELEM_REGISTER,	"nft_register_setelem"	   },
	{ AUDIT_NFT_OP_SETELEM_UNREGISTER,	"nft_unregister_setelem"   },
	{ AUDIT_NFT_OP_GEN_REGISTER,		"nft_register_gen"	   },
	{ AUDIT_NFT_OP_OBJ_REGISTER,		"nft_register_obj"	   },
	{ AUDIT_NFT_OP_OBJ_UNREGISTER,		"nft_unregister_obj"	   },
	{ AUDIT_NFT_OP_OBJ_RESET,		"nft_reset_obj"		   },
	{ AUDIT_NFT_OP_FLOWTABLE_REGISTER,	"nft_register_flowtable"   },
	{ AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,	"nft_unregister_flowtable" },
	{ AUDIT_NFT_OP_INVALID,			"nft_invalid"		   },
};

static int audit_match_perm(struct audit_context *ctx, int mask)
@@ -1876,6 +1894,20 @@ __audit_reusename(const __user char *uptr)
	return NULL;
}

inline void _audit_getcwd(struct audit_context *context)
{
	if (!context->pwd.dentry)
		get_fs_pwd(current->fs, &context->pwd);
}

void __audit_getcwd(void)
{
	struct audit_context *context = audit_context();

	if (context->in_syscall)
		_audit_getcwd(context);
}

/**
 * __audit_getname - add a name to the list
 * @name: name to add
@@ -1900,8 +1932,7 @@ void __audit_getname(struct filename *name)
	name->aname = n;
	name->refcnt++;

	if (!context->pwd.dentry)
		get_fs_pwd(current->fs, &context->pwd);
	_audit_getcwd(context);
}

static inline int audit_copy_fcaps(struct audit_names *name,
@@ -2557,12 +2588,12 @@ void __audit_ntp_log(const struct audit_ntp_data *ad)
}

void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
		       enum audit_nfcfgop op)
		       enum audit_nfcfgop op, gfp_t gfp)
{
	struct audit_buffer *ab;
	char comm[sizeof(current->comm)];

	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_NETFILTER_CFG);
	ab = audit_log_start(audit_context(), gfp, AUDIT_NETFILTER_CFG);
	if (!ab)
		return;
	audit_log_format(ab, "table=%s family=%u entries=%u op=%s",
Loading