• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Creating audit events from TTY input.
3  *
4  * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
5  * material is made available to anyone wishing to use, modify, copy, or
6  * redistribute it subject to the terms and conditions of the GNU General
7  * Public License v.2.
8  *
9  * Authors: Miloslav Trmac <mitr@redhat.com>
10  */
11 
12 #include <linux/audit.h>
13 #include <linux/file.h>
14 #include <linux/fdtable.h>
15 #include <linux/tty.h>
16 
17 struct tty_audit_buf {
18 	atomic_t count;
19 	struct mutex mutex;	/* Protects all data below */
20 	int major, minor;	/* The TTY which the data is from */
21 	unsigned icanon:1;
22 	size_t valid;
23 	unsigned char *data;	/* Allocated size N_TTY_BUF_SIZE */
24 };
25 
tty_audit_buf_alloc(int major,int minor,int icanon)26 static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
27 						 int icanon)
28 {
29 	struct tty_audit_buf *buf;
30 
31 	buf = kmalloc(sizeof(*buf), GFP_KERNEL);
32 	if (!buf)
33 		goto err;
34 	if (PAGE_SIZE != N_TTY_BUF_SIZE)
35 		buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
36 	else
37 		buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
38 	if (!buf->data)
39 		goto err_buf;
40 	atomic_set(&buf->count, 1);
41 	mutex_init(&buf->mutex);
42 	buf->major = major;
43 	buf->minor = minor;
44 	buf->icanon = icanon;
45 	buf->valid = 0;
46 	return buf;
47 
48 err_buf:
49 	kfree(buf);
50 err:
51 	return NULL;
52 }
53 
tty_audit_buf_free(struct tty_audit_buf * buf)54 static void tty_audit_buf_free(struct tty_audit_buf *buf)
55 {
56 	WARN_ON(buf->valid != 0);
57 	if (PAGE_SIZE != N_TTY_BUF_SIZE)
58 		kfree(buf->data);
59 	else
60 		free_page((unsigned long)buf->data);
61 	kfree(buf);
62 }
63 
tty_audit_buf_put(struct tty_audit_buf * buf)64 static void tty_audit_buf_put(struct tty_audit_buf *buf)
65 {
66 	if (atomic_dec_and_test(&buf->count))
67 		tty_audit_buf_free(buf);
68 }
69 
tty_audit_log(const char * description,struct task_struct * tsk,uid_t loginuid,unsigned sessionid,int major,int minor,unsigned char * data,size_t size)70 static void tty_audit_log(const char *description, struct task_struct *tsk,
71 			  uid_t loginuid, unsigned sessionid, int major,
72 			  int minor, unsigned char *data, size_t size)
73 {
74 	struct audit_buffer *ab;
75 
76 	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
77 	if (ab) {
78 		char name[sizeof(tsk->comm)];
79 		uid_t uid = task_uid(tsk);
80 
81 		audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
82 				 "major=%d minor=%d comm=", description,
83 				 tsk->pid, uid, loginuid, sessionid,
84 				 major, minor);
85 		get_task_comm(name, tsk);
86 		audit_log_untrustedstring(ab, name);
87 		audit_log_format(ab, " data=");
88 		audit_log_n_hex(ab, data, size);
89 		audit_log_end(ab);
90 	}
91 }
92 
93 /**
94  *	tty_audit_buf_push	-	Push buffered data out
95  *
96  *	Generate an audit message from the contents of @buf, which is owned by
97  *	@tsk with @loginuid.  @buf->mutex must be locked.
98  */
tty_audit_buf_push(struct task_struct * tsk,uid_t loginuid,unsigned int sessionid,struct tty_audit_buf * buf)99 static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
100 			       unsigned int sessionid,
101 			       struct tty_audit_buf *buf)
102 {
103 	if (buf->valid == 0)
104 		return;
105 	if (audit_enabled == 0)
106 		return;
107 	tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
108 		      buf->data, buf->valid);
109 	buf->valid = 0;
110 }
111 
112 /**
113  *	tty_audit_buf_push_current	-	Push buffered data out
114  *
115  *	Generate an audit message from the contents of @buf, which is owned by
116  *	the current task.  @buf->mutex must be locked.
117  */
tty_audit_buf_push_current(struct tty_audit_buf * buf)118 static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
119 {
120 	uid_t auid = audit_get_loginuid(current);
121 	unsigned int sessionid = audit_get_sessionid(current);
122 	tty_audit_buf_push(current, auid, sessionid, buf);
123 }
124 
125 /**
126  *	tty_audit_exit	-	Handle a task exit
127  *
128  *	Make sure all buffered data is written out and deallocate the buffer.
129  *	Only needs to be called if current->signal->tty_audit_buf != %NULL.
130  */
tty_audit_exit(void)131 void tty_audit_exit(void)
132 {
133 	struct tty_audit_buf *buf;
134 
135 	spin_lock_irq(&current->sighand->siglock);
136 	buf = current->signal->tty_audit_buf;
137 	current->signal->tty_audit_buf = NULL;
138 	spin_unlock_irq(&current->sighand->siglock);
139 	if (!buf)
140 		return;
141 
142 	mutex_lock(&buf->mutex);
143 	tty_audit_buf_push_current(buf);
144 	mutex_unlock(&buf->mutex);
145 
146 	tty_audit_buf_put(buf);
147 }
148 
149 /**
150  *	tty_audit_fork	-	Copy TTY audit state for a new task
151  *
152  *	Set up TTY audit state in @sig from current.  @sig needs no locking.
153  */
tty_audit_fork(struct signal_struct * sig)154 void tty_audit_fork(struct signal_struct *sig)
155 {
156 	spin_lock_irq(&current->sighand->siglock);
157 	sig->audit_tty = current->signal->audit_tty;
158 	spin_unlock_irq(&current->sighand->siglock);
159 	sig->tty_audit_buf = NULL;
160 }
161 
162 /**
163  *	tty_audit_tiocsti	-	Log TIOCSTI
164  */
tty_audit_tiocsti(struct tty_struct * tty,char ch)165 void tty_audit_tiocsti(struct tty_struct *tty, char ch)
166 {
167 	struct tty_audit_buf *buf;
168 	int major, minor, should_audit;
169 
170 	spin_lock_irq(&current->sighand->siglock);
171 	should_audit = current->signal->audit_tty;
172 	buf = current->signal->tty_audit_buf;
173 	if (buf)
174 		atomic_inc(&buf->count);
175 	spin_unlock_irq(&current->sighand->siglock);
176 
177 	major = tty->driver->major;
178 	minor = tty->driver->minor_start + tty->index;
179 	if (buf) {
180 		mutex_lock(&buf->mutex);
181 		if (buf->major == major && buf->minor == minor)
182 			tty_audit_buf_push_current(buf);
183 		mutex_unlock(&buf->mutex);
184 		tty_audit_buf_put(buf);
185 	}
186 
187 	if (should_audit && audit_enabled) {
188 		uid_t auid;
189 		unsigned int sessionid;
190 
191 		auid = audit_get_loginuid(current);
192 		sessionid = audit_get_sessionid(current);
193 		tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
194 			      minor, &ch, 1);
195 	}
196 }
197 
198 /**
199  *	tty_audit_push_task	-	Flush task's pending audit data
200  */
tty_audit_push_task(struct task_struct * tsk,uid_t loginuid,u32 sessionid)201 void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
202 {
203 	struct tty_audit_buf *buf;
204 
205 	spin_lock_irq(&tsk->sighand->siglock);
206 	buf = tsk->signal->tty_audit_buf;
207 	if (buf)
208 		atomic_inc(&buf->count);
209 	spin_unlock_irq(&tsk->sighand->siglock);
210 	if (!buf)
211 		return;
212 
213 	mutex_lock(&buf->mutex);
214 	tty_audit_buf_push(tsk, loginuid, sessionid, buf);
215 	mutex_unlock(&buf->mutex);
216 
217 	tty_audit_buf_put(buf);
218 }
219 
220 /**
221  *	tty_audit_buf_get	-	Get an audit buffer.
222  *
223  *	Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
224  *	if TTY auditing is disabled or out of memory.  Otherwise, return a new
225  *	reference to the buffer.
226  */
tty_audit_buf_get(struct tty_struct * tty)227 static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
228 {
229 	struct tty_audit_buf *buf, *buf2;
230 
231 	buf = NULL;
232 	buf2 = NULL;
233 	spin_lock_irq(&current->sighand->siglock);
234 	if (likely(!current->signal->audit_tty))
235 		goto out;
236 	buf = current->signal->tty_audit_buf;
237 	if (buf) {
238 		atomic_inc(&buf->count);
239 		goto out;
240 	}
241 	spin_unlock_irq(&current->sighand->siglock);
242 
243 	buf2 = tty_audit_buf_alloc(tty->driver->major,
244 				   tty->driver->minor_start + tty->index,
245 				   tty->icanon);
246 	if (buf2 == NULL) {
247 		audit_log_lost("out of memory in TTY auditing");
248 		return NULL;
249 	}
250 
251 	spin_lock_irq(&current->sighand->siglock);
252 	if (!current->signal->audit_tty)
253 		goto out;
254 	buf = current->signal->tty_audit_buf;
255 	if (!buf) {
256 		current->signal->tty_audit_buf = buf2;
257 		buf = buf2;
258 		buf2 = NULL;
259 	}
260 	atomic_inc(&buf->count);
261 	/* Fall through */
262  out:
263 	spin_unlock_irq(&current->sighand->siglock);
264 	if (buf2)
265 		tty_audit_buf_free(buf2);
266 	return buf;
267 }
268 
269 /**
270  *	tty_audit_add_data	-	Add data for TTY auditing.
271  *
272  *	Audit @data of @size from @tty, if necessary.
273  */
tty_audit_add_data(struct tty_struct * tty,unsigned char * data,size_t size)274 void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
275 			size_t size)
276 {
277 	struct tty_audit_buf *buf;
278 	int major, minor;
279 
280 	if (unlikely(size == 0))
281 		return;
282 
283 	if (tty->driver->type == TTY_DRIVER_TYPE_PTY
284 	    && tty->driver->subtype == PTY_TYPE_MASTER)
285 		return;
286 
287 	buf = tty_audit_buf_get(tty);
288 	if (!buf)
289 		return;
290 
291 	mutex_lock(&buf->mutex);
292 	major = tty->driver->major;
293 	minor = tty->driver->minor_start + tty->index;
294 	if (buf->major != major || buf->minor != minor
295 	    || buf->icanon != tty->icanon) {
296 		tty_audit_buf_push_current(buf);
297 		buf->major = major;
298 		buf->minor = minor;
299 		buf->icanon = tty->icanon;
300 	}
301 	do {
302 		size_t run;
303 
304 		run = N_TTY_BUF_SIZE - buf->valid;
305 		if (run > size)
306 			run = size;
307 		memcpy(buf->data + buf->valid, data, run);
308 		buf->valid += run;
309 		data += run;
310 		size -= run;
311 		if (buf->valid == N_TTY_BUF_SIZE)
312 			tty_audit_buf_push_current(buf);
313 	} while (size != 0);
314 	mutex_unlock(&buf->mutex);
315 	tty_audit_buf_put(buf);
316 }
317 
318 /**
319  *	tty_audit_push	-	Push buffered data out
320  *
321  *	Make sure no audit data is pending for @tty on the current process.
322  */
tty_audit_push(struct tty_struct * tty)323 void tty_audit_push(struct tty_struct *tty)
324 {
325 	struct tty_audit_buf *buf;
326 
327 	spin_lock_irq(&current->sighand->siglock);
328 	if (likely(!current->signal->audit_tty)) {
329 		spin_unlock_irq(&current->sighand->siglock);
330 		return;
331 	}
332 	buf = current->signal->tty_audit_buf;
333 	if (buf)
334 		atomic_inc(&buf->count);
335 	spin_unlock_irq(&current->sighand->siglock);
336 
337 	if (buf) {
338 		int major, minor;
339 
340 		major = tty->driver->major;
341 		minor = tty->driver->minor_start + tty->index;
342 		mutex_lock(&buf->mutex);
343 		if (buf->major == major && buf->minor == minor)
344 			tty_audit_buf_push_current(buf);
345 		mutex_unlock(&buf->mutex);
346 		tty_audit_buf_put(buf);
347 	}
348 }
349