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