Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tty_audit.c
Go to the documentation of this file.
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 <[email protected]>
10  */
11 
12 #include <linux/audit.h>
13 #include <linux/slab.h>
14 #include <linux/tty.h>
15 
16 struct tty_audit_buf {
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 static 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;
34  if (!buf->data)
35  goto err_buf;
36  atomic_set(&buf->count, 1);
37  mutex_init(&buf->mutex);
38  buf->major = major;
39  buf->minor = minor;
40  buf->icanon = icanon;
41  buf->valid = 0;
42  return buf;
43 
44 err_buf:
45  kfree(buf);
46 err:
47  return NULL;
48 }
49 
50 static void tty_audit_buf_free(struct tty_audit_buf *buf)
51 {
52  WARN_ON(buf->valid != 0);
53  kfree(buf->data);
54  kfree(buf);
55 }
56 
57 static void tty_audit_buf_put(struct tty_audit_buf *buf)
58 {
59  if (atomic_dec_and_test(&buf->count))
60  tty_audit_buf_free(buf);
61 }
62 
63 static void tty_audit_log(const char *description, struct task_struct *tsk,
64  kuid_t loginuid, unsigned sessionid, int major,
65  int minor, unsigned char *data, size_t size)
66 {
67  struct audit_buffer *ab;
68 
70  if (ab) {
71  char name[sizeof(tsk->comm)];
72  kuid_t uid = task_uid(tsk);
73 
74  audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
75  "major=%d minor=%d comm=", description,
76  tsk->pid,
77  from_kuid(&init_user_ns, uid),
78  from_kuid(&init_user_ns, loginuid),
79  sessionid,
80  major, minor);
81  get_task_comm(name, tsk);
83  audit_log_format(ab, " data=");
84  audit_log_n_hex(ab, data, size);
85  audit_log_end(ab);
86  }
87 }
88 
95 static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
96  unsigned int sessionid,
97  struct tty_audit_buf *buf)
98 {
99  if (buf->valid == 0)
100  return;
101  if (audit_enabled == 0) {
102  buf->valid = 0;
103  return;
104  }
105  tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
106  buf->data, buf->valid);
107  buf->valid = 0;
108 }
109 
116 static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
117 {
118  kuid_t auid = audit_get_loginuid(current);
119  unsigned int sessionid = audit_get_sessionid(current);
120  tty_audit_buf_push(current, auid, sessionid, buf);
121 }
122 
129 void tty_audit_exit(void)
130 {
131  struct tty_audit_buf *buf;
132 
133  spin_lock_irq(&current->sighand->siglock);
134  buf = current->signal->tty_audit_buf;
135  current->signal->tty_audit_buf = NULL;
136  spin_unlock_irq(&current->sighand->siglock);
137  if (!buf)
138  return;
139 
140  mutex_lock(&buf->mutex);
141  tty_audit_buf_push_current(buf);
142  mutex_unlock(&buf->mutex);
143 
144  tty_audit_buf_put(buf);
145 }
146 
153 {
154  spin_lock_irq(&current->sighand->siglock);
155  sig->audit_tty = current->signal->audit_tty;
156  spin_unlock_irq(&current->sighand->siglock);
157 }
158 
162 void tty_audit_tiocsti(struct tty_struct *tty, char ch)
163 {
164  struct tty_audit_buf *buf;
165  int major, minor, should_audit;
166 
167  spin_lock_irq(&current->sighand->siglock);
168  should_audit = current->signal->audit_tty;
169  buf = current->signal->tty_audit_buf;
170  if (buf)
171  atomic_inc(&buf->count);
172  spin_unlock_irq(&current->sighand->siglock);
173 
174  major = tty->driver->major;
175  minor = tty->driver->minor_start + tty->index;
176  if (buf) {
177  mutex_lock(&buf->mutex);
178  if (buf->major == major && buf->minor == minor)
179  tty_audit_buf_push_current(buf);
180  mutex_unlock(&buf->mutex);
181  tty_audit_buf_put(buf);
182  }
183 
184  if (should_audit && audit_enabled) {
185  kuid_t auid;
186  unsigned int sessionid;
187 
188  auid = audit_get_loginuid(current);
189  sessionid = audit_get_sessionid(current);
190  tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
191  minor, &ch, 1);
192  }
193 }
194 
205 int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
206 {
207  struct tty_audit_buf *buf = ERR_PTR(-EPERM);
208  unsigned long flags;
209 
210  if (!lock_task_sighand(tsk, &flags))
211  return -ESRCH;
212 
213  if (tsk->signal->audit_tty) {
214  buf = tsk->signal->tty_audit_buf;
215  if (buf)
216  atomic_inc(&buf->count);
217  }
218  unlock_task_sighand(tsk, &flags);
219 
220  /*
221  * Return 0 when signal->audit_tty set
222  * but tsk->signal->tty_audit_buf == NULL.
223  */
224  if (!buf || IS_ERR(buf))
225  return PTR_ERR(buf);
226 
227  mutex_lock(&buf->mutex);
228  tty_audit_buf_push(tsk, loginuid, sessionid, buf);
229  mutex_unlock(&buf->mutex);
230 
231  tty_audit_buf_put(buf);
232  return 0;
233 }
234 
242 static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
243 {
244  struct tty_audit_buf *buf, *buf2;
245 
246  buf = NULL;
247  buf2 = NULL;
248  spin_lock_irq(&current->sighand->siglock);
249  if (likely(!current->signal->audit_tty))
250  goto out;
251  buf = current->signal->tty_audit_buf;
252  if (buf) {
253  atomic_inc(&buf->count);
254  goto out;
255  }
256  spin_unlock_irq(&current->sighand->siglock);
257 
258  buf2 = tty_audit_buf_alloc(tty->driver->major,
259  tty->driver->minor_start + tty->index,
260  tty->icanon);
261  if (buf2 == NULL) {
262  audit_log_lost("out of memory in TTY auditing");
263  return NULL;
264  }
265 
266  spin_lock_irq(&current->sighand->siglock);
267  if (!current->signal->audit_tty)
268  goto out;
269  buf = current->signal->tty_audit_buf;
270  if (!buf) {
271  current->signal->tty_audit_buf = buf2;
272  buf = buf2;
273  buf2 = NULL;
274  }
275  atomic_inc(&buf->count);
276  /* Fall through */
277  out:
278  spin_unlock_irq(&current->sighand->siglock);
279  if (buf2)
280  tty_audit_buf_free(buf2);
281  return buf;
282 }
283 
289 void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
290  size_t size)
291 {
292  struct tty_audit_buf *buf;
293  int major, minor;
294 
295  if (unlikely(size == 0))
296  return;
297 
298  if (tty->driver->type == TTY_DRIVER_TYPE_PTY
299  && tty->driver->subtype == PTY_TYPE_MASTER)
300  return;
301 
302  buf = tty_audit_buf_get(tty);
303  if (!buf)
304  return;
305 
306  mutex_lock(&buf->mutex);
307  major = tty->driver->major;
308  minor = tty->driver->minor_start + tty->index;
309  if (buf->major != major || buf->minor != minor
310  || buf->icanon != tty->icanon) {
311  tty_audit_buf_push_current(buf);
312  buf->major = major;
313  buf->minor = minor;
314  buf->icanon = tty->icanon;
315  }
316  do {
317  size_t run;
318 
319  run = N_TTY_BUF_SIZE - buf->valid;
320  if (run > size)
321  run = size;
322  memcpy(buf->data + buf->valid, data, run);
323  buf->valid += run;
324  data += run;
325  size -= run;
326  if (buf->valid == N_TTY_BUF_SIZE)
327  tty_audit_buf_push_current(buf);
328  } while (size != 0);
329  mutex_unlock(&buf->mutex);
330  tty_audit_buf_put(buf);
331 }
332 
338 void tty_audit_push(struct tty_struct *tty)
339 {
340  struct tty_audit_buf *buf;
341 
342  spin_lock_irq(&current->sighand->siglock);
343  if (likely(!current->signal->audit_tty)) {
344  spin_unlock_irq(&current->sighand->siglock);
345  return;
346  }
347  buf = current->signal->tty_audit_buf;
348  if (buf)
349  atomic_inc(&buf->count);
350  spin_unlock_irq(&current->sighand->siglock);
351 
352  if (buf) {
353  int major, minor;
354 
355  major = tty->driver->major;
356  minor = tty->driver->minor_start + tty->index;
357  mutex_lock(&buf->mutex);
358  if (buf->major == major && buf->minor == minor)
359  tty_audit_buf_push_current(buf);
360  mutex_unlock(&buf->mutex);
361  tty_audit_buf_put(buf);
362  }
363 }