xref: /openbmc/linux/kernel/audit.c (revision 533c7b69c764ad5febb3e716899f43a75564fcab)
185c8721fS /* audit.c -- Auditing support
21da177e4SLinus Torvalds  * Gateway between the kernel (e.g., selinux) and the user-space audit daemon.
31da177e4SLinus Torvalds  * System-call specific features have moved to auditsc.c
41da177e4SLinus Torvalds  *
56a01b07fSSteve Grubb  * Copyright 2003-2007 Red Hat Inc., Durham, North Carolina.
61da177e4SLinus Torvalds  * All Rights Reserved.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
91da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
101da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or
111da177e4SLinus Torvalds  * (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
141da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
151da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161da177e4SLinus Torvalds  * GNU General Public License for more details.
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
191da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
201da177e4SLinus Torvalds  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * Written by Rickard E. (Rik) Faith <faith@redhat.com>
231da177e4SLinus Torvalds  *
24d7a96f3aSAhmed S. Darwish  * Goals: 1) Integrate fully with Security Modules.
251da177e4SLinus Torvalds  *	  2) Minimal run-time overhead:
261da177e4SLinus Torvalds  *	     a) Minimal when syscall auditing is disabled (audit_enable=0).
271da177e4SLinus Torvalds  *	     b) Small when syscall auditing is enabled and no audit record
281da177e4SLinus Torvalds  *		is generated (defer as much work as possible to record
291da177e4SLinus Torvalds  *		generation time):
301da177e4SLinus Torvalds  *		i) context is allocated,
311da177e4SLinus Torvalds  *		ii) names from getname are stored without a copy, and
321da177e4SLinus Torvalds  *		iii) inode information stored from path_lookup.
331da177e4SLinus Torvalds  *	  3) Ability to disable syscall auditing at boot time (audit=0).
341da177e4SLinus Torvalds  *	  4) Usable by other parts of the kernel (if audit_log* is called,
351da177e4SLinus Torvalds  *	     then a syscall record will be generated automatically for the
361da177e4SLinus Torvalds  *	     current syscall).
371da177e4SLinus Torvalds  *	  5) Netlink interface to user-space.
381da177e4SLinus Torvalds  *	  6) Support low-overhead kernel-based filtering to minimize the
391da177e4SLinus Torvalds  *	     information that must be passed to user-space.
401da177e4SLinus Torvalds  *
4185c8721fS  * Example user-space utilities: http://people.redhat.com/sgrubb/audit/
421da177e4SLinus Torvalds  */
431da177e4SLinus Torvalds 
44d957f7b7SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
45d957f7b7SJoe Perches 
465b282552SDavidlohr Bueso #include <linux/file.h>
471da177e4SLinus Torvalds #include <linux/init.h>
487153e402SPaul McQuade #include <linux/types.h>
4960063497SArun Sharma #include <linux/atomic.h>
501da177e4SLinus Torvalds #include <linux/mm.h>
519984de1aSPaul Gortmaker #include <linux/export.h>
525a0e3ad6STejun Heo #include <linux/slab.h>
53b7d11258SDavid Woodhouse #include <linux/err.h>
54b7d11258SDavid Woodhouse #include <linux/kthread.h>
5546e959eaSRichard Guy Briggs #include <linux/kernel.h>
56b24a30a7SEric Paris #include <linux/syscalls.h>
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds #include <linux/audit.h>
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds #include <net/sock.h>
6193315ed6SAmy Griffis #include <net/netlink.h>
621da177e4SLinus Torvalds #include <linux/skbuff.h>
63131ad62dSMr Dash Four #ifdef CONFIG_SECURITY
64131ad62dSMr Dash Four #include <linux/security.h>
65131ad62dSMr Dash Four #endif
667dfb7103SNigel Cunningham #include <linux/freezer.h>
6734e36d8eSEric W. Biederman #include <linux/pid_namespace.h>
6833faba7fSRichard Guy Briggs #include <net/netns/generic.h>
693dc7e315SDarrel Goeddel 
703dc7e315SDarrel Goeddel #include "audit.h"
711da177e4SLinus Torvalds 
72a3f07114SEric Paris /* No auditing will take place until audit_initialized == AUDIT_INITIALIZED.
731da177e4SLinus Torvalds  * (Initialization happens after skb_init is called.) */
74a3f07114SEric Paris #define AUDIT_DISABLED		-1
75a3f07114SEric Paris #define AUDIT_UNINITIALIZED	0
76a3f07114SEric Paris #define AUDIT_INITIALIZED	1
771da177e4SLinus Torvalds static int	audit_initialized;
781da177e4SLinus Torvalds 
791a6b9f23SEric Paris #define AUDIT_OFF	0
801a6b9f23SEric Paris #define AUDIT_ON	1
811a6b9f23SEric Paris #define AUDIT_LOCKED	2
823e1d0bb6SJoe Perches u32		audit_enabled;
833e1d0bb6SJoe Perches u32		audit_ever_enabled;
841da177e4SLinus Torvalds 
85ae9d67afSJan Engelhardt EXPORT_SYMBOL_GPL(audit_enabled);
86ae9d67afSJan Engelhardt 
871da177e4SLinus Torvalds /* Default state when kernel boots without any parameters. */
883e1d0bb6SJoe Perches static u32	audit_default;
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds /* If auditing cannot proceed, audit_failure selects what happens. */
913e1d0bb6SJoe Perches static u32	audit_failure = AUDIT_FAIL_PRINTK;
921da177e4SLinus Torvalds 
9375c0371aSPavel Emelyanov /*
9475c0371aSPavel Emelyanov  * If audit records are to be written to the netlink socket, audit_pid
9515e47304SEric W. Biederman  * contains the pid of the auditd process and audit_nlk_portid contains
9615e47304SEric W. Biederman  * the portid to use to send netlink messages to that process.
9775c0371aSPavel Emelyanov  */
98c2f0c7c3SSteve Grubb int		audit_pid;
99f9441639SRichard Guy Briggs static __u32	audit_nlk_portid;
1001da177e4SLinus Torvalds 
101b0dd25a8SRandy Dunlap /* If audit_rate_limit is non-zero, limit the rate of sending audit records
1021da177e4SLinus Torvalds  * to that number per second.  This prevents DoS attacks, but results in
1031da177e4SLinus Torvalds  * audit records being dropped. */
1043e1d0bb6SJoe Perches static u32	audit_rate_limit;
1051da177e4SLinus Torvalds 
10640c0775eSRichard Guy Briggs /* Number of outstanding audit_buffers allowed.
10740c0775eSRichard Guy Briggs  * When set to zero, this means unlimited. */
1083e1d0bb6SJoe Perches static u32	audit_backlog_limit = 64;
109e789e561SRichard Guy Briggs #define AUDIT_BACKLOG_WAIT_TIME (60 * HZ)
1103e1d0bb6SJoe Perches static u32	audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
1111da177e4SLinus Torvalds 
112c2f0c7c3SSteve Grubb /* The identity of the user shutting down the audit system. */
113cca080d9SEric W. Biederman kuid_t		audit_sig_uid = INVALID_UID;
114c2f0c7c3SSteve Grubb pid_t		audit_sig_pid = -1;
115e1396065SAl Viro u32		audit_sig_sid = 0;
116c2f0c7c3SSteve Grubb 
1171da177e4SLinus Torvalds /* Records can be lost in several ways:
1181da177e4SLinus Torvalds    0) [suppressed in audit_alloc]
1191da177e4SLinus Torvalds    1) out of memory in audit_log_start [kmalloc of struct audit_buffer]
1201da177e4SLinus Torvalds    2) out of memory in audit_log_move [alloc_skb]
1211da177e4SLinus Torvalds    3) suppressed due to audit_rate_limit
1221da177e4SLinus Torvalds    4) suppressed due to audit_backlog_limit
1231da177e4SLinus Torvalds */
1241da177e4SLinus Torvalds static atomic_t    audit_lost = ATOMIC_INIT(0);
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds /* The netlink socket. */
1271da177e4SLinus Torvalds static struct sock *audit_sock;
128c0a8d9b0SRichard Guy Briggs static int audit_net_id;
1291da177e4SLinus Torvalds 
130f368c07dSAmy Griffis /* Hash for inode-based rules */
131f368c07dSAmy Griffis struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
132f368c07dSAmy Griffis 
133b7d11258SDavid Woodhouse /* The audit_freelist is a list of pre-allocated audit buffers (if more
1341da177e4SLinus Torvalds  * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of
1351da177e4SLinus Torvalds  * being placed on the freelist). */
1361da177e4SLinus Torvalds static DEFINE_SPINLOCK(audit_freelist_lock);
137b0dd25a8SRandy Dunlap static int	   audit_freelist_count;
1381da177e4SLinus Torvalds static LIST_HEAD(audit_freelist);
1391da177e4SLinus Torvalds 
140c6480207SPaul Moore /* queue msgs to send via kauditd_task */
141af8b824fSPaul Moore static struct sk_buff_head audit_queue;
142c6480207SPaul Moore /* queue msgs due to temporary unicast send problems */
143c6480207SPaul Moore static struct sk_buff_head audit_retry_queue;
144c6480207SPaul Moore /* queue msgs waiting for new auditd connection */
145af8b824fSPaul Moore static struct sk_buff_head audit_hold_queue;
146c6480207SPaul Moore 
147c6480207SPaul Moore /* queue servicing thread */
148b7d11258SDavid Woodhouse static struct task_struct *kauditd_task;
149b7d11258SDavid Woodhouse static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
150c6480207SPaul Moore 
151c6480207SPaul Moore /* waitqueue for callers who are blocked on the audit backlog */
1529ad9ad38SDavid Woodhouse static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
1531da177e4SLinus Torvalds 
154b0fed402SEric Paris static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION,
155b0fed402SEric Paris 				   .mask = -1,
156b0fed402SEric Paris 				   .features = 0,
157b0fed402SEric Paris 				   .lock = 0,};
158b0fed402SEric Paris 
15921b85c31SEric Paris static char *audit_feature_names[2] = {
160d040e5afSEric Paris 	"only_unset_loginuid",
16121b85c31SEric Paris 	"loginuid_immutable",
162b0fed402SEric Paris };
163b0fed402SEric Paris 
164b0fed402SEric Paris 
165f368c07dSAmy Griffis /* Serialize requests from userspace. */
166916d7576SAl Viro DEFINE_MUTEX(audit_cmd_mutex);
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting
1691da177e4SLinus Torvalds  * audit records.  Since printk uses a 1024 byte buffer, this buffer
1701da177e4SLinus Torvalds  * should be at least that large. */
1711da177e4SLinus Torvalds #define AUDIT_BUFSIZ 1024
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds /* AUDIT_MAXFREE is the number of empty audit_buffers we keep on the
1741da177e4SLinus Torvalds  * audit_freelist.  Doing so eliminates many kmalloc/kfree calls. */
1751da177e4SLinus Torvalds #define AUDIT_MAXFREE  (2*NR_CPUS)
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds /* The audit_buffer is used when formatting an audit record.  The caller
1781da177e4SLinus Torvalds  * locks briefly to get the record off the freelist or to allocate the
1791da177e4SLinus Torvalds  * buffer, and locks briefly to send the buffer to the netlink layer or
1801da177e4SLinus Torvalds  * to place it on a transmit queue.  Multiple audit_buffers can be in
1811da177e4SLinus Torvalds  * use simultaneously. */
1821da177e4SLinus Torvalds struct audit_buffer {
1831da177e4SLinus Torvalds 	struct list_head     list;
1848fc6115cSChris Wright 	struct sk_buff       *skb;	/* formatted skb ready to send */
1851da177e4SLinus Torvalds 	struct audit_context *ctx;	/* NULL or associated context */
1869796fdd8SAl Viro 	gfp_t		     gfp_mask;
1871da177e4SLinus Torvalds };
1881da177e4SLinus Torvalds 
189f09ac9dbSEric Paris struct audit_reply {
190f9441639SRichard Guy Briggs 	__u32 portid;
19148095d99SEric W. Biederman 	struct net *net;
192f09ac9dbSEric Paris 	struct sk_buff *skb;
193f09ac9dbSEric Paris };
194f09ac9dbSEric Paris 
195f9441639SRichard Guy Briggs static void audit_set_portid(struct audit_buffer *ab, __u32 portid)
196c0404993SSteve Grubb {
19750397bd1SEric Paris 	if (ab) {
198b529ccf2SArnaldo Carvalho de Melo 		struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
199f9441639SRichard Guy Briggs 		nlh->nlmsg_pid = portid;
200c0404993SSteve Grubb 	}
20150397bd1SEric Paris }
202c0404993SSteve Grubb 
2038c8570fbSDustin Kirkland void audit_panic(const char *message)
2041da177e4SLinus Torvalds {
205d957f7b7SJoe Perches 	switch (audit_failure) {
2061da177e4SLinus Torvalds 	case AUDIT_FAIL_SILENT:
2071da177e4SLinus Torvalds 		break;
2081da177e4SLinus Torvalds 	case AUDIT_FAIL_PRINTK:
209320f1b1eSEric Paris 		if (printk_ratelimit())
210d957f7b7SJoe Perches 			pr_err("%s\n", message);
2111da177e4SLinus Torvalds 		break;
2121da177e4SLinus Torvalds 	case AUDIT_FAIL_PANIC:
213b29ee87eSEric Paris 		/* test audit_pid since printk is always losey, why bother? */
214b29ee87eSEric Paris 		if (audit_pid)
2151da177e4SLinus Torvalds 			panic("audit: %s\n", message);
2161da177e4SLinus Torvalds 		break;
2171da177e4SLinus Torvalds 	}
2181da177e4SLinus Torvalds }
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds static inline int audit_rate_check(void)
2211da177e4SLinus Torvalds {
2221da177e4SLinus Torvalds 	static unsigned long	last_check = 0;
2231da177e4SLinus Torvalds 	static int		messages   = 0;
2241da177e4SLinus Torvalds 	static DEFINE_SPINLOCK(lock);
2251da177e4SLinus Torvalds 	unsigned long		flags;
2261da177e4SLinus Torvalds 	unsigned long		now;
2271da177e4SLinus Torvalds 	unsigned long		elapsed;
2281da177e4SLinus Torvalds 	int			retval	   = 0;
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	if (!audit_rate_limit) return 1;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	spin_lock_irqsave(&lock, flags);
2331da177e4SLinus Torvalds 	if (++messages < audit_rate_limit) {
2341da177e4SLinus Torvalds 		retval = 1;
2351da177e4SLinus Torvalds 	} else {
2361da177e4SLinus Torvalds 		now     = jiffies;
2371da177e4SLinus Torvalds 		elapsed = now - last_check;
2381da177e4SLinus Torvalds 		if (elapsed > HZ) {
2391da177e4SLinus Torvalds 			last_check = now;
2401da177e4SLinus Torvalds 			messages   = 0;
2411da177e4SLinus Torvalds 			retval     = 1;
2421da177e4SLinus Torvalds 		}
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds 	spin_unlock_irqrestore(&lock, flags);
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 	return retval;
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
249b0dd25a8SRandy Dunlap /**
250b0dd25a8SRandy Dunlap  * audit_log_lost - conditionally log lost audit message event
251b0dd25a8SRandy Dunlap  * @message: the message stating reason for lost audit message
252b0dd25a8SRandy Dunlap  *
253b0dd25a8SRandy Dunlap  * Emit at least 1 message per second, even if audit_rate_check is
254b0dd25a8SRandy Dunlap  * throttling.
255b0dd25a8SRandy Dunlap  * Always increment the lost messages counter.
256b0dd25a8SRandy Dunlap */
2571da177e4SLinus Torvalds void audit_log_lost(const char *message)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds 	static unsigned long	last_msg = 0;
2601da177e4SLinus Torvalds 	static DEFINE_SPINLOCK(lock);
2611da177e4SLinus Torvalds 	unsigned long		flags;
2621da177e4SLinus Torvalds 	unsigned long		now;
2631da177e4SLinus Torvalds 	int			print;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	atomic_inc(&audit_lost);
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	print = (audit_failure == AUDIT_FAIL_PANIC || !audit_rate_limit);
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	if (!print) {
2701da177e4SLinus Torvalds 		spin_lock_irqsave(&lock, flags);
2711da177e4SLinus Torvalds 		now = jiffies;
2721da177e4SLinus Torvalds 		if (now - last_msg > HZ) {
2731da177e4SLinus Torvalds 			print = 1;
2741da177e4SLinus Torvalds 			last_msg = now;
2751da177e4SLinus Torvalds 		}
2761da177e4SLinus Torvalds 		spin_unlock_irqrestore(&lock, flags);
2771da177e4SLinus Torvalds 	}
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	if (print) {
280320f1b1eSEric Paris 		if (printk_ratelimit())
2813e1d0bb6SJoe Perches 			pr_warn("audit_lost=%u audit_rate_limit=%u audit_backlog_limit=%u\n",
2821da177e4SLinus Torvalds 				atomic_read(&audit_lost),
2831da177e4SLinus Torvalds 				audit_rate_limit,
2841da177e4SLinus Torvalds 				audit_backlog_limit);
2851da177e4SLinus Torvalds 		audit_panic(message);
2861da177e4SLinus Torvalds 	}
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds 
2893e1d0bb6SJoe Perches static int audit_log_config_change(char *function_name, u32 new, u32 old,
2902532386fSEric Paris 				   int allow_changes)
2911da177e4SLinus Torvalds {
2921a6b9f23SEric Paris 	struct audit_buffer *ab;
2931a6b9f23SEric Paris 	int rc = 0;
2946a01b07fSSteve Grubb 
2951a6b9f23SEric Paris 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
2960644ec0cSKees Cook 	if (unlikely(!ab))
2970644ec0cSKees Cook 		return rc;
2983e1d0bb6SJoe Perches 	audit_log_format(ab, "%s=%u old=%u", function_name, new, old);
2994d3fb709SEric Paris 	audit_log_session_info(ab);
300b122c376SEric Paris 	rc = audit_log_task_context(ab);
301b122c376SEric Paris 	if (rc)
3021a6b9f23SEric Paris 		allow_changes = 0; /* Something weird, deny request */
3031a6b9f23SEric Paris 	audit_log_format(ab, " res=%d", allow_changes);
3041a6b9f23SEric Paris 	audit_log_end(ab);
3051a6b9f23SEric Paris 	return rc;
3061a6b9f23SEric Paris }
3071a6b9f23SEric Paris 
3083e1d0bb6SJoe Perches static int audit_do_config_change(char *function_name, u32 *to_change, u32 new)
3091a6b9f23SEric Paris {
3103e1d0bb6SJoe Perches 	int allow_changes, rc = 0;
3113e1d0bb6SJoe Perches 	u32 old = *to_change;
3121a6b9f23SEric Paris 
3131a6b9f23SEric Paris 	/* check if we are locked */
3141a6b9f23SEric Paris 	if (audit_enabled == AUDIT_LOCKED)
3151a6b9f23SEric Paris 		allow_changes = 0;
3161a6b9f23SEric Paris 	else
3171a6b9f23SEric Paris 		allow_changes = 1;
3181a6b9f23SEric Paris 
3191a6b9f23SEric Paris 	if (audit_enabled != AUDIT_OFF) {
320dc9eb698SEric Paris 		rc = audit_log_config_change(function_name, new, old, allow_changes);
3211a6b9f23SEric Paris 		if (rc)
3221a6b9f23SEric Paris 			allow_changes = 0;
3231a6b9f23SEric Paris 	}
3246a01b07fSSteve Grubb 
3256a01b07fSSteve Grubb 	/* If we are allowed, make the change */
3261a6b9f23SEric Paris 	if (allow_changes == 1)
3271a6b9f23SEric Paris 		*to_change = new;
3286a01b07fSSteve Grubb 	/* Not allowed, update reason */
3296a01b07fSSteve Grubb 	else if (rc == 0)
3306a01b07fSSteve Grubb 		rc = -EPERM;
3316a01b07fSSteve Grubb 	return rc;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds 
3343e1d0bb6SJoe Perches static int audit_set_rate_limit(u32 limit)
3351a6b9f23SEric Paris {
336dc9eb698SEric Paris 	return audit_do_config_change("audit_rate_limit", &audit_rate_limit, limit);
3371a6b9f23SEric Paris }
3381a6b9f23SEric Paris 
3393e1d0bb6SJoe Perches static int audit_set_backlog_limit(u32 limit)
3401da177e4SLinus Torvalds {
341dc9eb698SEric Paris 	return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit, limit);
3421da177e4SLinus Torvalds }
3431da177e4SLinus Torvalds 
3443e1d0bb6SJoe Perches static int audit_set_backlog_wait_time(u32 timeout)
34551cc83f0SRichard Guy Briggs {
34651cc83f0SRichard Guy Briggs 	return audit_do_config_change("audit_backlog_wait_time",
34731975424SPaul Moore 				      &audit_backlog_wait_time, timeout);
34851cc83f0SRichard Guy Briggs }
34951cc83f0SRichard Guy Briggs 
3503e1d0bb6SJoe Perches static int audit_set_enabled(u32 state)
3511da177e4SLinus Torvalds {
352b593d384SEric Paris 	int rc;
353724e7bfcSPranith Kumar 	if (state > AUDIT_LOCKED)
3541da177e4SLinus Torvalds 		return -EINVAL;
355ce29b682SSteve Grubb 
356dc9eb698SEric Paris 	rc =  audit_do_config_change("audit_enabled", &audit_enabled, state);
357b593d384SEric Paris 	if (!rc)
358b593d384SEric Paris 		audit_ever_enabled |= !!state;
359b593d384SEric Paris 
360b593d384SEric Paris 	return rc;
3611da177e4SLinus Torvalds }
3621da177e4SLinus Torvalds 
3633e1d0bb6SJoe Perches static int audit_set_failure(u32 state)
3641da177e4SLinus Torvalds {
3651da177e4SLinus Torvalds 	if (state != AUDIT_FAIL_SILENT
3661da177e4SLinus Torvalds 	    && state != AUDIT_FAIL_PRINTK
3671da177e4SLinus Torvalds 	    && state != AUDIT_FAIL_PANIC)
3681da177e4SLinus Torvalds 		return -EINVAL;
369ce29b682SSteve Grubb 
370dc9eb698SEric Paris 	return audit_do_config_change("audit_failure", &audit_failure, state);
3711da177e4SLinus Torvalds }
3721da177e4SLinus Torvalds 
373f3d357b0SEric Paris /*
374038cbcf6SEric Paris  * For one reason or another this nlh isn't getting delivered to the userspace
375038cbcf6SEric Paris  * audit daemon, just send it to printk.
376038cbcf6SEric Paris  */
377af8b824fSPaul Moore static void kauditd_printk_skb(struct sk_buff *skb)
378038cbcf6SEric Paris {
379038cbcf6SEric Paris 	struct nlmsghdr *nlh = nlmsg_hdr(skb);
380c64e66c6SDavid S. Miller 	char *data = nlmsg_data(nlh);
381038cbcf6SEric Paris 
382038cbcf6SEric Paris 	if (nlh->nlmsg_type != AUDIT_EOE) {
383038cbcf6SEric Paris 		if (printk_ratelimit())
384d957f7b7SJoe Perches 			pr_notice("type=%d %s\n", nlh->nlmsg_type, data);
385038cbcf6SEric Paris 		else
386f1283527SJosh Boyer 			audit_log_lost("printk limit exceeded");
387038cbcf6SEric Paris 	}
388038cbcf6SEric Paris }
389038cbcf6SEric Paris 
390c6480207SPaul Moore /**
391c6480207SPaul Moore  * kauditd_hold_skb - Queue an audit record, waiting for auditd
392c6480207SPaul Moore  * @skb: audit record
393c6480207SPaul Moore  *
394c6480207SPaul Moore  * Description:
395c6480207SPaul Moore  * Queue the audit record, waiting for an instance of auditd.  When this
396c6480207SPaul Moore  * function is called we haven't given up yet on sending the record, but things
397c6480207SPaul Moore  * are not looking good.  The first thing we want to do is try to write the
398c6480207SPaul Moore  * record via printk and then see if we want to try and hold on to the record
399c6480207SPaul Moore  * and queue it, if we have room.  If we want to hold on to the record, but we
400c6480207SPaul Moore  * don't have room, record a record lost message.
401c6480207SPaul Moore  */
402c6480207SPaul Moore static void kauditd_hold_skb(struct sk_buff *skb)
403f3d357b0SEric Paris {
404c6480207SPaul Moore 	/* at this point it is uncertain if we will ever send this to auditd so
405c6480207SPaul Moore 	 * try to send the message via printk before we go any further */
406c6480207SPaul Moore 	kauditd_printk_skb(skb);
40732a1dbaeSRichard Guy Briggs 
408c6480207SPaul Moore 	/* can we just silently drop the message? */
409c6480207SPaul Moore 	if (!audit_default) {
410c6480207SPaul Moore 		kfree_skb(skb);
411c6480207SPaul Moore 		return;
412c6480207SPaul Moore 	}
41332a1dbaeSRichard Guy Briggs 
414c6480207SPaul Moore 	/* if we have room, queue the message */
415c6480207SPaul Moore 	if (!audit_backlog_limit ||
416c6480207SPaul Moore 	    skb_queue_len(&audit_hold_queue) < audit_backlog_limit) {
417c6480207SPaul Moore 		skb_queue_tail(&audit_hold_queue, skb);
418c6480207SPaul Moore 		return;
419c6480207SPaul Moore 	}
420c6480207SPaul Moore 
421c6480207SPaul Moore 	/* we have no other options - drop the message */
422c6480207SPaul Moore 	audit_log_lost("kauditd hold queue overflow");
423c6480207SPaul Moore 	kfree_skb(skb);
424c6480207SPaul Moore }
425c6480207SPaul Moore 
426c6480207SPaul Moore /**
427c6480207SPaul Moore  * kauditd_retry_skb - Queue an audit record, attempt to send again to auditd
428c6480207SPaul Moore  * @skb: audit record
429c6480207SPaul Moore  *
430c6480207SPaul Moore  * Description:
431c6480207SPaul Moore  * Not as serious as kauditd_hold_skb() as we still have a connected auditd,
432c6480207SPaul Moore  * but for some reason we are having problems sending it audit records so
433c6480207SPaul Moore  * queue the given record and attempt to resend.
434c6480207SPaul Moore  */
435c6480207SPaul Moore static void kauditd_retry_skb(struct sk_buff *skb)
436c6480207SPaul Moore {
437c6480207SPaul Moore 	/* NOTE: because records should only live in the retry queue for a
438c6480207SPaul Moore 	 * short period of time, before either being sent or moved to the hold
439c6480207SPaul Moore 	 * queue, we don't currently enforce a limit on this queue */
440c6480207SPaul Moore 	skb_queue_tail(&audit_retry_queue, skb);
441c6480207SPaul Moore }
442c6480207SPaul Moore 
443c6480207SPaul Moore /**
444c6480207SPaul Moore  * auditd_reset - Disconnect the auditd connection
445c6480207SPaul Moore  *
446c6480207SPaul Moore  * Description:
447c6480207SPaul Moore  * Break the auditd/kauditd connection and move all the records in the retry
448*533c7b69SRichard Guy Briggs  * queue into the hold queue in case auditd reconnects.  The audit_cmd_mutex
449*533c7b69SRichard Guy Briggs  * must be held when calling this function.
450c6480207SPaul Moore  */
451c6480207SPaul Moore static void auditd_reset(void)
452c6480207SPaul Moore {
453c6480207SPaul Moore 	struct sk_buff *skb;
454c6480207SPaul Moore 
455c6480207SPaul Moore 	/* break the connection */
456*533c7b69SRichard Guy Briggs 	if (audit_sock) {
457*533c7b69SRichard Guy Briggs 		sock_put(audit_sock);
45833faba7fSRichard Guy Briggs 		audit_sock = NULL;
459*533c7b69SRichard Guy Briggs 	}
460*533c7b69SRichard Guy Briggs 	audit_pid = 0;
461*533c7b69SRichard Guy Briggs 	audit_nlk_portid = 0;
462c6480207SPaul Moore 
463c6480207SPaul Moore 	/* flush all of the retry queue to the hold queue */
464c6480207SPaul Moore 	while ((skb = skb_dequeue(&audit_retry_queue)))
465c6480207SPaul Moore 		kauditd_hold_skb(skb);
46632a1dbaeSRichard Guy Briggs }
467c6480207SPaul Moore 
468c6480207SPaul Moore /**
469c6480207SPaul Moore  * kauditd_send_unicast_skb - Send a record via unicast to auditd
470c6480207SPaul Moore  * @skb: audit record
471c6480207SPaul Moore  */
472c6480207SPaul Moore static int kauditd_send_unicast_skb(struct sk_buff *skb)
473c6480207SPaul Moore {
474c6480207SPaul Moore 	int rc;
475c6480207SPaul Moore 
4766c54e789SPaul Moore 	/* if we know nothing is connected, don't even try the netlink call */
4776c54e789SPaul Moore 	if (!audit_pid)
4786c54e789SPaul Moore 		return -ECONNREFUSED;
4796c54e789SPaul Moore 
480c6480207SPaul Moore 	/* get an extra skb reference in case we fail to send */
481c6480207SPaul Moore 	skb_get(skb);
482c6480207SPaul Moore 	rc = netlink_unicast(audit_sock, skb, audit_nlk_portid, 0);
483c6480207SPaul Moore 	if (rc >= 0) {
48470d4bf6dSNeil Horman 		consume_skb(skb);
485c6480207SPaul Moore 		rc = 0;
486c6480207SPaul Moore 	}
487c6480207SPaul Moore 
488c6480207SPaul Moore 	return rc;
489f3d357b0SEric Paris }
490f3d357b0SEric Paris 
491f3d357b0SEric Paris /*
492c6480207SPaul Moore  * kauditd_send_multicast_skb - Send a record to any multicast listeners
493c6480207SPaul Moore  * @skb: audit record
494451f9216SRichard Guy Briggs  *
495c6480207SPaul Moore  * Description:
496451f9216SRichard Guy Briggs  * This function doesn't consume an skb as might be expected since it has to
497451f9216SRichard Guy Briggs  * copy it anyways.
498451f9216SRichard Guy Briggs  */
499c6480207SPaul Moore static void kauditd_send_multicast_skb(struct sk_buff *skb)
500451f9216SRichard Guy Briggs {
501451f9216SRichard Guy Briggs 	struct sk_buff *copy;
502451f9216SRichard Guy Briggs 	struct audit_net *aunet = net_generic(&init_net, audit_net_id);
503451f9216SRichard Guy Briggs 	struct sock *sock = aunet->nlsk;
504c6480207SPaul Moore 	struct nlmsghdr *nlh;
505451f9216SRichard Guy Briggs 
5067f74ecd7SRichard Guy Briggs 	if (!netlink_has_listeners(sock, AUDIT_NLGRP_READLOG))
5077f74ecd7SRichard Guy Briggs 		return;
5087f74ecd7SRichard Guy Briggs 
509451f9216SRichard Guy Briggs 	/*
510451f9216SRichard Guy Briggs 	 * The seemingly wasteful skb_copy() rather than bumping the refcount
511451f9216SRichard Guy Briggs 	 * using skb_get() is necessary because non-standard mods are made to
512451f9216SRichard Guy Briggs 	 * the skb by the original kaudit unicast socket send routine.  The
513451f9216SRichard Guy Briggs 	 * existing auditd daemon assumes this breakage.  Fixing this would
514451f9216SRichard Guy Briggs 	 * require co-ordinating a change in the established protocol between
515451f9216SRichard Guy Briggs 	 * the kaudit kernel subsystem and the auditd userspace code.  There is
516451f9216SRichard Guy Briggs 	 * no reason for new multicast clients to continue with this
517451f9216SRichard Guy Briggs 	 * non-compliance.
518451f9216SRichard Guy Briggs 	 */
519c6480207SPaul Moore 	copy = skb_copy(skb, GFP_KERNEL);
520451f9216SRichard Guy Briggs 	if (!copy)
521451f9216SRichard Guy Briggs 		return;
522c6480207SPaul Moore 	nlh = nlmsg_hdr(copy);
523c6480207SPaul Moore 	nlh->nlmsg_len = skb->len;
524451f9216SRichard Guy Briggs 
525c6480207SPaul Moore 	nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, GFP_KERNEL);
526451f9216SRichard Guy Briggs }
527451f9216SRichard Guy Briggs 
528c6480207SPaul Moore /**
529c6480207SPaul Moore  * kauditd_wake_condition - Return true when it is time to wake kauditd_thread
530b551d1d9SRichard Guy Briggs  *
531c6480207SPaul Moore  * Description:
532c6480207SPaul Moore  * This function is for use by the wait_event_freezable() call in
533c6480207SPaul Moore  * kauditd_thread().
534f3d357b0SEric Paris  */
535c6480207SPaul Moore static int kauditd_wake_condition(void)
536b551d1d9SRichard Guy Briggs {
537c6480207SPaul Moore 	static int pid_last = 0;
538c6480207SPaul Moore 	int rc;
539c6480207SPaul Moore 	int pid = audit_pid;
540b551d1d9SRichard Guy Briggs 
541c6480207SPaul Moore 	/* wake on new messages or a change in the connected auditd */
542c6480207SPaul Moore 	rc = skb_queue_len(&audit_queue) || (pid && pid != pid_last);
543c6480207SPaul Moore 	if (rc)
544c6480207SPaul Moore 		pid_last = pid;
545b551d1d9SRichard Guy Briggs 
546c6480207SPaul Moore 	return rc;
547f3d357b0SEric Paris }
548b551d1d9SRichard Guy Briggs 
54997a41e26SAdrian Bunk static int kauditd_thread(void *dummy)
550b7d11258SDavid Woodhouse {
551c6480207SPaul Moore 	int rc;
552c6480207SPaul Moore 	int auditd = 0;
553c6480207SPaul Moore 	int reschedule = 0;
5544aa83872SPaul Moore 	struct sk_buff *skb;
5554aa83872SPaul Moore 	struct nlmsghdr *nlh;
5564aa83872SPaul Moore 
557c6480207SPaul Moore #define UNICAST_RETRIES 5
558c6480207SPaul Moore #define AUDITD_BAD(x,y) \
559c6480207SPaul Moore 	((x) == -ECONNREFUSED || (x) == -EPERM || ++(y) >= UNICAST_RETRIES)
560c6480207SPaul Moore 
561c6480207SPaul Moore 	/* NOTE: we do invalidate the auditd connection flag on any sending
562c6480207SPaul Moore 	 * errors, but we only "restore" the connection flag at specific places
563c6480207SPaul Moore 	 * in the loop in order to help ensure proper ordering of audit
564c6480207SPaul Moore 	 * records */
565c6480207SPaul Moore 
56683144186SRafael J. Wysocki 	set_freezable();
5674899b8b1SAndrew Morton 	while (!kthread_should_stop()) {
568c6480207SPaul Moore 		/* NOTE: possible area for future improvement is to look at
569c6480207SPaul Moore 		 *       the hold and retry queues, since only this thread
570c6480207SPaul Moore 		 *       has access to these queues we might be able to do
571c6480207SPaul Moore 		 *       our own queuing and skip some/all of the locking */
572f3d357b0SEric Paris 
573c6480207SPaul Moore 		/* NOTE: it might be a fun experiment to split the hold and
574c6480207SPaul Moore 		 *       retry queue handling to another thread, but the
575c6480207SPaul Moore 		 *       synchronization issues and other overhead might kill
576c6480207SPaul Moore 		 *       any performance gains */
577c6480207SPaul Moore 
578c6480207SPaul Moore 		/* attempt to flush the hold queue */
579c6480207SPaul Moore 		while (auditd && (skb = skb_dequeue(&audit_hold_queue))) {
580c6480207SPaul Moore 			rc = kauditd_send_unicast_skb(skb);
581c6480207SPaul Moore 			if (rc) {
582c6480207SPaul Moore 				/* requeue to the same spot */
583c6480207SPaul Moore 				skb_queue_head(&audit_hold_queue, skb);
584c6480207SPaul Moore 
585c6480207SPaul Moore 				auditd = 0;
586c6480207SPaul Moore 				if (AUDITD_BAD(rc, reschedule)) {
587*533c7b69SRichard Guy Briggs 					mutex_lock(&audit_cmd_mutex);
588c6480207SPaul Moore 					auditd_reset();
589*533c7b69SRichard Guy Briggs 					mutex_unlock(&audit_cmd_mutex);
590c6480207SPaul Moore 					reschedule = 0;
591c6480207SPaul Moore 				}
592c6480207SPaul Moore 			} else
593c6480207SPaul Moore 				/* we were able to send successfully */
594c6480207SPaul Moore 				reschedule = 0;
595c6480207SPaul Moore 		}
596c6480207SPaul Moore 
597c6480207SPaul Moore 		/* attempt to flush the retry queue */
598c6480207SPaul Moore 		while (auditd && (skb = skb_dequeue(&audit_retry_queue))) {
599c6480207SPaul Moore 			rc = kauditd_send_unicast_skb(skb);
600c6480207SPaul Moore 			if (rc) {
601c6480207SPaul Moore 				auditd = 0;
602c6480207SPaul Moore 				if (AUDITD_BAD(rc, reschedule)) {
603c6480207SPaul Moore 					kauditd_hold_skb(skb);
604*533c7b69SRichard Guy Briggs 					mutex_lock(&audit_cmd_mutex);
605c6480207SPaul Moore 					auditd_reset();
606*533c7b69SRichard Guy Briggs 					mutex_unlock(&audit_cmd_mutex);
607c6480207SPaul Moore 					reschedule = 0;
608c6480207SPaul Moore 				} else
609c6480207SPaul Moore 					/* temporary problem (we hope), queue
610c6480207SPaul Moore 					 * to the same spot and retry */
611c6480207SPaul Moore 					skb_queue_head(&audit_retry_queue, skb);
612c6480207SPaul Moore 			} else
613c6480207SPaul Moore 				/* we were able to send successfully */
614c6480207SPaul Moore 				reschedule = 0;
615c6480207SPaul Moore 		}
616c6480207SPaul Moore 
617c6480207SPaul Moore 		/* standard queue processing, try to be as quick as possible */
618c6480207SPaul Moore quick_loop:
619af8b824fSPaul Moore 		skb = skb_dequeue(&audit_queue);
620b7d11258SDavid Woodhouse 		if (skb) {
621c6480207SPaul Moore 			/* setup the netlink header, see the comments in
622c6480207SPaul Moore 			 * kauditd_send_multicast_skb() for length quirks */
6234aa83872SPaul Moore 			nlh = nlmsg_hdr(skb);
624c6480207SPaul Moore 			nlh->nlmsg_len = skb->len - NLMSG_HDRLEN;
6254aa83872SPaul Moore 
626c6480207SPaul Moore 			/* attempt to send to any multicast listeners */
627c6480207SPaul Moore 			kauditd_send_multicast_skb(skb);
6284aa83872SPaul Moore 
629c6480207SPaul Moore 			/* attempt to send to auditd, queue on failure */
630c6480207SPaul Moore 			if (auditd) {
631c6480207SPaul Moore 				rc = kauditd_send_unicast_skb(skb);
632c6480207SPaul Moore 				if (rc) {
633c6480207SPaul Moore 					auditd = 0;
634c6480207SPaul Moore 					if (AUDITD_BAD(rc, reschedule)) {
635*533c7b69SRichard Guy Briggs 						mutex_lock(&audit_cmd_mutex);
636c6480207SPaul Moore 						auditd_reset();
637*533c7b69SRichard Guy Briggs 						mutex_unlock(&audit_cmd_mutex);
638c6480207SPaul Moore 						reschedule = 0;
6394aa83872SPaul Moore 					}
6404aa83872SPaul Moore 
641c6480207SPaul Moore 					/* move to the retry queue */
642c6480207SPaul Moore 					kauditd_retry_skb(skb);
643c6480207SPaul Moore 				} else
644c6480207SPaul Moore 					/* everything is working so go fast! */
645c6480207SPaul Moore 					goto quick_loop;
646c6480207SPaul Moore 			} else if (reschedule)
647c6480207SPaul Moore 				/* we are currently having problems, move to
648c6480207SPaul Moore 				 * the retry queue */
649c6480207SPaul Moore 				kauditd_retry_skb(skb);
650320f1b1eSEric Paris 			else
651c6480207SPaul Moore 				/* dump the message via printk and hold it */
652c6480207SPaul Moore 				kauditd_hold_skb(skb);
6534aa83872SPaul Moore 		} else {
654c6480207SPaul Moore 			/* we have flushed the backlog so wake everyone */
6554aa83872SPaul Moore 			wake_up(&audit_backlog_wait);
656c6480207SPaul Moore 
657c6480207SPaul Moore 			/* if everything is okay with auditd (if present), go
658c6480207SPaul Moore 			 * to sleep until there is something new in the queue
659c6480207SPaul Moore 			 * or we have a change in the connected auditd;
660c6480207SPaul Moore 			 * otherwise simply reschedule to give things a chance
661c6480207SPaul Moore 			 * to recover */
662c6480207SPaul Moore 			if (reschedule) {
663c6480207SPaul Moore 				set_current_state(TASK_INTERRUPTIBLE);
664c6480207SPaul Moore 				schedule();
665c6480207SPaul Moore 			} else
6664aa83872SPaul Moore 				wait_event_freezable(kauditd_wait,
667c6480207SPaul Moore 						     kauditd_wake_condition());
668c6480207SPaul Moore 
669c6480207SPaul Moore 			/* update the auditd connection status */
670c6480207SPaul Moore 			auditd = (audit_pid ? 1 : 0);
6713320c513SRichard Guy Briggs 		}
672b7d11258SDavid Woodhouse 	}
673c6480207SPaul Moore 
6744899b8b1SAndrew Morton 	return 0;
675b7d11258SDavid Woodhouse }
676b7d11258SDavid Woodhouse 
6779044e6bcSAl Viro int audit_send_list(void *_dest)
6789044e6bcSAl Viro {
6799044e6bcSAl Viro 	struct audit_netlink_list *dest = _dest;
6809044e6bcSAl Viro 	struct sk_buff *skb;
68148095d99SEric W. Biederman 	struct net *net = dest->net;
68233faba7fSRichard Guy Briggs 	struct audit_net *aunet = net_generic(net, audit_net_id);
6839044e6bcSAl Viro 
6849044e6bcSAl Viro 	/* wait for parent to finish and send an ACK */
685f368c07dSAmy Griffis 	mutex_lock(&audit_cmd_mutex);
686f368c07dSAmy Griffis 	mutex_unlock(&audit_cmd_mutex);
6879044e6bcSAl Viro 
6889044e6bcSAl Viro 	while ((skb = __skb_dequeue(&dest->q)) != NULL)
68933faba7fSRichard Guy Briggs 		netlink_unicast(aunet->nlsk, skb, dest->portid, 0);
6909044e6bcSAl Viro 
69148095d99SEric W. Biederman 	put_net(net);
6929044e6bcSAl Viro 	kfree(dest);
6939044e6bcSAl Viro 
6949044e6bcSAl Viro 	return 0;
6959044e6bcSAl Viro }
6969044e6bcSAl Viro 
697f9441639SRichard Guy Briggs struct sk_buff *audit_make_reply(__u32 portid, int seq, int type, int done,
698b8800aa5SStephen Hemminger 				 int multi, const void *payload, int size)
6999044e6bcSAl Viro {
7009044e6bcSAl Viro 	struct sk_buff	*skb;
7019044e6bcSAl Viro 	struct nlmsghdr	*nlh;
7029044e6bcSAl Viro 	void		*data;
7039044e6bcSAl Viro 	int		flags = multi ? NLM_F_MULTI : 0;
7049044e6bcSAl Viro 	int		t     = done  ? NLMSG_DONE  : type;
7059044e6bcSAl Viro 
706ee080e6cSEric Paris 	skb = nlmsg_new(size, GFP_KERNEL);
7079044e6bcSAl Viro 	if (!skb)
7089044e6bcSAl Viro 		return NULL;
7099044e6bcSAl Viro 
710f9441639SRichard Guy Briggs 	nlh	= nlmsg_put(skb, portid, seq, t, size, flags);
711c64e66c6SDavid S. Miller 	if (!nlh)
712c64e66c6SDavid S. Miller 		goto out_kfree_skb;
713c64e66c6SDavid S. Miller 	data = nlmsg_data(nlh);
7149044e6bcSAl Viro 	memcpy(data, payload, size);
7159044e6bcSAl Viro 	return skb;
7169044e6bcSAl Viro 
717c64e66c6SDavid S. Miller out_kfree_skb:
7189044e6bcSAl Viro 	kfree_skb(skb);
7199044e6bcSAl Viro 	return NULL;
7209044e6bcSAl Viro }
7219044e6bcSAl Viro 
722f09ac9dbSEric Paris static int audit_send_reply_thread(void *arg)
723f09ac9dbSEric Paris {
724f09ac9dbSEric Paris 	struct audit_reply *reply = (struct audit_reply *)arg;
72548095d99SEric W. Biederman 	struct net *net = reply->net;
72633faba7fSRichard Guy Briggs 	struct audit_net *aunet = net_generic(net, audit_net_id);
727f09ac9dbSEric Paris 
728f09ac9dbSEric Paris 	mutex_lock(&audit_cmd_mutex);
729f09ac9dbSEric Paris 	mutex_unlock(&audit_cmd_mutex);
730f09ac9dbSEric Paris 
731f09ac9dbSEric Paris 	/* Ignore failure. It'll only happen if the sender goes away,
732f09ac9dbSEric Paris 	   because our timeout is set to infinite. */
73333faba7fSRichard Guy Briggs 	netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0);
73448095d99SEric W. Biederman 	put_net(net);
735f09ac9dbSEric Paris 	kfree(reply);
736f09ac9dbSEric Paris 	return 0;
737f09ac9dbSEric Paris }
738c6480207SPaul Moore 
739b0dd25a8SRandy Dunlap /**
740b0dd25a8SRandy Dunlap  * audit_send_reply - send an audit reply message via netlink
741d211f177SEric W. Biederman  * @request_skb: skb of request we are replying to (used to target the reply)
742b0dd25a8SRandy Dunlap  * @seq: sequence number
743b0dd25a8SRandy Dunlap  * @type: audit message type
744b0dd25a8SRandy Dunlap  * @done: done (last) flag
745b0dd25a8SRandy Dunlap  * @multi: multi-part message flag
746b0dd25a8SRandy Dunlap  * @payload: payload data
747b0dd25a8SRandy Dunlap  * @size: payload size
748b0dd25a8SRandy Dunlap  *
749f9441639SRichard Guy Briggs  * Allocates an skb, builds the netlink message, and sends it to the port id.
750b0dd25a8SRandy Dunlap  * No failure notifications.
751b0dd25a8SRandy Dunlap  */
7526f285b19SEric W. Biederman static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
753f9441639SRichard Guy Briggs 			     int multi, const void *payload, int size)
7541da177e4SLinus Torvalds {
7556f285b19SEric W. Biederman 	u32 portid = NETLINK_CB(request_skb).portid;
7566f285b19SEric W. Biederman 	struct net *net = sock_net(NETLINK_CB(request_skb).sk);
7571da177e4SLinus Torvalds 	struct sk_buff *skb;
758f09ac9dbSEric Paris 	struct task_struct *tsk;
759f09ac9dbSEric Paris 	struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
760f09ac9dbSEric Paris 					    GFP_KERNEL);
761f09ac9dbSEric Paris 
762f09ac9dbSEric Paris 	if (!reply)
763f09ac9dbSEric Paris 		return;
764f09ac9dbSEric Paris 
765f9441639SRichard Guy Briggs 	skb = audit_make_reply(portid, seq, type, done, multi, payload, size);
7661da177e4SLinus Torvalds 	if (!skb)
767fcaf1eb8SAndrew Morton 		goto out;
768f09ac9dbSEric Paris 
7696f285b19SEric W. Biederman 	reply->net = get_net(net);
770f9441639SRichard Guy Briggs 	reply->portid = portid;
771f09ac9dbSEric Paris 	reply->skb = skb;
772f09ac9dbSEric Paris 
773f09ac9dbSEric Paris 	tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
774fcaf1eb8SAndrew Morton 	if (!IS_ERR(tsk))
775fcaf1eb8SAndrew Morton 		return;
776f09ac9dbSEric Paris 	kfree_skb(skb);
777fcaf1eb8SAndrew Morton out:
778fcaf1eb8SAndrew Morton 	kfree(reply);
7791da177e4SLinus Torvalds }
7801da177e4SLinus Torvalds 
7811da177e4SLinus Torvalds /*
7821da177e4SLinus Torvalds  * Check for appropriate CAP_AUDIT_ capabilities on incoming audit
7831da177e4SLinus Torvalds  * control messages.
7841da177e4SLinus Torvalds  */
785c7bdb545SDarrel Goeddel static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
7861da177e4SLinus Torvalds {
7871da177e4SLinus Torvalds 	int err = 0;
7881da177e4SLinus Torvalds 
7895a3cb3b6SRichard Guy Briggs 	/* Only support initial user namespace for now. */
790aa4af831SEric Paris 	/*
791aa4af831SEric Paris 	 * We return ECONNREFUSED because it tricks userspace into thinking
792aa4af831SEric Paris 	 * that audit was not configured into the kernel.  Lots of users
793aa4af831SEric Paris 	 * configure their PAM stack (because that's what the distro does)
794aa4af831SEric Paris 	 * to reject login if unable to send messages to audit.  If we return
795aa4af831SEric Paris 	 * ECONNREFUSED the PAM stack thinks the kernel does not have audit
796aa4af831SEric Paris 	 * configured in and will let login proceed.  If we return EPERM
797aa4af831SEric Paris 	 * userspace will reject all logins.  This should be removed when we
798aa4af831SEric Paris 	 * support non init namespaces!!
799aa4af831SEric Paris 	 */
8000b747172SLinus Torvalds 	if (current_user_ns() != &init_user_ns)
801aa4af831SEric Paris 		return -ECONNREFUSED;
80234e36d8eSEric W. Biederman 
8031da177e4SLinus Torvalds 	switch (msg_type) {
8041da177e4SLinus Torvalds 	case AUDIT_LIST:
8051da177e4SLinus Torvalds 	case AUDIT_ADD:
8061da177e4SLinus Torvalds 	case AUDIT_DEL:
80718900909SEric Paris 		return -EOPNOTSUPP;
80818900909SEric Paris 	case AUDIT_GET:
80918900909SEric Paris 	case AUDIT_SET:
810b0fed402SEric Paris 	case AUDIT_GET_FEATURE:
811b0fed402SEric Paris 	case AUDIT_SET_FEATURE:
81218900909SEric Paris 	case AUDIT_LIST_RULES:
81318900909SEric Paris 	case AUDIT_ADD_RULE:
81493315ed6SAmy Griffis 	case AUDIT_DEL_RULE:
815c2f0c7c3SSteve Grubb 	case AUDIT_SIGNAL_INFO:
816522ed776SMiloslav Trmac 	case AUDIT_TTY_GET:
817522ed776SMiloslav Trmac 	case AUDIT_TTY_SET:
81874c3cbe3SAl Viro 	case AUDIT_TRIM:
81974c3cbe3SAl Viro 	case AUDIT_MAKE_EQUIV:
8205a3cb3b6SRichard Guy Briggs 		/* Only support auditd and auditctl in initial pid namespace
8215a3cb3b6SRichard Guy Briggs 		 * for now. */
8225985de67SAmeen Ali 		if (task_active_pid_ns(current) != &init_pid_ns)
8235a3cb3b6SRichard Guy Briggs 			return -EPERM;
8245a3cb3b6SRichard Guy Briggs 
82590f62cf3SEric W. Biederman 		if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
8261da177e4SLinus Torvalds 			err = -EPERM;
8271da177e4SLinus Torvalds 		break;
82805474106SSteve Grubb 	case AUDIT_USER:
829209aba03SDavid Woodhouse 	case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
83090d526c0SSteve Grubb 	case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
83190f62cf3SEric W. Biederman 		if (!netlink_capable(skb, CAP_AUDIT_WRITE))
8321da177e4SLinus Torvalds 			err = -EPERM;
8331da177e4SLinus Torvalds 		break;
8341da177e4SLinus Torvalds 	default:  /* bad msg */
8351da177e4SLinus Torvalds 		err = -EINVAL;
8361da177e4SLinus Torvalds 	}
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 	return err;
8391da177e4SLinus Torvalds }
8401da177e4SLinus Torvalds 
841233a6866SPaul Moore static void audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)
84250397bd1SEric Paris {
843dc9eb698SEric Paris 	uid_t uid = from_kuid(&init_user_ns, current_uid());
844f1dc4867SRichard Guy Briggs 	pid_t pid = task_tgid_nr(current);
84550397bd1SEric Paris 
8460868a5e1STyler Hicks 	if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
84750397bd1SEric Paris 		*ab = NULL;
848233a6866SPaul Moore 		return;
84950397bd1SEric Paris 	}
85050397bd1SEric Paris 
85150397bd1SEric Paris 	*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
8520644ec0cSKees Cook 	if (unlikely(!*ab))
853233a6866SPaul Moore 		return;
854f1dc4867SRichard Guy Briggs 	audit_log_format(*ab, "pid=%d uid=%u", pid, uid);
8554d3fb709SEric Paris 	audit_log_session_info(*ab);
856b122c376SEric Paris 	audit_log_task_context(*ab);
85750397bd1SEric Paris }
85850397bd1SEric Paris 
859b0fed402SEric Paris int is_audit_feature_set(int i)
860b0fed402SEric Paris {
861b0fed402SEric Paris 	return af.features & AUDIT_FEATURE_TO_MASK(i);
862b0fed402SEric Paris }
863b0fed402SEric Paris 
864b0fed402SEric Paris 
865b0fed402SEric Paris static int audit_get_feature(struct sk_buff *skb)
866b0fed402SEric Paris {
867b0fed402SEric Paris 	u32 seq;
868b0fed402SEric Paris 
869b0fed402SEric Paris 	seq = nlmsg_hdr(skb)->nlmsg_seq;
870b0fed402SEric Paris 
8719ef91514SRichard Guy Briggs 	audit_send_reply(skb, seq, AUDIT_GET_FEATURE, 0, 0, &af, sizeof(af));
872b0fed402SEric Paris 
873b0fed402SEric Paris 	return 0;
874b0fed402SEric Paris }
875b0fed402SEric Paris 
876b0fed402SEric Paris static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature,
877b0fed402SEric Paris 				     u32 old_lock, u32 new_lock, int res)
878b0fed402SEric Paris {
879b0fed402SEric Paris 	struct audit_buffer *ab;
880b0fed402SEric Paris 
881b6c50fe0SGao feng 	if (audit_enabled == AUDIT_OFF)
882b6c50fe0SGao feng 		return;
883b6c50fe0SGao feng 
884b0fed402SEric Paris 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
885ad2ac263SRichard Guy Briggs 	audit_log_task_info(ab, current);
8863e1d0bb6SJoe Perches 	audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d",
887b0fed402SEric Paris 			 audit_feature_names[which], !!old_feature, !!new_feature,
888b0fed402SEric Paris 			 !!old_lock, !!new_lock, res);
889b0fed402SEric Paris 	audit_log_end(ab);
890b0fed402SEric Paris }
891b0fed402SEric Paris 
892b0fed402SEric Paris static int audit_set_feature(struct sk_buff *skb)
893b0fed402SEric Paris {
894b0fed402SEric Paris 	struct audit_features *uaf;
895b0fed402SEric Paris 	int i;
896b0fed402SEric Paris 
8976eed9b26SFabian Frederick 	BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names));
898b0fed402SEric Paris 	uaf = nlmsg_data(nlmsg_hdr(skb));
899b0fed402SEric Paris 
900b0fed402SEric Paris 	/* if there is ever a version 2 we should handle that here */
901b0fed402SEric Paris 
902b0fed402SEric Paris 	for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
903b0fed402SEric Paris 		u32 feature = AUDIT_FEATURE_TO_MASK(i);
904b0fed402SEric Paris 		u32 old_feature, new_feature, old_lock, new_lock;
905b0fed402SEric Paris 
906b0fed402SEric Paris 		/* if we are not changing this feature, move along */
907b0fed402SEric Paris 		if (!(feature & uaf->mask))
908b0fed402SEric Paris 			continue;
909b0fed402SEric Paris 
910b0fed402SEric Paris 		old_feature = af.features & feature;
911b0fed402SEric Paris 		new_feature = uaf->features & feature;
912b0fed402SEric Paris 		new_lock = (uaf->lock | af.lock) & feature;
913b0fed402SEric Paris 		old_lock = af.lock & feature;
914b0fed402SEric Paris 
915b0fed402SEric Paris 		/* are we changing a locked feature? */
9164547b3bcSGao feng 		if (old_lock && (new_feature != old_feature)) {
917b0fed402SEric Paris 			audit_log_feature_change(i, old_feature, new_feature,
918b0fed402SEric Paris 						 old_lock, new_lock, 0);
919b0fed402SEric Paris 			return -EPERM;
920b0fed402SEric Paris 		}
921b0fed402SEric Paris 	}
922b0fed402SEric Paris 	/* nothing invalid, do the changes */
923b0fed402SEric Paris 	for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
924b0fed402SEric Paris 		u32 feature = AUDIT_FEATURE_TO_MASK(i);
925b0fed402SEric Paris 		u32 old_feature, new_feature, old_lock, new_lock;
926b0fed402SEric Paris 
927b0fed402SEric Paris 		/* if we are not changing this feature, move along */
928b0fed402SEric Paris 		if (!(feature & uaf->mask))
929b0fed402SEric Paris 			continue;
930b0fed402SEric Paris 
931b0fed402SEric Paris 		old_feature = af.features & feature;
932b0fed402SEric Paris 		new_feature = uaf->features & feature;
933b0fed402SEric Paris 		old_lock = af.lock & feature;
934b0fed402SEric Paris 		new_lock = (uaf->lock | af.lock) & feature;
935b0fed402SEric Paris 
936b0fed402SEric Paris 		if (new_feature != old_feature)
937b0fed402SEric Paris 			audit_log_feature_change(i, old_feature, new_feature,
938b0fed402SEric Paris 						 old_lock, new_lock, 1);
939b0fed402SEric Paris 
940b0fed402SEric Paris 		if (new_feature)
941b0fed402SEric Paris 			af.features |= feature;
942b0fed402SEric Paris 		else
943b0fed402SEric Paris 			af.features &= ~feature;
944b0fed402SEric Paris 		af.lock |= new_lock;
945b0fed402SEric Paris 	}
946b0fed402SEric Paris 
947b0fed402SEric Paris 	return 0;
948b0fed402SEric Paris }
949b0fed402SEric Paris 
950133e1e5aSRichard Guy Briggs static int audit_replace(pid_t pid)
951133e1e5aSRichard Guy Briggs {
952133e1e5aSRichard Guy Briggs 	struct sk_buff *skb = audit_make_reply(0, 0, AUDIT_REPLACE, 0, 0,
953133e1e5aSRichard Guy Briggs 					       &pid, sizeof(pid));
954133e1e5aSRichard Guy Briggs 
955133e1e5aSRichard Guy Briggs 	if (!skb)
956133e1e5aSRichard Guy Briggs 		return -ENOMEM;
957133e1e5aSRichard Guy Briggs 	return netlink_unicast(audit_sock, skb, audit_nlk_portid, 0);
958133e1e5aSRichard Guy Briggs }
959133e1e5aSRichard Guy Briggs 
9601da177e4SLinus Torvalds static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
9611da177e4SLinus Torvalds {
962dc9eb698SEric Paris 	u32			seq;
9631da177e4SLinus Torvalds 	void			*data;
9641da177e4SLinus Torvalds 	int			err;
965c0404993SSteve Grubb 	struct audit_buffer	*ab;
9661da177e4SLinus Torvalds 	u16			msg_type = nlh->nlmsg_type;
967e1396065SAl Viro 	struct audit_sig_info   *sig_data;
96850397bd1SEric Paris 	char			*ctx = NULL;
969e1396065SAl Viro 	u32			len;
9701da177e4SLinus Torvalds 
971c7bdb545SDarrel Goeddel 	err = audit_netlink_ok(skb, msg_type);
9721da177e4SLinus Torvalds 	if (err)
9731da177e4SLinus Torvalds 		return err;
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 	seq  = nlh->nlmsg_seq;
976c64e66c6SDavid S. Miller 	data = nlmsg_data(nlh);
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 	switch (msg_type) {
97909f883a9SRichard Guy Briggs 	case AUDIT_GET: {
98009f883a9SRichard Guy Briggs 		struct audit_status	s;
98109f883a9SRichard Guy Briggs 		memset(&s, 0, sizeof(s));
98209f883a9SRichard Guy Briggs 		s.enabled		= audit_enabled;
98309f883a9SRichard Guy Briggs 		s.failure		= audit_failure;
98409f883a9SRichard Guy Briggs 		s.pid			= audit_pid;
98509f883a9SRichard Guy Briggs 		s.rate_limit		= audit_rate_limit;
98609f883a9SRichard Guy Briggs 		s.backlog_limit		= audit_backlog_limit;
98709f883a9SRichard Guy Briggs 		s.lost			= atomic_read(&audit_lost);
988af8b824fSPaul Moore 		s.backlog		= skb_queue_len(&audit_queue);
9890288d718SRichard Guy Briggs 		s.feature_bitmap	= AUDIT_FEATURE_BITMAP_ALL;
99031975424SPaul Moore 		s.backlog_wait_time	= audit_backlog_wait_time;
9916f285b19SEric W. Biederman 		audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
9921da177e4SLinus Torvalds 		break;
99309f883a9SRichard Guy Briggs 	}
99409f883a9SRichard Guy Briggs 	case AUDIT_SET: {
99509f883a9SRichard Guy Briggs 		struct audit_status	s;
99609f883a9SRichard Guy Briggs 		memset(&s, 0, sizeof(s));
99709f883a9SRichard Guy Briggs 		/* guard against past and future API changes */
99809f883a9SRichard Guy Briggs 		memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
99909f883a9SRichard Guy Briggs 		if (s.mask & AUDIT_STATUS_ENABLED) {
100009f883a9SRichard Guy Briggs 			err = audit_set_enabled(s.enabled);
100120c6aaa3Szhangxiliang 			if (err < 0)
100220c6aaa3Szhangxiliang 				return err;
10031da177e4SLinus Torvalds 		}
100409f883a9SRichard Guy Briggs 		if (s.mask & AUDIT_STATUS_FAILURE) {
100509f883a9SRichard Guy Briggs 			err = audit_set_failure(s.failure);
100620c6aaa3Szhangxiliang 			if (err < 0)
100720c6aaa3Szhangxiliang 				return err;
10081da177e4SLinus Torvalds 		}
100909f883a9SRichard Guy Briggs 		if (s.mask & AUDIT_STATUS_PID) {
101009f883a9SRichard Guy Briggs 			int new_pid = s.pid;
1011133e1e5aSRichard Guy Briggs 			pid_t requesting_pid = task_tgid_vnr(current);
10121a6b9f23SEric Paris 
1013935c9e7fSRichard Guy Briggs 			if ((!new_pid) && (requesting_pid != audit_pid)) {
1014935c9e7fSRichard Guy Briggs 				audit_log_config_change("audit_pid", new_pid, audit_pid, 0);
101534eab0a7SRichard Guy Briggs 				return -EACCES;
1016935c9e7fSRichard Guy Briggs 			}
1017133e1e5aSRichard Guy Briggs 			if (audit_pid && new_pid &&
1018935c9e7fSRichard Guy Briggs 			    audit_replace(requesting_pid) != -ECONNREFUSED) {
1019935c9e7fSRichard Guy Briggs 				audit_log_config_change("audit_pid", new_pid, audit_pid, 0);
1020133e1e5aSRichard Guy Briggs 				return -EEXIST;
1021935c9e7fSRichard Guy Briggs 			}
10221a6b9f23SEric Paris 			if (audit_enabled != AUDIT_OFF)
1023dc9eb698SEric Paris 				audit_log_config_change("audit_pid", new_pid, audit_pid, 1);
1024*533c7b69SRichard Guy Briggs 			if (new_pid) {
1025*533c7b69SRichard Guy Briggs 				if (audit_sock)
1026*533c7b69SRichard Guy Briggs 					sock_put(audit_sock);
10271a6b9f23SEric Paris 				audit_pid = new_pid;
102815e47304SEric W. Biederman 				audit_nlk_portid = NETLINK_CB(skb).portid;
1029*533c7b69SRichard Guy Briggs 				sock_hold(skb->sk);
1030de92fc97SGao feng 				audit_sock = skb->sk;
1031*533c7b69SRichard Guy Briggs 			} else {
10326c54e789SPaul Moore 				auditd_reset();
1033*533c7b69SRichard Guy Briggs 			}
1034e1d16621SPaul Moore 			wake_up_interruptible(&kauditd_wait);
10351da177e4SLinus Torvalds 		}
103609f883a9SRichard Guy Briggs 		if (s.mask & AUDIT_STATUS_RATE_LIMIT) {
103709f883a9SRichard Guy Briggs 			err = audit_set_rate_limit(s.rate_limit);
103820c6aaa3Szhangxiliang 			if (err < 0)
103920c6aaa3Szhangxiliang 				return err;
104020c6aaa3Szhangxiliang 		}
104151cc83f0SRichard Guy Briggs 		if (s.mask & AUDIT_STATUS_BACKLOG_LIMIT) {
104209f883a9SRichard Guy Briggs 			err = audit_set_backlog_limit(s.backlog_limit);
104351cc83f0SRichard Guy Briggs 			if (err < 0)
104451cc83f0SRichard Guy Briggs 				return err;
104551cc83f0SRichard Guy Briggs 		}
104651cc83f0SRichard Guy Briggs 		if (s.mask & AUDIT_STATUS_BACKLOG_WAIT_TIME) {
104751cc83f0SRichard Guy Briggs 			if (sizeof(s) > (size_t)nlh->nlmsg_len)
104851cc83f0SRichard Guy Briggs 				return -EINVAL;
1049724e7bfcSPranith Kumar 			if (s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME)
105051cc83f0SRichard Guy Briggs 				return -EINVAL;
105151cc83f0SRichard Guy Briggs 			err = audit_set_backlog_wait_time(s.backlog_wait_time);
105251cc83f0SRichard Guy Briggs 			if (err < 0)
105351cc83f0SRichard Guy Briggs 				return err;
105451cc83f0SRichard Guy Briggs 		}
10551da177e4SLinus Torvalds 		break;
105609f883a9SRichard Guy Briggs 	}
1057b0fed402SEric Paris 	case AUDIT_GET_FEATURE:
1058b0fed402SEric Paris 		err = audit_get_feature(skb);
1059b0fed402SEric Paris 		if (err)
1060b0fed402SEric Paris 			return err;
1061b0fed402SEric Paris 		break;
1062b0fed402SEric Paris 	case AUDIT_SET_FEATURE:
1063b0fed402SEric Paris 		err = audit_set_feature(skb);
1064b0fed402SEric Paris 		if (err)
1065b0fed402SEric Paris 			return err;
1066b0fed402SEric Paris 		break;
106705474106SSteve Grubb 	case AUDIT_USER:
1068209aba03SDavid Woodhouse 	case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
106990d526c0SSteve Grubb 	case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
10704a4cd633SDavid Woodhouse 		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
10714a4cd633SDavid Woodhouse 			return 0;
10720f45aa18SDavid Woodhouse 
107386b2efbeSRichard Guy Briggs 		err = audit_filter(msg_type, AUDIT_FILTER_USER);
1074724e4fccSRichard Guy Briggs 		if (err == 1) { /* match or error */
10754a4cd633SDavid Woodhouse 			err = 0;
1076522ed776SMiloslav Trmac 			if (msg_type == AUDIT_USER_TTY) {
107737282a77SPeter Hurley 				err = tty_audit_push();
1078522ed776SMiloslav Trmac 				if (err)
1079522ed776SMiloslav Trmac 					break;
1080522ed776SMiloslav Trmac 			}
10811b7b533fSRichard Guy Briggs 			mutex_unlock(&audit_cmd_mutex);
1082dc9eb698SEric Paris 			audit_log_common_recv_msg(&ab, msg_type);
1083522ed776SMiloslav Trmac 			if (msg_type != AUDIT_USER_TTY)
1084b50eba7eSRichard Guy Briggs 				audit_log_format(ab, " msg='%.*s'",
1085b50eba7eSRichard Guy Briggs 						 AUDIT_MESSAGE_TEXT_MAX,
1086e7c34970SSteve Grubb 						 (char *)data);
1087522ed776SMiloslav Trmac 			else {
1088522ed776SMiloslav Trmac 				int size;
1089522ed776SMiloslav Trmac 
1090f7616102SEric Paris 				audit_log_format(ab, " data=");
1091522ed776SMiloslav Trmac 				size = nlmsg_len(nlh);
109255ad2f8dSMiloslav Trmac 				if (size > 0 &&
109355ad2f8dSMiloslav Trmac 				    ((unsigned char *)data)[size - 1] == '\0')
109455ad2f8dSMiloslav Trmac 					size--;
1095b556f8adSEric Paris 				audit_log_n_untrustedstring(ab, data, size);
1096522ed776SMiloslav Trmac 			}
1097f9441639SRichard Guy Briggs 			audit_set_portid(ab, NETLINK_CB(skb).portid);
1098c0404993SSteve Grubb 			audit_log_end(ab);
10991b7b533fSRichard Guy Briggs 			mutex_lock(&audit_cmd_mutex);
11000f45aa18SDavid Woodhouse 		}
11011da177e4SLinus Torvalds 		break;
110293315ed6SAmy Griffis 	case AUDIT_ADD_RULE:
110393315ed6SAmy Griffis 	case AUDIT_DEL_RULE:
110493315ed6SAmy Griffis 		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
110593315ed6SAmy Griffis 			return -EINVAL;
11061a6b9f23SEric Paris 		if (audit_enabled == AUDIT_LOCKED) {
1107dc9eb698SEric Paris 			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
1108dc9eb698SEric Paris 			audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled);
11096a01b07fSSteve Grubb 			audit_log_end(ab);
11106a01b07fSSteve Grubb 			return -EPERM;
11116a01b07fSSteve Grubb 		}
1112ce0d9f04SRichard Guy Briggs 		err = audit_rule_change(msg_type, NETLINK_CB(skb).portid,
1113dc9eb698SEric Paris 					   seq, data, nlmsg_len(nlh));
11141da177e4SLinus Torvalds 		break;
1115ce0d9f04SRichard Guy Briggs 	case AUDIT_LIST_RULES:
11166f285b19SEric W. Biederman 		err = audit_list_rules_send(skb, seq);
1117ce0d9f04SRichard Guy Briggs 		break;
111874c3cbe3SAl Viro 	case AUDIT_TRIM:
111974c3cbe3SAl Viro 		audit_trim_trees();
1120dc9eb698SEric Paris 		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
112174c3cbe3SAl Viro 		audit_log_format(ab, " op=trim res=1");
112274c3cbe3SAl Viro 		audit_log_end(ab);
112374c3cbe3SAl Viro 		break;
112474c3cbe3SAl Viro 	case AUDIT_MAKE_EQUIV: {
112574c3cbe3SAl Viro 		void *bufp = data;
112674c3cbe3SAl Viro 		u32 sizes[2];
11277719e437SHarvey Harrison 		size_t msglen = nlmsg_len(nlh);
112874c3cbe3SAl Viro 		char *old, *new;
112974c3cbe3SAl Viro 
113074c3cbe3SAl Viro 		err = -EINVAL;
11317719e437SHarvey Harrison 		if (msglen < 2 * sizeof(u32))
113274c3cbe3SAl Viro 			break;
113374c3cbe3SAl Viro 		memcpy(sizes, bufp, 2 * sizeof(u32));
113474c3cbe3SAl Viro 		bufp += 2 * sizeof(u32);
11357719e437SHarvey Harrison 		msglen -= 2 * sizeof(u32);
11367719e437SHarvey Harrison 		old = audit_unpack_string(&bufp, &msglen, sizes[0]);
113774c3cbe3SAl Viro 		if (IS_ERR(old)) {
113874c3cbe3SAl Viro 			err = PTR_ERR(old);
113974c3cbe3SAl Viro 			break;
114074c3cbe3SAl Viro 		}
11417719e437SHarvey Harrison 		new = audit_unpack_string(&bufp, &msglen, sizes[1]);
114274c3cbe3SAl Viro 		if (IS_ERR(new)) {
114374c3cbe3SAl Viro 			err = PTR_ERR(new);
114474c3cbe3SAl Viro 			kfree(old);
114574c3cbe3SAl Viro 			break;
114674c3cbe3SAl Viro 		}
114774c3cbe3SAl Viro 		/* OK, here comes... */
114874c3cbe3SAl Viro 		err = audit_tag_tree(old, new);
114974c3cbe3SAl Viro 
1150dc9eb698SEric Paris 		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
115150397bd1SEric Paris 
115274c3cbe3SAl Viro 		audit_log_format(ab, " op=make_equiv old=");
115374c3cbe3SAl Viro 		audit_log_untrustedstring(ab, old);
115474c3cbe3SAl Viro 		audit_log_format(ab, " new=");
115574c3cbe3SAl Viro 		audit_log_untrustedstring(ab, new);
115674c3cbe3SAl Viro 		audit_log_format(ab, " res=%d", !err);
115774c3cbe3SAl Viro 		audit_log_end(ab);
115874c3cbe3SAl Viro 		kfree(old);
115974c3cbe3SAl Viro 		kfree(new);
116074c3cbe3SAl Viro 		break;
116174c3cbe3SAl Viro 	}
1162c2f0c7c3SSteve Grubb 	case AUDIT_SIGNAL_INFO:
1163939cbf26SEric Paris 		len = 0;
1164939cbf26SEric Paris 		if (audit_sig_sid) {
11652a862b32SAhmed S. Darwish 			err = security_secid_to_secctx(audit_sig_sid, &ctx, &len);
1166e1396065SAl Viro 			if (err)
1167e1396065SAl Viro 				return err;
1168939cbf26SEric Paris 		}
1169e1396065SAl Viro 		sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
1170e1396065SAl Viro 		if (!sig_data) {
1171939cbf26SEric Paris 			if (audit_sig_sid)
11722a862b32SAhmed S. Darwish 				security_release_secctx(ctx, len);
1173e1396065SAl Viro 			return -ENOMEM;
1174e1396065SAl Viro 		}
1175cca080d9SEric W. Biederman 		sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
1176e1396065SAl Viro 		sig_data->pid = audit_sig_pid;
1177939cbf26SEric Paris 		if (audit_sig_sid) {
1178e1396065SAl Viro 			memcpy(sig_data->ctx, ctx, len);
11792a862b32SAhmed S. Darwish 			security_release_secctx(ctx, len);
1180939cbf26SEric Paris 		}
11816f285b19SEric W. Biederman 		audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
11826f285b19SEric W. Biederman 				 sig_data, sizeof(*sig_data) + len);
1183e1396065SAl Viro 		kfree(sig_data);
1184c2f0c7c3SSteve Grubb 		break;
1185522ed776SMiloslav Trmac 	case AUDIT_TTY_GET: {
1186522ed776SMiloslav Trmac 		struct audit_tty_status s;
11872e28d38aSPeter Hurley 		unsigned int t;
1188522ed776SMiloslav Trmac 
11892e28d38aSPeter Hurley 		t = READ_ONCE(current->signal->audit_tty);
11902e28d38aSPeter Hurley 		s.enabled = t & AUDIT_TTY_ENABLE;
11912e28d38aSPeter Hurley 		s.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD);
119220703205SThomas Gleixner 
11936f285b19SEric W. Biederman 		audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
1194522ed776SMiloslav Trmac 		break;
1195522ed776SMiloslav Trmac 	}
1196522ed776SMiloslav Trmac 	case AUDIT_TTY_SET: {
1197a06e56b2SRichard Guy Briggs 		struct audit_tty_status s, old;
1198a06e56b2SRichard Guy Briggs 		struct audit_buffer	*ab;
11992e28d38aSPeter Hurley 		unsigned int t;
1200522ed776SMiloslav Trmac 
120146e959eaSRichard Guy Briggs 		memset(&s, 0, sizeof(s));
120246e959eaSRichard Guy Briggs 		/* guard against past and future API changes */
12034d8fe737SMathias Krause 		memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
12040e23baccSEric Paris 		/* check if new data is valid */
12050e23baccSEric Paris 		if ((s.enabled != 0 && s.enabled != 1) ||
12060e23baccSEric Paris 		    (s.log_passwd != 0 && s.log_passwd != 1))
12070e23baccSEric Paris 			err = -EINVAL;
12080e23baccSEric Paris 
12092e28d38aSPeter Hurley 		if (err)
12102e28d38aSPeter Hurley 			t = READ_ONCE(current->signal->audit_tty);
12112e28d38aSPeter Hurley 		else {
12122e28d38aSPeter Hurley 			t = s.enabled | (-s.log_passwd & AUDIT_TTY_LOG_PASSWD);
12132e28d38aSPeter Hurley 			t = xchg(&current->signal->audit_tty, t);
12140e23baccSEric Paris 		}
12152e28d38aSPeter Hurley 		old.enabled = t & AUDIT_TTY_ENABLE;
12162e28d38aSPeter Hurley 		old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD);
12170e23baccSEric Paris 
1218a06e56b2SRichard Guy Briggs 		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);
12191ce319f1SEric Paris 		audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d"
12201ce319f1SEric Paris 				 " old-log_passwd=%d new-log_passwd=%d res=%d",
12211ce319f1SEric Paris 				 old.enabled, s.enabled, old.log_passwd,
12221ce319f1SEric Paris 				 s.log_passwd, !err);
1223a06e56b2SRichard Guy Briggs 		audit_log_end(ab);
1224522ed776SMiloslav Trmac 		break;
1225522ed776SMiloslav Trmac 	}
12261da177e4SLinus Torvalds 	default:
12271da177e4SLinus Torvalds 		err = -EINVAL;
12281da177e4SLinus Torvalds 		break;
12291da177e4SLinus Torvalds 	}
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds 	return err < 0 ? err : 0;
12321da177e4SLinus Torvalds }
12331da177e4SLinus Torvalds 
1234b0dd25a8SRandy Dunlap /*
1235ea7ae60bSEric Paris  * Get message from skb.  Each message is processed by audit_receive_msg.
1236ea7ae60bSEric Paris  * Malformed skbs with wrong length are discarded silently.
1237b0dd25a8SRandy Dunlap  */
12382a0a6ebeSHerbert Xu static void audit_receive_skb(struct sk_buff *skb)
12391da177e4SLinus Torvalds {
12401da177e4SLinus Torvalds 	struct nlmsghdr *nlh;
1241ea7ae60bSEric Paris 	/*
124294191213SHong zhi guo 	 * len MUST be signed for nlmsg_next to be able to dec it below 0
1243ea7ae60bSEric Paris 	 * if the nlmsg_len was not aligned
1244ea7ae60bSEric Paris 	 */
1245ea7ae60bSEric Paris 	int len;
1246ea7ae60bSEric Paris 	int err;
12471da177e4SLinus Torvalds 
1248b529ccf2SArnaldo Carvalho de Melo 	nlh = nlmsg_hdr(skb);
1249ea7ae60bSEric Paris 	len = skb->len;
1250ea7ae60bSEric Paris 
125194191213SHong zhi guo 	while (nlmsg_ok(nlh, len)) {
1252ea7ae60bSEric Paris 		err = audit_receive_msg(skb, nlh);
1253ea7ae60bSEric Paris 		/* if err or if this message says it wants a response */
1254ea7ae60bSEric Paris 		if (err || (nlh->nlmsg_flags & NLM_F_ACK))
12551da177e4SLinus Torvalds 			netlink_ack(skb, nlh, err);
1256ea7ae60bSEric Paris 
12572851da57SAlexandru Copot 		nlh = nlmsg_next(nlh, &len);
12581da177e4SLinus Torvalds 	}
12591da177e4SLinus Torvalds }
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds /* Receive messages from netlink socket. */
1262cd40b7d3SDenis V. Lunev static void audit_receive(struct sk_buff  *skb)
12631da177e4SLinus Torvalds {
1264f368c07dSAmy Griffis 	mutex_lock(&audit_cmd_mutex);
12652a0a6ebeSHerbert Xu 	audit_receive_skb(skb);
1266f368c07dSAmy Griffis 	mutex_unlock(&audit_cmd_mutex);
12671da177e4SLinus Torvalds }
12681da177e4SLinus Torvalds 
12693a101b8dSRichard Guy Briggs /* Run custom bind function on netlink socket group connect or bind requests. */
1270023e2cfaSJohannes Berg static int audit_bind(struct net *net, int group)
12713a101b8dSRichard Guy Briggs {
12723a101b8dSRichard Guy Briggs 	if (!capable(CAP_AUDIT_READ))
12733a101b8dSRichard Guy Briggs 		return -EPERM;
12743a101b8dSRichard Guy Briggs 
12753a101b8dSRichard Guy Briggs 	return 0;
12763a101b8dSRichard Guy Briggs }
12773a101b8dSRichard Guy Briggs 
127833faba7fSRichard Guy Briggs static int __net_init audit_net_init(struct net *net)
12791da177e4SLinus Torvalds {
1280a31f2d17SPablo Neira Ayuso 	struct netlink_kernel_cfg cfg = {
1281a31f2d17SPablo Neira Ayuso 		.input	= audit_receive,
12823a101b8dSRichard Guy Briggs 		.bind	= audit_bind,
1283451f9216SRichard Guy Briggs 		.flags	= NL_CFG_F_NONROOT_RECV,
1284451f9216SRichard Guy Briggs 		.groups	= AUDIT_NLGRP_MAX,
1285a31f2d17SPablo Neira Ayuso 	};
1286f368c07dSAmy Griffis 
128733faba7fSRichard Guy Briggs 	struct audit_net *aunet = net_generic(net, audit_net_id);
128833faba7fSRichard Guy Briggs 
128933faba7fSRichard Guy Briggs 	aunet->nlsk = netlink_kernel_create(net, NETLINK_AUDIT, &cfg);
129011ee39ebSGao feng 	if (aunet->nlsk == NULL) {
129133faba7fSRichard Guy Briggs 		audit_panic("cannot initialize netlink socket in namespace");
129211ee39ebSGao feng 		return -ENOMEM;
129311ee39ebSGao feng 	}
129433faba7fSRichard Guy Briggs 	aunet->nlsk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
129533faba7fSRichard Guy Briggs 	return 0;
129633faba7fSRichard Guy Briggs }
129733faba7fSRichard Guy Briggs 
129833faba7fSRichard Guy Briggs static void __net_exit audit_net_exit(struct net *net)
129933faba7fSRichard Guy Briggs {
130033faba7fSRichard Guy Briggs 	struct audit_net *aunet = net_generic(net, audit_net_id);
130133faba7fSRichard Guy Briggs 	struct sock *sock = aunet->nlsk;
1302*533c7b69SRichard Guy Briggs 	mutex_lock(&audit_cmd_mutex);
1303c6480207SPaul Moore 	if (sock == audit_sock)
1304c6480207SPaul Moore 		auditd_reset();
1305*533c7b69SRichard Guy Briggs 	mutex_unlock(&audit_cmd_mutex);
130633faba7fSRichard Guy Briggs 
1307e231d54cSMonam Agarwal 	RCU_INIT_POINTER(aunet->nlsk, NULL);
130833faba7fSRichard Guy Briggs 	synchronize_net();
130933faba7fSRichard Guy Briggs 	netlink_kernel_release(sock);
131033faba7fSRichard Guy Briggs }
131133faba7fSRichard Guy Briggs 
13128626877bSRichard Guy Briggs static struct pernet_operations audit_net_ops __net_initdata = {
131333faba7fSRichard Guy Briggs 	.init = audit_net_init,
131433faba7fSRichard Guy Briggs 	.exit = audit_net_exit,
131533faba7fSRichard Guy Briggs 	.id = &audit_net_id,
131633faba7fSRichard Guy Briggs 	.size = sizeof(struct audit_net),
131733faba7fSRichard Guy Briggs };
131833faba7fSRichard Guy Briggs 
131933faba7fSRichard Guy Briggs /* Initialize audit support at boot time. */
132033faba7fSRichard Guy Briggs static int __init audit_init(void)
132133faba7fSRichard Guy Briggs {
132233faba7fSRichard Guy Briggs 	int i;
132333faba7fSRichard Guy Briggs 
1324a3f07114SEric Paris 	if (audit_initialized == AUDIT_DISABLED)
1325a3f07114SEric Paris 		return 0;
1326a3f07114SEric Paris 
1327d957f7b7SJoe Perches 	pr_info("initializing netlink subsys (%s)\n",
13281da177e4SLinus Torvalds 		audit_default ? "enabled" : "disabled");
132933faba7fSRichard Guy Briggs 	register_pernet_subsys(&audit_net_ops);
133071e1c784SAmy Griffis 
1331af8b824fSPaul Moore 	skb_queue_head_init(&audit_queue);
1332c6480207SPaul Moore 	skb_queue_head_init(&audit_retry_queue);
1333af8b824fSPaul Moore 	skb_queue_head_init(&audit_hold_queue);
1334a3f07114SEric Paris 	audit_initialized = AUDIT_INITIALIZED;
13351da177e4SLinus Torvalds 	audit_enabled = audit_default;
1336b593d384SEric Paris 	audit_ever_enabled |= !!audit_default;
13373dc7e315SDarrel Goeddel 
1338f368c07dSAmy Griffis 	for (i = 0; i < AUDIT_INODE_BUCKETS; i++)
1339f368c07dSAmy Griffis 		INIT_LIST_HEAD(&audit_inode_hash[i]);
1340f368c07dSAmy Griffis 
13416c925564SPaul Moore 	kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
13426c925564SPaul Moore 	if (IS_ERR(kauditd_task)) {
13436c925564SPaul Moore 		int err = PTR_ERR(kauditd_task);
13446c925564SPaul Moore 		panic("audit: failed to start the kauditd thread (%d)\n", err);
13456c925564SPaul Moore 	}
13466c925564SPaul Moore 
13476c925564SPaul Moore 	audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
13486c925564SPaul Moore 
13491da177e4SLinus Torvalds 	return 0;
13501da177e4SLinus Torvalds }
13511da177e4SLinus Torvalds __initcall(audit_init);
13521da177e4SLinus Torvalds 
13531da177e4SLinus Torvalds /* Process kernel command-line parameter at boot time.  audit=0 or audit=1. */
13541da177e4SLinus Torvalds static int __init audit_enable(char *str)
13551da177e4SLinus Torvalds {
13561da177e4SLinus Torvalds 	audit_default = !!simple_strtol(str, NULL, 0);
1357a3f07114SEric Paris 	if (!audit_default)
1358a3f07114SEric Paris 		audit_initialized = AUDIT_DISABLED;
1359a3f07114SEric Paris 
1360d957f7b7SJoe Perches 	pr_info("%s\n", audit_default ?
1361d3ca0344SGao feng 		"enabled (after initialization)" : "disabled (until reboot)");
1362a3f07114SEric Paris 
13639b41046cSOGAWA Hirofumi 	return 1;
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds __setup("audit=", audit_enable);
13661da177e4SLinus Torvalds 
1367f910fde7SRichard Guy Briggs /* Process kernel command-line parameter at boot time.
1368f910fde7SRichard Guy Briggs  * audit_backlog_limit=<n> */
1369f910fde7SRichard Guy Briggs static int __init audit_backlog_limit_set(char *str)
1370f910fde7SRichard Guy Briggs {
13713e1d0bb6SJoe Perches 	u32 audit_backlog_limit_arg;
1372d957f7b7SJoe Perches 
1373f910fde7SRichard Guy Briggs 	pr_info("audit_backlog_limit: ");
13743e1d0bb6SJoe Perches 	if (kstrtouint(str, 0, &audit_backlog_limit_arg)) {
13753e1d0bb6SJoe Perches 		pr_cont("using default of %u, unable to parse %s\n",
1376f910fde7SRichard Guy Briggs 			audit_backlog_limit, str);
1377f910fde7SRichard Guy Briggs 		return 1;
1378f910fde7SRichard Guy Briggs 	}
13793e1d0bb6SJoe Perches 
13803e1d0bb6SJoe Perches 	audit_backlog_limit = audit_backlog_limit_arg;
1381d957f7b7SJoe Perches 	pr_cont("%d\n", audit_backlog_limit);
1382f910fde7SRichard Guy Briggs 
1383f910fde7SRichard Guy Briggs 	return 1;
1384f910fde7SRichard Guy Briggs }
1385f910fde7SRichard Guy Briggs __setup("audit_backlog_limit=", audit_backlog_limit_set);
1386f910fde7SRichard Guy Briggs 
138716e1904eSChris Wright static void audit_buffer_free(struct audit_buffer *ab)
138816e1904eSChris Wright {
138916e1904eSChris Wright 	unsigned long flags;
139016e1904eSChris Wright 
13918fc6115cSChris Wright 	if (!ab)
13928fc6115cSChris Wright 		return;
13938fc6115cSChris Wright 
13945ac52f33SChris Wright 	kfree_skb(ab->skb);
139516e1904eSChris Wright 	spin_lock_irqsave(&audit_freelist_lock, flags);
13965d136a01SSerge E. Hallyn 	if (audit_freelist_count > AUDIT_MAXFREE)
139716e1904eSChris Wright 		kfree(ab);
13985d136a01SSerge E. Hallyn 	else {
13995d136a01SSerge E. Hallyn 		audit_freelist_count++;
140016e1904eSChris Wright 		list_add(&ab->list, &audit_freelist);
14015d136a01SSerge E. Hallyn 	}
140216e1904eSChris Wright 	spin_unlock_irqrestore(&audit_freelist_lock, flags);
140316e1904eSChris Wright }
140416e1904eSChris Wright 
1405c0404993SSteve Grubb static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx,
1406dd0fc66fSAl Viro 						gfp_t gfp_mask, int type)
140716e1904eSChris Wright {
140816e1904eSChris Wright 	unsigned long flags;
140916e1904eSChris Wright 	struct audit_buffer *ab = NULL;
1410c0404993SSteve Grubb 	struct nlmsghdr *nlh;
141116e1904eSChris Wright 
141216e1904eSChris Wright 	spin_lock_irqsave(&audit_freelist_lock, flags);
141316e1904eSChris Wright 	if (!list_empty(&audit_freelist)) {
141416e1904eSChris Wright 		ab = list_entry(audit_freelist.next,
141516e1904eSChris Wright 				struct audit_buffer, list);
141616e1904eSChris Wright 		list_del(&ab->list);
141716e1904eSChris Wright 		--audit_freelist_count;
141816e1904eSChris Wright 	}
141916e1904eSChris Wright 	spin_unlock_irqrestore(&audit_freelist_lock, flags);
142016e1904eSChris Wright 
142116e1904eSChris Wright 	if (!ab) {
14224332bdd3SDavid Woodhouse 		ab = kmalloc(sizeof(*ab), gfp_mask);
142316e1904eSChris Wright 		if (!ab)
14248fc6115cSChris Wright 			goto err;
142516e1904eSChris Wright 	}
14268fc6115cSChris Wright 
1427c0404993SSteve Grubb 	ab->ctx = ctx;
14289ad9ad38SDavid Woodhouse 	ab->gfp_mask = gfp_mask;
1429ee080e6cSEric Paris 
1430ee080e6cSEric Paris 	ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
1431ee080e6cSEric Paris 	if (!ab->skb)
1432c64e66c6SDavid S. Miller 		goto err;
1433ee080e6cSEric Paris 
1434c64e66c6SDavid S. Miller 	nlh = nlmsg_put(ab->skb, 0, 0, type, 0, 0);
1435c64e66c6SDavid S. Miller 	if (!nlh)
1436c64e66c6SDavid S. Miller 		goto out_kfree_skb;
1437ee080e6cSEric Paris 
143816e1904eSChris Wright 	return ab;
1439ee080e6cSEric Paris 
1440c64e66c6SDavid S. Miller out_kfree_skb:
1441ee080e6cSEric Paris 	kfree_skb(ab->skb);
1442ee080e6cSEric Paris 	ab->skb = NULL;
14438fc6115cSChris Wright err:
14448fc6115cSChris Wright 	audit_buffer_free(ab);
14458fc6115cSChris Wright 	return NULL;
144616e1904eSChris Wright }
14471da177e4SLinus Torvalds 
1448b0dd25a8SRandy Dunlap /**
1449b0dd25a8SRandy Dunlap  * audit_serial - compute a serial number for the audit record
1450b0dd25a8SRandy Dunlap  *
1451b0dd25a8SRandy Dunlap  * Compute a serial number for the audit record.  Audit records are
1452bfb4496eSDavid Woodhouse  * written to user-space as soon as they are generated, so a complete
1453bfb4496eSDavid Woodhouse  * audit record may be written in several pieces.  The timestamp of the
1454bfb4496eSDavid Woodhouse  * record and this serial number are used by the user-space tools to
1455bfb4496eSDavid Woodhouse  * determine which pieces belong to the same audit record.  The
1456bfb4496eSDavid Woodhouse  * (timestamp,serial) tuple is unique for each syscall and is live from
1457bfb4496eSDavid Woodhouse  * syscall entry to syscall exit.
1458bfb4496eSDavid Woodhouse  *
1459bfb4496eSDavid Woodhouse  * NOTE: Another possibility is to store the formatted records off the
1460bfb4496eSDavid Woodhouse  * audit context (for those records that have a context), and emit them
1461bfb4496eSDavid Woodhouse  * all at syscall exit.  However, this could delay the reporting of
1462bfb4496eSDavid Woodhouse  * significant errors until syscall exit (or never, if the system
1463b0dd25a8SRandy Dunlap  * halts).
1464b0dd25a8SRandy Dunlap  */
1465bfb4496eSDavid Woodhouse unsigned int audit_serial(void)
1466bfb4496eSDavid Woodhouse {
146701478d7dSRichard Guy Briggs 	static atomic_t serial = ATOMIC_INIT(0);
1468bfb4496eSDavid Woodhouse 
146901478d7dSRichard Guy Briggs 	return atomic_add_return(1, &serial);
1470bfb4496eSDavid Woodhouse }
1471bfb4496eSDavid Woodhouse 
1472bfb4496eSDavid Woodhouse static inline void audit_get_stamp(struct audit_context *ctx,
1473bfb4496eSDavid Woodhouse 				   struct timespec *t, unsigned int *serial)
1474bfb4496eSDavid Woodhouse {
147548887e63SAl Viro 	if (!ctx || !auditsc_get_stamp(ctx, t, serial)) {
1476bfb4496eSDavid Woodhouse 		*t = CURRENT_TIME;
1477bfb4496eSDavid Woodhouse 		*serial = audit_serial();
1478bfb4496eSDavid Woodhouse 	}
1479bfb4496eSDavid Woodhouse }
1480bfb4496eSDavid Woodhouse 
1481b0dd25a8SRandy Dunlap /**
1482b0dd25a8SRandy Dunlap  * audit_log_start - obtain an audit buffer
1483b0dd25a8SRandy Dunlap  * @ctx: audit_context (may be NULL)
1484b0dd25a8SRandy Dunlap  * @gfp_mask: type of allocation
1485b0dd25a8SRandy Dunlap  * @type: audit message type
1486b0dd25a8SRandy Dunlap  *
1487b0dd25a8SRandy Dunlap  * Returns audit_buffer pointer on success or NULL on error.
1488b0dd25a8SRandy Dunlap  *
1489b0dd25a8SRandy Dunlap  * Obtain an audit buffer.  This routine does locking to obtain the
1490b0dd25a8SRandy Dunlap  * audit buffer, but then no locking is required for calls to
1491b0dd25a8SRandy Dunlap  * audit_log_*format.  If the task (ctx) is a task that is currently in a
1492b0dd25a8SRandy Dunlap  * syscall, then the syscall is marked as auditable and an audit record
1493b0dd25a8SRandy Dunlap  * will be written at syscall exit.  If there is no associated task, then
1494b0dd25a8SRandy Dunlap  * task context (ctx) should be NULL.
1495b0dd25a8SRandy Dunlap  */
14969796fdd8SAl Viro struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
14979ad9ad38SDavid Woodhouse 				     int type)
14981da177e4SLinus Torvalds {
149931975424SPaul Moore 	struct audit_buffer *ab;
15001da177e4SLinus Torvalds 	struct timespec t;
1501ef00be05SAndrew Morton 	unsigned int uninitialized_var(serial);
15021da177e4SLinus Torvalds 
1503a3f07114SEric Paris 	if (audit_initialized != AUDIT_INITIALIZED)
15041da177e4SLinus Torvalds 		return NULL;
15051da177e4SLinus Torvalds 
150686b2efbeSRichard Guy Briggs 	if (unlikely(!audit_filter(type, AUDIT_FILTER_TYPE)))
1507c8edc80cSDustin Kirkland 		return NULL;
1508c8edc80cSDustin Kirkland 
1509a09cfa47SPaul Moore 	/* don't ever fail/sleep on these two conditions:
1510a09cfa47SPaul Moore 	 * 1. auditd generated record - since we need auditd to drain the
151131975424SPaul Moore 	 *    queue; also, when we are checking for auditd, compare PIDs using
1512a09cfa47SPaul Moore 	 *    task_tgid_vnr() since auditd_pid is set in audit_receive_msg()
1513a09cfa47SPaul Moore 	 *    using a PID anchored in the caller's namespace
1514a09cfa47SPaul Moore 	 * 2. audit command message - record types 1000 through 1099 inclusive
1515a09cfa47SPaul Moore 	 *    are command messages/records used to manage the kernel subsystem
1516a09cfa47SPaul Moore 	 *    and the audit userspace, blocking on these messages could cause
1517a09cfa47SPaul Moore 	 *    problems under load so don't do it (note: not all of these
1518a09cfa47SPaul Moore 	 *    command types are valid as record types, but it is quicker to
1519a09cfa47SPaul Moore 	 *    just check two ints than a series of ints in a if/switch stmt) */
1520a09cfa47SPaul Moore 	if (!((audit_pid && audit_pid == task_tgid_vnr(current)) ||
1521a09cfa47SPaul Moore 	      (type >= 1000 && type <= 1099))) {
152231975424SPaul Moore 		long sleep_time = audit_backlog_wait_time;
15239ad9ad38SDavid Woodhouse 
152431975424SPaul Moore 		while (audit_backlog_limit &&
152531975424SPaul Moore 		       (skb_queue_len(&audit_queue) > audit_backlog_limit)) {
152631975424SPaul Moore 			/* wake kauditd to try and flush the queue */
152731975424SPaul Moore 			wake_up_interruptible(&kauditd_wait);
1528ac4cec44SDavid Woodhouse 
152931975424SPaul Moore 			/* sleep if we are allowed and we haven't exhausted our
153031975424SPaul Moore 			 * backlog wait limit */
153131975424SPaul Moore 			if ((gfp_mask & __GFP_DIRECT_RECLAIM) &&
153231975424SPaul Moore 			    (sleep_time > 0)) {
153331975424SPaul Moore 				DECLARE_WAITQUEUE(wait, current);
153431975424SPaul Moore 
153531975424SPaul Moore 				add_wait_queue_exclusive(&audit_backlog_wait,
153631975424SPaul Moore 							 &wait);
153731975424SPaul Moore 				set_current_state(TASK_UNINTERRUPTIBLE);
153831975424SPaul Moore 				sleep_time = schedule_timeout(sleep_time);
153931975424SPaul Moore 				remove_wait_queue(&audit_backlog_wait, &wait);
154031975424SPaul Moore 			} else {
1541320f1b1eSEric Paris 				if (audit_rate_check() && printk_ratelimit())
1542d957f7b7SJoe Perches 					pr_warn("audit_backlog=%d > audit_backlog_limit=%d\n",
1543af8b824fSPaul Moore 						skb_queue_len(&audit_queue),
1544fb19b4c6SDavid Woodhouse 						audit_backlog_limit);
1545fb19b4c6SDavid Woodhouse 				audit_log_lost("backlog limit exceeded");
1546fb19b4c6SDavid Woodhouse 				return NULL;
1547fb19b4c6SDavid Woodhouse 			}
154831975424SPaul Moore 		}
154931975424SPaul Moore 	}
1550e789e561SRichard Guy Briggs 
15519ad9ad38SDavid Woodhouse 	ab = audit_buffer_alloc(ctx, gfp_mask, type);
15521da177e4SLinus Torvalds 	if (!ab) {
15531da177e4SLinus Torvalds 		audit_log_lost("out of memory in audit_log_start");
15541da177e4SLinus Torvalds 		return NULL;
15551da177e4SLinus Torvalds 	}
15561da177e4SLinus Torvalds 
1557bfb4496eSDavid Woodhouse 	audit_get_stamp(ab->ctx, &t, &serial);
15581da177e4SLinus Torvalds 	audit_log_format(ab, "audit(%lu.%03lu:%u): ",
15591da177e4SLinus Torvalds 			 t.tv_sec, t.tv_nsec/1000000, serial);
156031975424SPaul Moore 
15611da177e4SLinus Torvalds 	return ab;
15621da177e4SLinus Torvalds }
15631da177e4SLinus Torvalds 
15648fc6115cSChris Wright /**
15655ac52f33SChris Wright  * audit_expand - expand skb in the audit buffer
15668fc6115cSChris Wright  * @ab: audit_buffer
1567b0dd25a8SRandy Dunlap  * @extra: space to add at tail of the skb
15688fc6115cSChris Wright  *
15698fc6115cSChris Wright  * Returns 0 (no space) on failed expansion, or available space if
15708fc6115cSChris Wright  * successful.
15718fc6115cSChris Wright  */
1572e3b926b4SDavid Woodhouse static inline int audit_expand(struct audit_buffer *ab, int extra)
15738fc6115cSChris Wright {
15745ac52f33SChris Wright 	struct sk_buff *skb = ab->skb;
1575406a1d86SHerbert Xu 	int oldtail = skb_tailroom(skb);
1576406a1d86SHerbert Xu 	int ret = pskb_expand_head(skb, 0, extra, ab->gfp_mask);
1577406a1d86SHerbert Xu 	int newtail = skb_tailroom(skb);
1578406a1d86SHerbert Xu 
15795ac52f33SChris Wright 	if (ret < 0) {
15805ac52f33SChris Wright 		audit_log_lost("out of memory in audit_expand");
15818fc6115cSChris Wright 		return 0;
15825ac52f33SChris Wright 	}
1583406a1d86SHerbert Xu 
1584406a1d86SHerbert Xu 	skb->truesize += newtail - oldtail;
1585406a1d86SHerbert Xu 	return newtail;
15868fc6115cSChris Wright }
15871da177e4SLinus Torvalds 
1588b0dd25a8SRandy Dunlap /*
1589b0dd25a8SRandy Dunlap  * Format an audit message into the audit buffer.  If there isn't enough
15901da177e4SLinus Torvalds  * room in the audit buffer, more room will be allocated and vsnprint
15911da177e4SLinus Torvalds  * will be called a second time.  Currently, we assume that a printk
1592b0dd25a8SRandy Dunlap  * can't format message larger than 1024 bytes, so we don't either.
1593b0dd25a8SRandy Dunlap  */
15941da177e4SLinus Torvalds static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
15951da177e4SLinus Torvalds 			      va_list args)
15961da177e4SLinus Torvalds {
15971da177e4SLinus Torvalds 	int len, avail;
15985ac52f33SChris Wright 	struct sk_buff *skb;
1599eecb0a73SDavid Woodhouse 	va_list args2;
16001da177e4SLinus Torvalds 
16011da177e4SLinus Torvalds 	if (!ab)
16021da177e4SLinus Torvalds 		return;
16031da177e4SLinus Torvalds 
16045ac52f33SChris Wright 	BUG_ON(!ab->skb);
16055ac52f33SChris Wright 	skb = ab->skb;
16065ac52f33SChris Wright 	avail = skb_tailroom(skb);
16075ac52f33SChris Wright 	if (avail == 0) {
1608e3b926b4SDavid Woodhouse 		avail = audit_expand(ab, AUDIT_BUFSIZ);
16098fc6115cSChris Wright 		if (!avail)
16108fc6115cSChris Wright 			goto out;
16111da177e4SLinus Torvalds 	}
1612eecb0a73SDavid Woodhouse 	va_copy(args2, args);
161327a884dcSArnaldo Carvalho de Melo 	len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args);
16141da177e4SLinus Torvalds 	if (len >= avail) {
16151da177e4SLinus Torvalds 		/* The printk buffer is 1024 bytes long, so if we get
16161da177e4SLinus Torvalds 		 * here and AUDIT_BUFSIZ is at least 1024, then we can
16171da177e4SLinus Torvalds 		 * log everything that printk could have logged. */
1618b0dd25a8SRandy Dunlap 		avail = audit_expand(ab,
1619b0dd25a8SRandy Dunlap 			max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
16208fc6115cSChris Wright 		if (!avail)
1621a0e86bd4SJesper Juhl 			goto out_va_end;
162227a884dcSArnaldo Carvalho de Melo 		len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
16231da177e4SLinus Torvalds 	}
1624168b7173SSteve Grubb 	if (len > 0)
1625168b7173SSteve Grubb 		skb_put(skb, len);
1626a0e86bd4SJesper Juhl out_va_end:
1627a0e86bd4SJesper Juhl 	va_end(args2);
16288fc6115cSChris Wright out:
16298fc6115cSChris Wright 	return;
16301da177e4SLinus Torvalds }
16311da177e4SLinus Torvalds 
1632b0dd25a8SRandy Dunlap /**
1633b0dd25a8SRandy Dunlap  * audit_log_format - format a message into the audit buffer.
1634b0dd25a8SRandy Dunlap  * @ab: audit_buffer
1635b0dd25a8SRandy Dunlap  * @fmt: format string
1636b0dd25a8SRandy Dunlap  * @...: optional parameters matching @fmt string
1637b0dd25a8SRandy Dunlap  *
1638b0dd25a8SRandy Dunlap  * All the work is done in audit_log_vformat.
1639b0dd25a8SRandy Dunlap  */
16401da177e4SLinus Torvalds void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)
16411da177e4SLinus Torvalds {
16421da177e4SLinus Torvalds 	va_list args;
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds 	if (!ab)
16451da177e4SLinus Torvalds 		return;
16461da177e4SLinus Torvalds 	va_start(args, fmt);
16471da177e4SLinus Torvalds 	audit_log_vformat(ab, fmt, args);
16481da177e4SLinus Torvalds 	va_end(args);
16491da177e4SLinus Torvalds }
16501da177e4SLinus Torvalds 
1651b0dd25a8SRandy Dunlap /**
1652b0dd25a8SRandy Dunlap  * audit_log_hex - convert a buffer to hex and append it to the audit skb
1653b0dd25a8SRandy Dunlap  * @ab: the audit_buffer
1654b0dd25a8SRandy Dunlap  * @buf: buffer to convert to hex
1655b0dd25a8SRandy Dunlap  * @len: length of @buf to be converted
1656b0dd25a8SRandy Dunlap  *
1657b0dd25a8SRandy Dunlap  * No return value; failure to expand is silently ignored.
1658b0dd25a8SRandy Dunlap  *
1659b0dd25a8SRandy Dunlap  * This function will take the passed buf and convert it into a string of
1660b0dd25a8SRandy Dunlap  * ascii hex digits. The new string is placed onto the skb.
1661b0dd25a8SRandy Dunlap  */
1662b556f8adSEric Paris void audit_log_n_hex(struct audit_buffer *ab, const unsigned char *buf,
1663168b7173SSteve Grubb 		size_t len)
166483c7d091S {
1665168b7173SSteve Grubb 	int i, avail, new_len;
1666168b7173SSteve Grubb 	unsigned char *ptr;
1667168b7173SSteve Grubb 	struct sk_buff *skb;
166883c7d091S 
16698ef2d304SAmy Griffis 	if (!ab)
16708ef2d304SAmy Griffis 		return;
16718ef2d304SAmy Griffis 
1672168b7173SSteve Grubb 	BUG_ON(!ab->skb);
1673168b7173SSteve Grubb 	skb = ab->skb;
1674168b7173SSteve Grubb 	avail = skb_tailroom(skb);
1675168b7173SSteve Grubb 	new_len = len<<1;
1676168b7173SSteve Grubb 	if (new_len >= avail) {
1677168b7173SSteve Grubb 		/* Round the buffer request up to the next multiple */
1678168b7173SSteve Grubb 		new_len = AUDIT_BUFSIZ*(((new_len-avail)/AUDIT_BUFSIZ) + 1);
1679168b7173SSteve Grubb 		avail = audit_expand(ab, new_len);
1680168b7173SSteve Grubb 		if (!avail)
1681168b7173SSteve Grubb 			return;
168283c7d091S 	}
168383c7d091S 
168427a884dcSArnaldo Carvalho de Melo 	ptr = skb_tail_pointer(skb);
1685b8dbc324SJoe Perches 	for (i = 0; i < len; i++)
1686b8dbc324SJoe Perches 		ptr = hex_byte_pack_upper(ptr, buf[i]);
1687168b7173SSteve Grubb 	*ptr = 0;
1688168b7173SSteve Grubb 	skb_put(skb, len << 1); /* new string is twice the old string */
1689168b7173SSteve Grubb }
1690168b7173SSteve Grubb 
16919c937dccSAmy Griffis /*
16929c937dccSAmy Griffis  * Format a string of no more than slen characters into the audit buffer,
16939c937dccSAmy Griffis  * enclosed in quote marks.
16949c937dccSAmy Griffis  */
1695b556f8adSEric Paris void audit_log_n_string(struct audit_buffer *ab, const char *string,
1696b556f8adSEric Paris 			size_t slen)
16979c937dccSAmy Griffis {
16989c937dccSAmy Griffis 	int avail, new_len;
16999c937dccSAmy Griffis 	unsigned char *ptr;
17009c937dccSAmy Griffis 	struct sk_buff *skb;
17019c937dccSAmy Griffis 
17028ef2d304SAmy Griffis 	if (!ab)
17038ef2d304SAmy Griffis 		return;
17048ef2d304SAmy Griffis 
17059c937dccSAmy Griffis 	BUG_ON(!ab->skb);
17069c937dccSAmy Griffis 	skb = ab->skb;
17079c937dccSAmy Griffis 	avail = skb_tailroom(skb);
17089c937dccSAmy Griffis 	new_len = slen + 3;	/* enclosing quotes + null terminator */
17099c937dccSAmy Griffis 	if (new_len > avail) {
17109c937dccSAmy Griffis 		avail = audit_expand(ab, new_len);
17119c937dccSAmy Griffis 		if (!avail)
17129c937dccSAmy Griffis 			return;
17139c937dccSAmy Griffis 	}
171427a884dcSArnaldo Carvalho de Melo 	ptr = skb_tail_pointer(skb);
17159c937dccSAmy Griffis 	*ptr++ = '"';
17169c937dccSAmy Griffis 	memcpy(ptr, string, slen);
17179c937dccSAmy Griffis 	ptr += slen;
17189c937dccSAmy Griffis 	*ptr++ = '"';
17199c937dccSAmy Griffis 	*ptr = 0;
17209c937dccSAmy Griffis 	skb_put(skb, slen + 2);	/* don't include null terminator */
17219c937dccSAmy Griffis }
17229c937dccSAmy Griffis 
1723b0dd25a8SRandy Dunlap /**
1724de6bbd1dSEric Paris  * audit_string_contains_control - does a string need to be logged in hex
1725f706d5d2SDave Jones  * @string: string to be checked
1726f706d5d2SDave Jones  * @len: max length of the string to check
1727de6bbd1dSEric Paris  */
17289fcf836bSYaowei Bai bool audit_string_contains_control(const char *string, size_t len)
1729de6bbd1dSEric Paris {
1730de6bbd1dSEric Paris 	const unsigned char *p;
1731b3897f56SMiloslav Trmac 	for (p = string; p < (const unsigned char *)string + len; p++) {
17321d6c9649SVesa-Matti J Kari 		if (*p == '"' || *p < 0x21 || *p > 0x7e)
17339fcf836bSYaowei Bai 			return true;
1734de6bbd1dSEric Paris 	}
17359fcf836bSYaowei Bai 	return false;
1736de6bbd1dSEric Paris }
1737de6bbd1dSEric Paris 
1738de6bbd1dSEric Paris /**
1739522ed776SMiloslav Trmac  * audit_log_n_untrustedstring - log a string that may contain random characters
1740b0dd25a8SRandy Dunlap  * @ab: audit_buffer
1741f706d5d2SDave Jones  * @len: length of string (not including trailing null)
1742b0dd25a8SRandy Dunlap  * @string: string to be logged
1743b0dd25a8SRandy Dunlap  *
1744b0dd25a8SRandy Dunlap  * This code will escape a string that is passed to it if the string
1745168b7173SSteve Grubb  * contains a control character, unprintable character, double quote mark,
1746168b7173SSteve Grubb  * or a space. Unescaped strings will start and end with a double quote mark.
1747b0dd25a8SRandy Dunlap  * Strings that are escaped are printed in hex (2 digits per char).
17489c937dccSAmy Griffis  *
17499c937dccSAmy Griffis  * The caller specifies the number of characters in the string to log, which may
17509c937dccSAmy Griffis  * or may not be the entire string.
1751b0dd25a8SRandy Dunlap  */
1752b556f8adSEric Paris void audit_log_n_untrustedstring(struct audit_buffer *ab, const char *string,
1753b556f8adSEric Paris 				 size_t len)
175483c7d091S {
1755de6bbd1dSEric Paris 	if (audit_string_contains_control(string, len))
1756b556f8adSEric Paris 		audit_log_n_hex(ab, string, len);
1757de6bbd1dSEric Paris 	else
1758b556f8adSEric Paris 		audit_log_n_string(ab, string, len);
175983c7d091S }
176083c7d091S 
17619c937dccSAmy Griffis /**
1762522ed776SMiloslav Trmac  * audit_log_untrustedstring - log a string that may contain random characters
17639c937dccSAmy Griffis  * @ab: audit_buffer
17649c937dccSAmy Griffis  * @string: string to be logged
17659c937dccSAmy Griffis  *
1766522ed776SMiloslav Trmac  * Same as audit_log_n_untrustedstring(), except that strlen is used to
17679c937dccSAmy Griffis  * determine string length.
17689c937dccSAmy Griffis  */
1769de6bbd1dSEric Paris void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
17709c937dccSAmy Griffis {
1771b556f8adSEric Paris 	audit_log_n_untrustedstring(ab, string, strlen(string));
17729c937dccSAmy Griffis }
17739c937dccSAmy Griffis 
1774168b7173SSteve Grubb /* This is a helper-function to print the escaped d_path */
17751da177e4SLinus Torvalds void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
177666b3fad3SAl Viro 		      const struct path *path)
17771da177e4SLinus Torvalds {
177844707fdfSJan Blunck 	char *p, *pathname;
17791da177e4SLinus Torvalds 
17808fc6115cSChris Wright 	if (prefix)
17818fc6115cSChris Wright 		audit_log_format(ab, "%s", prefix);
17821da177e4SLinus Torvalds 
1783168b7173SSteve Grubb 	/* We will allow 11 spaces for ' (deleted)' to be appended */
178444707fdfSJan Blunck 	pathname = kmalloc(PATH_MAX+11, ab->gfp_mask);
178544707fdfSJan Blunck 	if (!pathname) {
1786def57543SEric Paris 		audit_log_string(ab, "<no_memory>");
1787168b7173SSteve Grubb 		return;
1788168b7173SSteve Grubb 	}
1789cf28b486SJan Blunck 	p = d_path(path, pathname, PATH_MAX+11);
1790168b7173SSteve Grubb 	if (IS_ERR(p)) { /* Should never happen since we send PATH_MAX */
17911da177e4SLinus Torvalds 		/* FIXME: can we save some information here? */
1792def57543SEric Paris 		audit_log_string(ab, "<too_long>");
1793168b7173SSteve Grubb 	} else
1794168b7173SSteve Grubb 		audit_log_untrustedstring(ab, p);
179544707fdfSJan Blunck 	kfree(pathname);
17961da177e4SLinus Torvalds }
17971da177e4SLinus Torvalds 
17984d3fb709SEric Paris void audit_log_session_info(struct audit_buffer *ab)
17994d3fb709SEric Paris {
18004440e854SEric Paris 	unsigned int sessionid = audit_get_sessionid(current);
18014d3fb709SEric Paris 	uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
18024d3fb709SEric Paris 
1803b8f89caaSRichard Guy Briggs 	audit_log_format(ab, " auid=%u ses=%u", auid, sessionid);
18044d3fb709SEric Paris }
18054d3fb709SEric Paris 
18069d960985SEric Paris void audit_log_key(struct audit_buffer *ab, char *key)
18079d960985SEric Paris {
18089d960985SEric Paris 	audit_log_format(ab, " key=");
18099d960985SEric Paris 	if (key)
18109d960985SEric Paris 		audit_log_untrustedstring(ab, key);
18119d960985SEric Paris 	else
18129d960985SEric Paris 		audit_log_format(ab, "(null)");
18139d960985SEric Paris }
18149d960985SEric Paris 
1815b24a30a7SEric Paris void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
1816b24a30a7SEric Paris {
1817b24a30a7SEric Paris 	int i;
1818b24a30a7SEric Paris 
1819b24a30a7SEric Paris 	audit_log_format(ab, " %s=", prefix);
1820b24a30a7SEric Paris 	CAP_FOR_EACH_U32(i) {
1821b24a30a7SEric Paris 		audit_log_format(ab, "%08x",
18227d8b6c63SEric Paris 				 cap->cap[CAP_LAST_U32 - i]);
1823b24a30a7SEric Paris 	}
1824b24a30a7SEric Paris }
1825b24a30a7SEric Paris 
1826691e6d59SRichard Guy Briggs static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
1827b24a30a7SEric Paris {
1828b24a30a7SEric Paris 	kernel_cap_t *perm = &name->fcap.permitted;
1829b24a30a7SEric Paris 	kernel_cap_t *inh = &name->fcap.inheritable;
1830b24a30a7SEric Paris 	int log = 0;
1831b24a30a7SEric Paris 
1832b24a30a7SEric Paris 	if (!cap_isclear(*perm)) {
1833b24a30a7SEric Paris 		audit_log_cap(ab, "cap_fp", perm);
1834b24a30a7SEric Paris 		log = 1;
1835b24a30a7SEric Paris 	}
1836b24a30a7SEric Paris 	if (!cap_isclear(*inh)) {
1837b24a30a7SEric Paris 		audit_log_cap(ab, "cap_fi", inh);
1838b24a30a7SEric Paris 		log = 1;
1839b24a30a7SEric Paris 	}
1840b24a30a7SEric Paris 
1841b24a30a7SEric Paris 	if (log)
1842b24a30a7SEric Paris 		audit_log_format(ab, " cap_fe=%d cap_fver=%x",
1843b24a30a7SEric Paris 				 name->fcap.fE, name->fcap_ver);
1844b24a30a7SEric Paris }
1845b24a30a7SEric Paris 
1846b24a30a7SEric Paris static inline int audit_copy_fcaps(struct audit_names *name,
1847b24a30a7SEric Paris 				   const struct dentry *dentry)
1848b24a30a7SEric Paris {
1849b24a30a7SEric Paris 	struct cpu_vfs_cap_data caps;
1850b24a30a7SEric Paris 	int rc;
1851b24a30a7SEric Paris 
1852b24a30a7SEric Paris 	if (!dentry)
1853b24a30a7SEric Paris 		return 0;
1854b24a30a7SEric Paris 
1855b24a30a7SEric Paris 	rc = get_vfs_caps_from_disk(dentry, &caps);
1856b24a30a7SEric Paris 	if (rc)
1857b24a30a7SEric Paris 		return rc;
1858b24a30a7SEric Paris 
1859b24a30a7SEric Paris 	name->fcap.permitted = caps.permitted;
1860b24a30a7SEric Paris 	name->fcap.inheritable = caps.inheritable;
1861b24a30a7SEric Paris 	name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
1862b24a30a7SEric Paris 	name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >>
1863b24a30a7SEric Paris 				VFS_CAP_REVISION_SHIFT;
1864b24a30a7SEric Paris 
1865b24a30a7SEric Paris 	return 0;
1866b24a30a7SEric Paris }
1867b24a30a7SEric Paris 
1868b24a30a7SEric Paris /* Copy inode data into an audit_names. */
1869b24a30a7SEric Paris void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
1870d6335d77SAndreas Gruenbacher 		      struct inode *inode)
1871b24a30a7SEric Paris {
1872b24a30a7SEric Paris 	name->ino   = inode->i_ino;
1873b24a30a7SEric Paris 	name->dev   = inode->i_sb->s_dev;
1874b24a30a7SEric Paris 	name->mode  = inode->i_mode;
1875b24a30a7SEric Paris 	name->uid   = inode->i_uid;
1876b24a30a7SEric Paris 	name->gid   = inode->i_gid;
1877b24a30a7SEric Paris 	name->rdev  = inode->i_rdev;
1878b24a30a7SEric Paris 	security_inode_getsecid(inode, &name->osid);
1879b24a30a7SEric Paris 	audit_copy_fcaps(name, dentry);
1880b24a30a7SEric Paris }
1881b24a30a7SEric Paris 
1882b24a30a7SEric Paris /**
1883b24a30a7SEric Paris  * audit_log_name - produce AUDIT_PATH record from struct audit_names
1884b24a30a7SEric Paris  * @context: audit_context for the task
1885b24a30a7SEric Paris  * @n: audit_names structure with reportable details
1886b24a30a7SEric Paris  * @path: optional path to report instead of audit_names->name
1887b24a30a7SEric Paris  * @record_num: record number to report when handling a list of names
1888b24a30a7SEric Paris  * @call_panic: optional pointer to int that will be updated if secid fails
1889b24a30a7SEric Paris  */
1890b24a30a7SEric Paris void audit_log_name(struct audit_context *context, struct audit_names *n,
1891b24a30a7SEric Paris 		    struct path *path, int record_num, int *call_panic)
1892b24a30a7SEric Paris {
1893b24a30a7SEric Paris 	struct audit_buffer *ab;
1894b24a30a7SEric Paris 	ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
1895b24a30a7SEric Paris 	if (!ab)
1896b24a30a7SEric Paris 		return;
1897b24a30a7SEric Paris 
1898b24a30a7SEric Paris 	audit_log_format(ab, "item=%d", record_num);
1899b24a30a7SEric Paris 
1900b24a30a7SEric Paris 	if (path)
1901b24a30a7SEric Paris 		audit_log_d_path(ab, " name=", path);
1902b24a30a7SEric Paris 	else if (n->name) {
1903b24a30a7SEric Paris 		switch (n->name_len) {
1904b24a30a7SEric Paris 		case AUDIT_NAME_FULL:
1905b24a30a7SEric Paris 			/* log the full path */
1906b24a30a7SEric Paris 			audit_log_format(ab, " name=");
1907b24a30a7SEric Paris 			audit_log_untrustedstring(ab, n->name->name);
1908b24a30a7SEric Paris 			break;
1909b24a30a7SEric Paris 		case 0:
1910b24a30a7SEric Paris 			/* name was specified as a relative path and the
1911b24a30a7SEric Paris 			 * directory component is the cwd */
1912b24a30a7SEric Paris 			audit_log_d_path(ab, " name=", &context->pwd);
1913b24a30a7SEric Paris 			break;
1914b24a30a7SEric Paris 		default:
1915b24a30a7SEric Paris 			/* log the name's directory component */
1916b24a30a7SEric Paris 			audit_log_format(ab, " name=");
1917b24a30a7SEric Paris 			audit_log_n_untrustedstring(ab, n->name->name,
1918b24a30a7SEric Paris 						    n->name_len);
1919b24a30a7SEric Paris 		}
1920b24a30a7SEric Paris 	} else
1921b24a30a7SEric Paris 		audit_log_format(ab, " name=(null)");
1922b24a30a7SEric Paris 
1923425afcffSLinus Torvalds 	if (n->ino != AUDIT_INO_UNSET)
1924b24a30a7SEric Paris 		audit_log_format(ab, " inode=%lu"
1925b24a30a7SEric Paris 				 " dev=%02x:%02x mode=%#ho"
1926b24a30a7SEric Paris 				 " ouid=%u ogid=%u rdev=%02x:%02x",
1927b24a30a7SEric Paris 				 n->ino,
1928b24a30a7SEric Paris 				 MAJOR(n->dev),
1929b24a30a7SEric Paris 				 MINOR(n->dev),
1930b24a30a7SEric Paris 				 n->mode,
1931b24a30a7SEric Paris 				 from_kuid(&init_user_ns, n->uid),
1932b24a30a7SEric Paris 				 from_kgid(&init_user_ns, n->gid),
1933b24a30a7SEric Paris 				 MAJOR(n->rdev),
1934b24a30a7SEric Paris 				 MINOR(n->rdev));
1935b24a30a7SEric Paris 	if (n->osid != 0) {
1936b24a30a7SEric Paris 		char *ctx = NULL;
1937b24a30a7SEric Paris 		u32 len;
1938b24a30a7SEric Paris 		if (security_secid_to_secctx(
1939b24a30a7SEric Paris 			n->osid, &ctx, &len)) {
1940b24a30a7SEric Paris 			audit_log_format(ab, " osid=%u", n->osid);
1941b24a30a7SEric Paris 			if (call_panic)
1942b24a30a7SEric Paris 				*call_panic = 2;
1943b24a30a7SEric Paris 		} else {
1944b24a30a7SEric Paris 			audit_log_format(ab, " obj=%s", ctx);
1945b24a30a7SEric Paris 			security_release_secctx(ctx, len);
1946b24a30a7SEric Paris 		}
1947b24a30a7SEric Paris 	}
1948b24a30a7SEric Paris 
1949d3aea84aSJeff Layton 	/* log the audit_names record type */
1950d3aea84aSJeff Layton 	audit_log_format(ab, " nametype=");
1951d3aea84aSJeff Layton 	switch(n->type) {
1952d3aea84aSJeff Layton 	case AUDIT_TYPE_NORMAL:
1953d3aea84aSJeff Layton 		audit_log_format(ab, "NORMAL");
1954d3aea84aSJeff Layton 		break;
1955d3aea84aSJeff Layton 	case AUDIT_TYPE_PARENT:
1956d3aea84aSJeff Layton 		audit_log_format(ab, "PARENT");
1957d3aea84aSJeff Layton 		break;
1958d3aea84aSJeff Layton 	case AUDIT_TYPE_CHILD_DELETE:
1959d3aea84aSJeff Layton 		audit_log_format(ab, "DELETE");
1960d3aea84aSJeff Layton 		break;
1961d3aea84aSJeff Layton 	case AUDIT_TYPE_CHILD_CREATE:
1962d3aea84aSJeff Layton 		audit_log_format(ab, "CREATE");
1963d3aea84aSJeff Layton 		break;
1964d3aea84aSJeff Layton 	default:
1965d3aea84aSJeff Layton 		audit_log_format(ab, "UNKNOWN");
1966d3aea84aSJeff Layton 		break;
1967d3aea84aSJeff Layton 	}
1968d3aea84aSJeff Layton 
1969b24a30a7SEric Paris 	audit_log_fcaps(ab, n);
1970b24a30a7SEric Paris 	audit_log_end(ab);
1971b24a30a7SEric Paris }
1972b24a30a7SEric Paris 
1973b24a30a7SEric Paris int audit_log_task_context(struct audit_buffer *ab)
1974b24a30a7SEric Paris {
1975b24a30a7SEric Paris 	char *ctx = NULL;
1976b24a30a7SEric Paris 	unsigned len;
1977b24a30a7SEric Paris 	int error;
1978b24a30a7SEric Paris 	u32 sid;
1979b24a30a7SEric Paris 
1980b24a30a7SEric Paris 	security_task_getsecid(current, &sid);
1981b24a30a7SEric Paris 	if (!sid)
1982b24a30a7SEric Paris 		return 0;
1983b24a30a7SEric Paris 
1984b24a30a7SEric Paris 	error = security_secid_to_secctx(sid, &ctx, &len);
1985b24a30a7SEric Paris 	if (error) {
1986b24a30a7SEric Paris 		if (error != -EINVAL)
1987b24a30a7SEric Paris 			goto error_path;
1988b24a30a7SEric Paris 		return 0;
1989b24a30a7SEric Paris 	}
1990b24a30a7SEric Paris 
1991b24a30a7SEric Paris 	audit_log_format(ab, " subj=%s", ctx);
1992b24a30a7SEric Paris 	security_release_secctx(ctx, len);
1993b24a30a7SEric Paris 	return 0;
1994b24a30a7SEric Paris 
1995b24a30a7SEric Paris error_path:
1996b24a30a7SEric Paris 	audit_panic("error in audit_log_task_context");
1997b24a30a7SEric Paris 	return error;
1998b24a30a7SEric Paris }
1999b24a30a7SEric Paris EXPORT_SYMBOL(audit_log_task_context);
2000b24a30a7SEric Paris 
20014766b199SDavidlohr Bueso void audit_log_d_path_exe(struct audit_buffer *ab,
20024766b199SDavidlohr Bueso 			  struct mm_struct *mm)
20034766b199SDavidlohr Bueso {
20045b282552SDavidlohr Bueso 	struct file *exe_file;
20054766b199SDavidlohr Bueso 
20065b282552SDavidlohr Bueso 	if (!mm)
20075b282552SDavidlohr Bueso 		goto out_null;
20085b282552SDavidlohr Bueso 
20095b282552SDavidlohr Bueso 	exe_file = get_mm_exe_file(mm);
20105b282552SDavidlohr Bueso 	if (!exe_file)
20115b282552SDavidlohr Bueso 		goto out_null;
20125b282552SDavidlohr Bueso 
20135b282552SDavidlohr Bueso 	audit_log_d_path(ab, " exe=", &exe_file->f_path);
20145b282552SDavidlohr Bueso 	fput(exe_file);
20155b282552SDavidlohr Bueso 	return;
20165b282552SDavidlohr Bueso out_null:
20175b282552SDavidlohr Bueso 	audit_log_format(ab, " exe=(null)");
20184766b199SDavidlohr Bueso }
20194766b199SDavidlohr Bueso 
20203f5be2daSRichard Guy Briggs struct tty_struct *audit_get_tty(struct task_struct *tsk)
20213f5be2daSRichard Guy Briggs {
20223f5be2daSRichard Guy Briggs 	struct tty_struct *tty = NULL;
20233f5be2daSRichard Guy Briggs 	unsigned long flags;
20243f5be2daSRichard Guy Briggs 
20253f5be2daSRichard Guy Briggs 	spin_lock_irqsave(&tsk->sighand->siglock, flags);
20263f5be2daSRichard Guy Briggs 	if (tsk->signal)
20273f5be2daSRichard Guy Briggs 		tty = tty_kref_get(tsk->signal->tty);
20283f5be2daSRichard Guy Briggs 	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
20293f5be2daSRichard Guy Briggs 	return tty;
20303f5be2daSRichard Guy Briggs }
20313f5be2daSRichard Guy Briggs 
20323f5be2daSRichard Guy Briggs void audit_put_tty(struct tty_struct *tty)
20333f5be2daSRichard Guy Briggs {
20343f5be2daSRichard Guy Briggs 	tty_kref_put(tty);
20353f5be2daSRichard Guy Briggs }
20363f5be2daSRichard Guy Briggs 
2037b24a30a7SEric Paris void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
2038b24a30a7SEric Paris {
2039b24a30a7SEric Paris 	const struct cred *cred;
20409eab339bSRichard Guy Briggs 	char comm[sizeof(tsk->comm)];
2041db0a6fb5SRichard Guy Briggs 	struct tty_struct *tty;
2042b24a30a7SEric Paris 
2043b24a30a7SEric Paris 	if (!ab)
2044b24a30a7SEric Paris 		return;
2045b24a30a7SEric Paris 
2046b24a30a7SEric Paris 	/* tsk == current */
2047b24a30a7SEric Paris 	cred = current_cred();
2048db0a6fb5SRichard Guy Briggs 	tty = audit_get_tty(tsk);
2049b24a30a7SEric Paris 	audit_log_format(ab,
2050c92cdeb4SRichard Guy Briggs 			 " ppid=%d pid=%d auid=%u uid=%u gid=%u"
2051b24a30a7SEric Paris 			 " euid=%u suid=%u fsuid=%u"
20522f2ad101SRichard Guy Briggs 			 " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
2053c92cdeb4SRichard Guy Briggs 			 task_ppid_nr(tsk),
2054f1dc4867SRichard Guy Briggs 			 task_pid_nr(tsk),
2055b24a30a7SEric Paris 			 from_kuid(&init_user_ns, audit_get_loginuid(tsk)),
2056b24a30a7SEric Paris 			 from_kuid(&init_user_ns, cred->uid),
2057b24a30a7SEric Paris 			 from_kgid(&init_user_ns, cred->gid),
2058b24a30a7SEric Paris 			 from_kuid(&init_user_ns, cred->euid),
2059b24a30a7SEric Paris 			 from_kuid(&init_user_ns, cred->suid),
2060b24a30a7SEric Paris 			 from_kuid(&init_user_ns, cred->fsuid),
2061b24a30a7SEric Paris 			 from_kgid(&init_user_ns, cred->egid),
2062b24a30a7SEric Paris 			 from_kgid(&init_user_ns, cred->sgid),
2063b24a30a7SEric Paris 			 from_kgid(&init_user_ns, cred->fsgid),
2064db0a6fb5SRichard Guy Briggs 			 tty ? tty_name(tty) : "(none)",
2065db0a6fb5SRichard Guy Briggs 			 audit_get_sessionid(tsk));
2066db0a6fb5SRichard Guy Briggs 	audit_put_tty(tty);
2067b24a30a7SEric Paris 	audit_log_format(ab, " comm=");
20689eab339bSRichard Guy Briggs 	audit_log_untrustedstring(ab, get_task_comm(comm, tsk));
20694766b199SDavidlohr Bueso 	audit_log_d_path_exe(ab, tsk->mm);
2070b24a30a7SEric Paris 	audit_log_task_context(ab);
2071b24a30a7SEric Paris }
2072b24a30a7SEric Paris EXPORT_SYMBOL(audit_log_task_info);
2073b24a30a7SEric Paris 
2074b0dd25a8SRandy Dunlap /**
2075a51d9eaaSKees Cook  * audit_log_link_denied - report a link restriction denial
207622011964SShailendra Verma  * @operation: specific link operation
2077a51d9eaaSKees Cook  * @link: the path that triggered the restriction
2078a51d9eaaSKees Cook  */
2079a51d9eaaSKees Cook void audit_log_link_denied(const char *operation, struct path *link)
2080a51d9eaaSKees Cook {
2081a51d9eaaSKees Cook 	struct audit_buffer *ab;
2082b24a30a7SEric Paris 	struct audit_names *name;
2083a51d9eaaSKees Cook 
2084b24a30a7SEric Paris 	name = kzalloc(sizeof(*name), GFP_NOFS);
2085b24a30a7SEric Paris 	if (!name)
2086b24a30a7SEric Paris 		return;
2087b24a30a7SEric Paris 
2088b24a30a7SEric Paris 	/* Generate AUDIT_ANOM_LINK with subject, operation, outcome. */
2089a51d9eaaSKees Cook 	ab = audit_log_start(current->audit_context, GFP_KERNEL,
2090a51d9eaaSKees Cook 			     AUDIT_ANOM_LINK);
2091d1c7d97aSSasha Levin 	if (!ab)
2092b24a30a7SEric Paris 		goto out;
2093b24a30a7SEric Paris 	audit_log_format(ab, "op=%s", operation);
2094b24a30a7SEric Paris 	audit_log_task_info(ab, current);
2095b24a30a7SEric Paris 	audit_log_format(ab, " res=0");
2096a51d9eaaSKees Cook 	audit_log_end(ab);
2097b24a30a7SEric Paris 
2098b24a30a7SEric Paris 	/* Generate AUDIT_PATH record with object. */
2099b24a30a7SEric Paris 	name->type = AUDIT_TYPE_NORMAL;
21003b362157SDavid Howells 	audit_copy_inode(name, link->dentry, d_backing_inode(link->dentry));
2101b24a30a7SEric Paris 	audit_log_name(current->audit_context, name, link, 0, NULL);
2102b24a30a7SEric Paris out:
2103b24a30a7SEric Paris 	kfree(name);
2104a51d9eaaSKees Cook }
2105a51d9eaaSKees Cook 
2106a51d9eaaSKees Cook /**
2107b0dd25a8SRandy Dunlap  * audit_log_end - end one audit record
2108b0dd25a8SRandy Dunlap  * @ab: the audit_buffer
2109b0dd25a8SRandy Dunlap  *
21104aa83872SPaul Moore  * We can not do a netlink send inside an irq context because it blocks (last
21114aa83872SPaul Moore  * arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed on a
21124aa83872SPaul Moore  * queue and a tasklet is scheduled to remove them from the queue outside the
21134aa83872SPaul Moore  * irq context.  May be called in any context.
2114b0dd25a8SRandy Dunlap  */
2115b7d11258SDavid Woodhouse void audit_log_end(struct audit_buffer *ab)
21161da177e4SLinus Torvalds {
21171da177e4SLinus Torvalds 	if (!ab)
21181da177e4SLinus Torvalds 		return;
21191da177e4SLinus Torvalds 	if (!audit_rate_check()) {
21201da177e4SLinus Torvalds 		audit_log_lost("rate limit exceeded");
21211da177e4SLinus Torvalds 	} else {
2122af8b824fSPaul Moore 		skb_queue_tail(&audit_queue, ab->skb);
2123b7d11258SDavid Woodhouse 		wake_up_interruptible(&kauditd_wait);
2124f3d357b0SEric Paris 		ab->skb = NULL;
21251da177e4SLinus Torvalds 	}
212616e1904eSChris Wright 	audit_buffer_free(ab);
21271da177e4SLinus Torvalds }
21281da177e4SLinus Torvalds 
2129b0dd25a8SRandy Dunlap /**
2130b0dd25a8SRandy Dunlap  * audit_log - Log an audit record
2131b0dd25a8SRandy Dunlap  * @ctx: audit context
2132b0dd25a8SRandy Dunlap  * @gfp_mask: type of allocation
2133b0dd25a8SRandy Dunlap  * @type: audit message type
2134b0dd25a8SRandy Dunlap  * @fmt: format string to use
2135b0dd25a8SRandy Dunlap  * @...: variable parameters matching the format string
2136b0dd25a8SRandy Dunlap  *
2137b0dd25a8SRandy Dunlap  * This is a convenience function that calls audit_log_start,
2138b0dd25a8SRandy Dunlap  * audit_log_vformat, and audit_log_end.  It may be called
2139b0dd25a8SRandy Dunlap  * in any context.
2140b0dd25a8SRandy Dunlap  */
21419796fdd8SAl Viro void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
21429ad9ad38SDavid Woodhouse 	       const char *fmt, ...)
21431da177e4SLinus Torvalds {
21441da177e4SLinus Torvalds 	struct audit_buffer *ab;
21451da177e4SLinus Torvalds 	va_list args;
21461da177e4SLinus Torvalds 
21479ad9ad38SDavid Woodhouse 	ab = audit_log_start(ctx, gfp_mask, type);
21481da177e4SLinus Torvalds 	if (ab) {
21491da177e4SLinus Torvalds 		va_start(args, fmt);
21501da177e4SLinus Torvalds 		audit_log_vformat(ab, fmt, args);
21511da177e4SLinus Torvalds 		va_end(args);
21521da177e4SLinus Torvalds 		audit_log_end(ab);
21531da177e4SLinus Torvalds 	}
21541da177e4SLinus Torvalds }
2155bf45da97Slorenzo@gnu.org 
2156131ad62dSMr Dash Four #ifdef CONFIG_SECURITY
2157131ad62dSMr Dash Four /**
2158131ad62dSMr Dash Four  * audit_log_secctx - Converts and logs SELinux context
2159131ad62dSMr Dash Four  * @ab: audit_buffer
2160131ad62dSMr Dash Four  * @secid: security number
2161131ad62dSMr Dash Four  *
2162131ad62dSMr Dash Four  * This is a helper function that calls security_secid_to_secctx to convert
2163131ad62dSMr Dash Four  * secid to secctx and then adds the (converted) SELinux context to the audit
2164131ad62dSMr Dash Four  * log by calling audit_log_format, thus also preventing leak of internal secid
2165131ad62dSMr Dash Four  * to userspace. If secid cannot be converted audit_panic is called.
2166131ad62dSMr Dash Four  */
2167131ad62dSMr Dash Four void audit_log_secctx(struct audit_buffer *ab, u32 secid)
2168131ad62dSMr Dash Four {
2169131ad62dSMr Dash Four 	u32 len;
2170131ad62dSMr Dash Four 	char *secctx;
2171131ad62dSMr Dash Four 
2172131ad62dSMr Dash Four 	if (security_secid_to_secctx(secid, &secctx, &len)) {
2173131ad62dSMr Dash Four 		audit_panic("Cannot convert secid to context");
2174131ad62dSMr Dash Four 	} else {
2175131ad62dSMr Dash Four 		audit_log_format(ab, " obj=%s", secctx);
2176131ad62dSMr Dash Four 		security_release_secctx(secctx, len);
2177131ad62dSMr Dash Four 	}
2178131ad62dSMr Dash Four }
2179131ad62dSMr Dash Four EXPORT_SYMBOL(audit_log_secctx);
2180131ad62dSMr Dash Four #endif
2181131ad62dSMr Dash Four 
2182bf45da97Slorenzo@gnu.org EXPORT_SYMBOL(audit_log_start);
2183bf45da97Slorenzo@gnu.org EXPORT_SYMBOL(audit_log_end);
2184bf45da97Slorenzo@gnu.org EXPORT_SYMBOL(audit_log_format);
2185bf45da97Slorenzo@gnu.org EXPORT_SYMBOL(audit_log);
2186