]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/char/tty_audit.c
[AUDIT] collect uid, loginuid, and comm in OBJ_PID records
[mirror_ubuntu-zesty-kernel.git] / drivers / char / tty_audit.c
CommitLineData
522ed776
MT
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/tty.h>
15
16struct tty_audit_buf {
17 atomic_t count;
18 struct mutex mutex; /* Protects all data below */
19 int major, minor; /* The TTY which the data is from */
20 unsigned icanon:1;
21 size_t valid;
22 unsigned char *data; /* Allocated size N_TTY_BUF_SIZE */
23};
24
25static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
26 int icanon)
27{
28 struct tty_audit_buf *buf;
29
30 buf = kmalloc(sizeof (*buf), GFP_KERNEL);
31 if (!buf)
32 goto err;
33 if (PAGE_SIZE != N_TTY_BUF_SIZE)
34 buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
35 else
36 buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
37 if (!buf->data)
38 goto err_buf;
39 atomic_set(&buf->count, 1);
40 mutex_init(&buf->mutex);
41 buf->major = major;
42 buf->minor = minor;
43 buf->icanon = icanon;
44 buf->valid = 0;
45 return buf;
46
47err_buf:
48 kfree(buf);
49err:
50 return NULL;
51}
52
53static void tty_audit_buf_free(struct tty_audit_buf *buf)
54{
55 WARN_ON(buf->valid != 0);
56 if (PAGE_SIZE != N_TTY_BUF_SIZE)
57 kfree(buf->data);
58 else
59 free_page((unsigned long)buf->data);
60 kfree(buf);
61}
62
63static void tty_audit_buf_put(struct tty_audit_buf *buf)
64{
65 if (atomic_dec_and_test(&buf->count))
66 tty_audit_buf_free(buf);
67}
68
69/**
70 * tty_audit_buf_push - Push buffered data out
71 *
72 * Generate an audit message from the contents of @buf, which is owned by
73 * @tsk with @loginuid. @buf->mutex must be locked.
74 */
75static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
76 struct tty_audit_buf *buf)
77{
78 struct audit_buffer *ab;
79
80 if (buf->valid == 0)
81 return;
82 if (audit_enabled == 0)
83 return;
84 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
85 if (ab) {
86 char name[sizeof(tsk->comm)];
87
88 audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d "
89 "minor=%d comm=", tsk->pid, tsk->uid,
90 loginuid, buf->major, buf->minor);
91 get_task_comm(name, tsk);
92 audit_log_untrustedstring(ab, name);
93 audit_log_format(ab, " data=");
94 audit_log_n_untrustedstring(ab, buf->valid, buf->data);
95 audit_log_end(ab);
96 }
97 buf->valid = 0;
98}
99
100/**
101 * tty_audit_buf_push_current - Push buffered data out
102 *
103 * Generate an audit message from the contents of @buf, which is owned by
104 * the current task. @buf->mutex must be locked.
105 */
106static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
107{
0c11b942 108 tty_audit_buf_push(current, audit_get_loginuid(current), buf);
522ed776
MT
109}
110
111/**
112 * tty_audit_exit - Handle a task exit
113 *
114 * Make sure all buffered data is written out and deallocate the buffer.
115 * Only needs to be called if current->signal->tty_audit_buf != %NULL.
116 */
117void tty_audit_exit(void)
118{
119 struct tty_audit_buf *buf;
120
121 spin_lock_irq(&current->sighand->siglock);
122 buf = current->signal->tty_audit_buf;
123 current->signal->tty_audit_buf = NULL;
124 spin_unlock_irq(&current->sighand->siglock);
125 if (!buf)
126 return;
127
128 mutex_lock(&buf->mutex);
129 tty_audit_buf_push_current(buf);
130 mutex_unlock(&buf->mutex);
131
132 tty_audit_buf_put(buf);
133}
134
135/**
136 * tty_audit_fork - Copy TTY audit state for a new task
137 *
138 * Set up TTY audit state in @sig from current. @sig needs no locking.
139 */
140void tty_audit_fork(struct signal_struct *sig)
141{
142 spin_lock_irq(&current->sighand->siglock);
143 sig->audit_tty = current->signal->audit_tty;
144 spin_unlock_irq(&current->sighand->siglock);
145 sig->tty_audit_buf = NULL;
146}
147
148/**
149 * tty_audit_push_task - Flush task's pending audit data
150 */
151void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
152{
153 struct tty_audit_buf *buf;
154
155 spin_lock_irq(&tsk->sighand->siglock);
156 buf = tsk->signal->tty_audit_buf;
157 if (buf)
158 atomic_inc(&buf->count);
159 spin_unlock_irq(&tsk->sighand->siglock);
160 if (!buf)
161 return;
162
163 mutex_lock(&buf->mutex);
164 tty_audit_buf_push(tsk, loginuid, buf);
165 mutex_unlock(&buf->mutex);
166
167 tty_audit_buf_put(buf);
168}
169
170/**
171 * tty_audit_buf_get - Get an audit buffer.
172 *
173 * Get an audit buffer for @tty, allocate it if necessary. Return %NULL
174 * if TTY auditing is disabled or out of memory. Otherwise, return a new
175 * reference to the buffer.
176 */
177static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
178{
179 struct tty_audit_buf *buf, *buf2;
180
181 buf = NULL;
182 buf2 = NULL;
183 spin_lock_irq(&current->sighand->siglock);
184 if (likely(!current->signal->audit_tty))
185 goto out;
186 buf = current->signal->tty_audit_buf;
187 if (buf) {
188 atomic_inc(&buf->count);
189 goto out;
190 }
191 spin_unlock_irq(&current->sighand->siglock);
192
193 buf2 = tty_audit_buf_alloc(tty->driver->major,
194 tty->driver->minor_start + tty->index,
195 tty->icanon);
196 if (buf2 == NULL) {
197 audit_log_lost("out of memory in TTY auditing");
198 return NULL;
199 }
200
201 spin_lock_irq(&current->sighand->siglock);
202 if (!current->signal->audit_tty)
203 goto out;
204 buf = current->signal->tty_audit_buf;
205 if (!buf) {
206 current->signal->tty_audit_buf = buf2;
207 buf = buf2;
208 buf2 = NULL;
209 }
210 atomic_inc(&buf->count);
211 /* Fall through */
212 out:
213 spin_unlock_irq(&current->sighand->siglock);
214 if (buf2)
215 tty_audit_buf_free(buf2);
216 return buf;
217}
218
219/**
220 * tty_audit_add_data - Add data for TTY auditing.
221 *
222 * Audit @data of @size from @tty, if necessary.
223 */
224void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
225 size_t size)
226{
227 struct tty_audit_buf *buf;
228 int major, minor;
229
230 if (unlikely(size == 0))
231 return;
232
233 buf = tty_audit_buf_get(tty);
234 if (!buf)
235 return;
236
237 mutex_lock(&buf->mutex);
238 major = tty->driver->major;
239 minor = tty->driver->minor_start + tty->index;
240 if (buf->major != major || buf->minor != minor
241 || buf->icanon != tty->icanon) {
242 tty_audit_buf_push_current(buf);
243 buf->major = major;
244 buf->minor = minor;
245 buf->icanon = tty->icanon;
246 }
247 do {
248 size_t run;
249
250 run = N_TTY_BUF_SIZE - buf->valid;
251 if (run > size)
252 run = size;
253 memcpy(buf->data + buf->valid, data, run);
254 buf->valid += run;
255 data += run;
256 size -= run;
257 if (buf->valid == N_TTY_BUF_SIZE)
258 tty_audit_buf_push_current(buf);
259 } while (size != 0);
260 mutex_unlock(&buf->mutex);
261 tty_audit_buf_put(buf);
262}
263
264/**
265 * tty_audit_push - Push buffered data out
266 *
267 * Make sure no audit data is pending for @tty on the current process.
268 */
269void tty_audit_push(struct tty_struct *tty)
270{
271 struct tty_audit_buf *buf;
272
273 spin_lock_irq(&current->sighand->siglock);
274 if (likely(!current->signal->audit_tty)) {
275 spin_unlock_irq(&current->sighand->siglock);
276 return;
277 }
278 buf = current->signal->tty_audit_buf;
279 if (buf)
280 atomic_inc(&buf->count);
281 spin_unlock_irq(&current->sighand->siglock);
282
283 if (buf) {
284 int major, minor;
285
286 major = tty->driver->major;
287 minor = tty->driver->minor_start + tty->index;
288 mutex_lock(&buf->mutex);
289 if (buf->major == major && buf->minor == minor)
290 tty_audit_buf_push_current(buf);
291 mutex_unlock(&buf->mutex);
292 tty_audit_buf_put(buf);
293 }
294}
295
296/**
297 * tty_audit_opening - A TTY is being opened.
298 *
299 * As a special hack, tasks that close all their TTYs and open new ones
300 * are assumed to be system daemons (e.g. getty) and auditing is
301 * automatically disabled for them.
302 */
303void tty_audit_opening(void)
304{
305 int disable;
306
307 disable = 1;
308 spin_lock_irq(&current->sighand->siglock);
309 if (current->signal->audit_tty == 0)
310 disable = 0;
311 spin_unlock_irq(&current->sighand->siglock);
312 if (!disable)
313 return;
314
315 task_lock(current);
316 if (current->files) {
317 struct fdtable *fdt;
318 unsigned i;
319
320 /*
321 * We don't take a ref to the file, so we must hold ->file_lock
322 * instead.
323 */
324 spin_lock(&current->files->file_lock);
325 fdt = files_fdtable(current->files);
326 for (i = 0; i < fdt->max_fds; i++) {
327 struct file *filp;
328
329 filp = fcheck_files(current->files, i);
330 if (filp && is_tty(filp)) {
331 disable = 0;
332 break;
333 }
334 }
335 spin_unlock(&current->files->file_lock);
336 }
337 task_unlock(current);
338 if (!disable)
339 return;
340
341 spin_lock_irq(&current->sighand->siglock);
342 current->signal->audit_tty = 0;
343 spin_unlock_irq(&current->sighand->siglock);
344}