aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmac <mitr@redhat.com>2007-07-16 02:40:56 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:47 -0400
commit522ed7767e800cff6c650ec64b0ee0677303119c (patch)
treef65ecb29f2cf885018d3557f840de3ef4be6ec64
parent4f27c00bf80f122513d3a5be16ed851573164534 (diff)
Audit: add TTY input auditing
Add TTY input auditing, used to audit system administrator's actions. This is required by various security standards such as DCID 6/3 and PCI to provide non-repudiation of administrator's actions and to allow a review of past actions if the administrator seems to overstep their duties or if the system becomes misconfigured for unknown reasons. These requirements do not make it necessary to audit TTY output as well. Compared to an user-space keylogger, this approach records TTY input using the audit subsystem, correlated with other audit events, and it is completely transparent to the user-space application (e.g. the console ioctls still work). TTY input auditing works on a higher level than auditing all system calls within the session, which would produce an overwhelming amount of mostly useless audit events. Add an "audit_tty" attribute, inherited across fork (). Data read from TTYs by process with the attribute is sent to the audit subsystem by the kernel. The audit netlink interface is extended to allow modifying the audit_tty attribute, and to allow sending explanatory audit events from user-space (for example, a shell might send an event containing the final command, after the interactive command-line editing and history expansion is performed, which might be difficult to decipher from the TTY input alone). Because the "audit_tty" attribute is inherited across fork (), it would be set e.g. for sshd restarted within an audited session. To prevent this, the audit_tty attribute is cleared when a process with no open TTY file descriptors (e.g. after daemon startup) opens a TTY. See https://www.redhat.com/archives/linux-audit/2007-June/msg00000.html for a more detailed rationale document for an older version of this patch. [akpm@linux-foundation.org: build fix] Signed-off-by: Miloslav Trmac <mitr@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Paul Fulghum <paulkf@microgate.com> Cc: Casey Schaufler <casey@schaufler-ca.com> Cc: Steve Grubb <sgrubb@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/n_tty.c20
-rw-r--r--drivers/char/tty_audit.c345
-rw-r--r--drivers/char/tty_io.c14
-rw-r--r--include/linux/audit.h11
-rw-r--r--include/linux/sched.h4
-rw-r--r--include/linux/tty.h33
-rw-r--r--kernel/audit.c96
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditsc.c3
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c3
-rw-r--r--net/netlabel/netlabel_user.c4
-rw-r--r--security/selinux/nlmsgtab.c2
14 files changed, 518 insertions, 21 deletions
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 2f56ecc035aa..f2996a95eb07 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -15,6 +15,7 @@ obj-y += misc.o
15obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \ 15obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \
16 consolemap_deftbl.o selection.o keyboard.o 16 consolemap_deftbl.o selection.o keyboard.o
17obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o 17obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
18obj-$(CONFIG_AUDIT) += tty_audit.o
18obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o 19obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
19obj-$(CONFIG_ESPSERIAL) += esp.o 20obj-$(CONFIG_ESPSERIAL) += esp.o
20obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o 21obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 371631f4bfb9..038056911934 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -45,6 +45,8 @@
45#include <linux/slab.h> 45#include <linux/slab.h>
46#include <linux/poll.h> 46#include <linux/poll.h>
47#include <linux/bitops.h> 47#include <linux/bitops.h>
48#include <linux/audit.h>
49#include <linux/file.h>
48 50
49#include <asm/uaccess.h> 51#include <asm/uaccess.h>
50#include <asm/system.h> 52#include <asm/system.h>
@@ -78,6 +80,13 @@ static inline void free_buf(unsigned char *buf)
78 free_page((unsigned long) buf); 80 free_page((unsigned long) buf);
79} 81}
80 82
83static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
84 unsigned char __user *ptr)
85{
86 tty_audit_add_data(tty, &x, 1);
87 return put_user(x, ptr);
88}
89
81/** 90/**
82 * n_tty_set__room - receive space 91 * n_tty_set__room - receive space
83 * @tty: terminal 92 * @tty: terminal
@@ -1153,6 +1162,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
1153 if (n) { 1162 if (n) {
1154 retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); 1163 retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
1155 n -= retval; 1164 n -= retval;
1165 tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
1156 spin_lock_irqsave(&tty->read_lock, flags); 1166 spin_lock_irqsave(&tty->read_lock, flags);
1157 tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); 1167 tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
1158 tty->read_cnt -= n; 1168 tty->read_cnt -= n;
@@ -1279,7 +1289,7 @@ do_it_again:
1279 break; 1289 break;
1280 cs = tty->link->ctrl_status; 1290 cs = tty->link->ctrl_status;
1281 tty->link->ctrl_status = 0; 1291 tty->link->ctrl_status = 0;
1282 if (put_user(cs, b++)) { 1292 if (tty_put_user(tty, cs, b++)) {
1283 retval = -EFAULT; 1293 retval = -EFAULT;
1284 b--; 1294 b--;
1285 break; 1295 break;
@@ -1321,7 +1331,7 @@ do_it_again:
1321 1331
1322 /* Deal with packet mode. */ 1332 /* Deal with packet mode. */
1323 if (tty->packet && b == buf) { 1333 if (tty->packet && b == buf) {
1324 if (put_user(TIOCPKT_DATA, b++)) { 1334 if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
1325 retval = -EFAULT; 1335 retval = -EFAULT;
1326 b--; 1336 b--;
1327 break; 1337 break;
@@ -1352,15 +1362,17 @@ do_it_again:
1352 spin_unlock_irqrestore(&tty->read_lock, flags); 1362 spin_unlock_irqrestore(&tty->read_lock, flags);
1353 1363
1354 if (!eol || (c != __DISABLED_CHAR)) { 1364 if (!eol || (c != __DISABLED_CHAR)) {
1355 if (put_user(c, b++)) { 1365 if (tty_put_user(tty, c, b++)) {
1356 retval = -EFAULT; 1366 retval = -EFAULT;
1357 b--; 1367 b--;
1358 break; 1368 break;
1359 } 1369 }
1360 nr--; 1370 nr--;
1361 } 1371 }
1362 if (eol) 1372 if (eol) {
1373 tty_audit_push(tty);
1363 break; 1374 break;
1375 }
1364 } 1376 }
1365 if (retval) 1377 if (retval)
1366 break; 1378 break;
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
new file mode 100644
index 000000000000..d222012c1b0c
--- /dev/null
+++ b/drivers/char/tty_audit.c
@@ -0,0 +1,345 @@
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{
108 tty_audit_buf_push(current, audit_get_loginuid(current->audit_context),
109 buf);
110}
111
112/**
113 * tty_audit_exit - Handle a task exit
114 *
115 * Make sure all buffered data is written out and deallocate the buffer.
116 * Only needs to be called if current->signal->tty_audit_buf != %NULL.
117 */
118void tty_audit_exit(void)
119{
120 struct tty_audit_buf *buf;
121
122 spin_lock_irq(&current->sighand->siglock);
123 buf = current->signal->tty_audit_buf;
124 current->signal->tty_audit_buf = NULL;
125 spin_unlock_irq(&current->sighand->siglock);
126 if (!buf)
127 return;
128
129 mutex_lock(&buf->mutex);
130 tty_audit_buf_push_current(buf);
131 mutex_unlock(&buf->mutex);
132
133 tty_audit_buf_put(buf);
134}
135
136/**
137 * tty_audit_fork - Copy TTY audit state for a new task
138 *
139 * Set up TTY audit state in @sig from current. @sig needs no locking.
140 */
141void tty_audit_fork(struct signal_struct *sig)
142{
143 spin_lock_irq(&current->sighand->siglock);
144 sig->audit_tty = current->signal->audit_tty;
145 spin_unlock_irq(&current->sighand->siglock);
146 sig->tty_audit_buf = NULL;
147}
148
149/**
150 * tty_audit_push_task - Flush task's pending audit data
151 */
152void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
153{
154 struct tty_audit_buf *buf;
155
156 spin_lock_irq(&tsk->sighand->siglock);
157 buf = tsk->signal->tty_audit_buf;
158 if (buf)
159 atomic_inc(&buf->count);
160 spin_unlock_irq(&tsk->sighand->siglock);
161 if (!buf)
162 return;
163
164 mutex_lock(&buf->mutex);
165 tty_audit_buf_push(tsk, loginuid, buf);
166 mutex_unlock(&buf->mutex);
167
168 tty_audit_buf_put(buf);
169}
170
171/**
172 * tty_audit_buf_get - Get an audit buffer.
173 *
174 * Get an audit buffer for @tty, allocate it if necessary. Return %NULL
175 * if TTY auditing is disabled or out of memory. Otherwise, return a new
176 * reference to the buffer.
177 */
178static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
179{
180 struct tty_audit_buf *buf, *buf2;
181
182 buf = NULL;
183 buf2 = NULL;
184 spin_lock_irq(&current->sighand->siglock);
185 if (likely(!current->signal->audit_tty))
186 goto out;
187 buf = current->signal->tty_audit_buf;
188 if (buf) {
189 atomic_inc(&buf->count);
190 goto out;
191 }
192 spin_unlock_irq(&current->sighand->siglock);
193
194 buf2 = tty_audit_buf_alloc(tty->driver->major,
195 tty->driver->minor_start + tty->index,
196 tty->icanon);
197 if (buf2 == NULL) {
198 audit_log_lost("out of memory in TTY auditing");
199 return NULL;
200 }
201
202 spin_lock_irq(&current->sighand->siglock);
203 if (!current->signal->audit_tty)
204 goto out;
205 buf = current->signal->tty_audit_buf;
206 if (!buf) {
207 current->signal->tty_audit_buf = buf2;
208 buf = buf2;
209 buf2 = NULL;
210 }
211 atomic_inc(&buf->count);
212 /* Fall through */
213 out:
214 spin_unlock_irq(&current->sighand->siglock);
215 if (buf2)
216 tty_audit_buf_free(buf2);
217 return buf;
218}
219
220/**
221 * tty_audit_add_data - Add data for TTY auditing.
222 *
223 * Audit @data of @size from @tty, if necessary.
224 */
225void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
226 size_t size)
227{
228 struct tty_audit_buf *buf;
229 int major, minor;
230
231 if (unlikely(size == 0))
232 return;
233
234 buf = tty_audit_buf_get(tty);
235 if (!buf)
236 return;
237
238 mutex_lock(&buf->mutex);
239 major = tty->driver->major;
240 minor = tty->driver->minor_start + tty->index;
241 if (buf->major != major || buf->minor != minor
242 || buf->icanon != tty->icanon) {
243 tty_audit_buf_push_current(buf);
244 buf->major = major;
245 buf->minor = minor;
246 buf->icanon = tty->icanon;
247 }
248 do {
249 size_t run;
250
251 run = N_TTY_BUF_SIZE - buf->valid;
252 if (run > size)
253 run = size;
254 memcpy(buf->data + buf->valid, data, run);
255 buf->valid += run;
256 data += run;
257 size -= run;
258 if (buf->valid == N_TTY_BUF_SIZE)
259 tty_audit_buf_push_current(buf);
260 } while (size != 0);
261 mutex_unlock(&buf->mutex);
262 tty_audit_buf_put(buf);
263}
264
265/**
266 * tty_audit_push - Push buffered data out
267 *
268 * Make sure no audit data is pending for @tty on the current process.
269 */
270void tty_audit_push(struct tty_struct *tty)
271{
272 struct tty_audit_buf *buf;
273
274 spin_lock_irq(&current->sighand->siglock);
275 if (likely(!current->signal->audit_tty)) {
276 spin_unlock_irq(&current->sighand->siglock);
277 return;
278 }
279 buf = current->signal->tty_audit_buf;
280 if (buf)
281 atomic_inc(&buf->count);
282 spin_unlock_irq(&current->sighand->siglock);
283
284 if (buf) {
285 int major, minor;
286
287 major = tty->driver->major;
288 minor = tty->driver->minor_start + tty->index;
289 mutex_lock(&buf->mutex);
290 if (buf->major == major && buf->minor == minor)
291 tty_audit_buf_push_current(buf);
292 mutex_unlock(&buf->mutex);
293 tty_audit_buf_put(buf);
294 }
295}
296
297/**
298 * tty_audit_opening - A TTY is being opened.
299 *
300 * As a special hack, tasks that close all their TTYs and open new ones
301 * are assumed to be system daemons (e.g. getty) and auditing is
302 * automatically disabled for them.
303 */
304void tty_audit_opening(void)
305{
306 int disable;
307
308 disable = 1;
309 spin_lock_irq(&current->sighand->siglock);
310 if (current->signal->audit_tty == 0)
311 disable = 0;
312 spin_unlock_irq(&current->sighand->siglock);
313 if (!disable)
314 return;
315
316 task_lock(current);
317 if (current->files) {
318 struct fdtable *fdt;
319 unsigned i;
320
321 /*
322 * We don't take a ref to the file, so we must hold ->file_lock
323 * instead.
324 */
325 spin_lock(&current->files->file_lock);
326 fdt = files_fdtable(current->files);
327 for (i = 0; i < fdt->max_fds; i++) {
328 struct file *filp;
329
330 filp = fcheck_files(current->files, i);
331 if (filp && is_tty(filp)) {
332 disable = 0;
333 break;
334 }
335 }
336 spin_unlock(&current->files->file_lock);
337 }
338 task_unlock(current);
339 if (!disable)
340 return;
341
342 spin_lock_irq(&current->sighand->siglock);
343 current->signal->audit_tty = 0;
344 spin_unlock_irq(&current->sighand->siglock);
345}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index fde69e589ca7..de37ebc3a4cf 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1503,6 +1503,15 @@ int tty_hung_up_p(struct file * filp)
1503 1503
1504EXPORT_SYMBOL(tty_hung_up_p); 1504EXPORT_SYMBOL(tty_hung_up_p);
1505 1505
1506/**
1507 * is_tty - checker whether file is a TTY
1508 */
1509int is_tty(struct file *filp)
1510{
1511 return filp->f_op->read == tty_read
1512 || filp->f_op->read == hung_up_tty_read;
1513}
1514
1506static void session_clear_tty(struct pid *session) 1515static void session_clear_tty(struct pid *session)
1507{ 1516{
1508 struct task_struct *p; 1517 struct task_struct *p;
@@ -2673,6 +2682,7 @@ got_driver:
2673 __proc_set_tty(current, tty); 2682 __proc_set_tty(current, tty);
2674 spin_unlock_irq(&current->sighand->siglock); 2683 spin_unlock_irq(&current->sighand->siglock);
2675 mutex_unlock(&tty_mutex); 2684 mutex_unlock(&tty_mutex);
2685 tty_audit_opening();
2676 return 0; 2686 return 0;
2677} 2687}
2678 2688
@@ -2735,8 +2745,10 @@ static int ptmx_open(struct inode * inode, struct file * filp)
2735 2745
2736 check_tty_count(tty, "tty_open"); 2746 check_tty_count(tty, "tty_open");
2737 retval = ptm_driver->open(tty, filp); 2747 retval = ptm_driver->open(tty, filp);
2738 if (!retval) 2748 if (!retval) {
2749 tty_audit_opening();
2739 return 0; 2750 return 0;
2751 }
2740out1: 2752out1:
2741 release_dev(filp); 2753 release_dev(filp);
2742 return retval; 2754 return retval;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index fccc6e50298a..8ca7ca0b47f0 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -63,9 +63,12 @@
63#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */ 63#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
64#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */ 64#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
65#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */ 65#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
66#define AUDIT_TTY_GET 1014 /* Get TTY auditing status */
67#define AUDIT_TTY_SET 1015 /* Set TTY auditing status */
66 68
67#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ 69#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
68#define AUDIT_USER_AVC 1107 /* We filter this differently */ 70#define AUDIT_USER_AVC 1107 /* We filter this differently */
71#define AUDIT_USER_TTY 1124 /* Non-ICANON TTY input meaning */
69#define AUDIT_LAST_USER_MSG 1199 72#define AUDIT_LAST_USER_MSG 1199
70#define AUDIT_FIRST_USER_MSG2 2100 /* More user space messages */ 73#define AUDIT_FIRST_USER_MSG2 2100 /* More user space messages */
71#define AUDIT_LAST_USER_MSG2 2999 74#define AUDIT_LAST_USER_MSG2 2999
@@ -92,6 +95,7 @@
92#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */ 95#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */
93#define AUDIT_FD_PAIR 1317 /* audit record for pipe/socketpair */ 96#define AUDIT_FD_PAIR 1317 /* audit record for pipe/socketpair */
94#define AUDIT_OBJ_PID 1318 /* ptrace target */ 97#define AUDIT_OBJ_PID 1318 /* ptrace target */
98#define AUDIT_TTY 1319 /* Input on an administrative TTY */
95 99
96#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ 100#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
97#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ 101#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -289,6 +293,10 @@ struct audit_status {
289 __u32 backlog; /* messages waiting in queue */ 293 __u32 backlog; /* messages waiting in queue */
290}; 294};
291 295
296struct audit_tty_status {
297 __u32 enabled; /* 1 = enabled, 0 = disabled */
298};
299
292/* audit_rule_data supports filter rules with both integer and string 300/* audit_rule_data supports filter rules with both integer and string
293 * fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and 301 * fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
294 * AUDIT_LIST_RULES requests. 302 * AUDIT_LIST_RULES requests.
@@ -515,11 +523,13 @@ extern void audit_log_d_path(struct audit_buffer *ab,
515 const char *prefix, 523 const char *prefix,
516 struct dentry *dentry, 524 struct dentry *dentry,
517 struct vfsmount *vfsmnt); 525 struct vfsmount *vfsmnt);
526extern void audit_log_lost(const char *message);
518 /* Private API (for audit.c only) */ 527 /* Private API (for audit.c only) */
519extern int audit_filter_user(struct netlink_skb_parms *cb, int type); 528extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
520extern int audit_filter_type(int type); 529extern int audit_filter_type(int type);
521extern int audit_receive_filter(int type, int pid, int uid, int seq, 530extern int audit_receive_filter(int type, int pid, int uid, int seq,
522 void *data, size_t datasz, uid_t loginuid, u32 sid); 531 void *data, size_t datasz, uid_t loginuid, u32 sid);
532extern int audit_enabled;
523#else 533#else
524#define audit_log(c,g,t,f,...) do { ; } while (0) 534#define audit_log(c,g,t,f,...) do { ; } while (0)
525#define audit_log_start(c,g,t) ({ NULL; }) 535#define audit_log_start(c,g,t) ({ NULL; })
@@ -530,6 +540,7 @@ extern int audit_receive_filter(int type, int pid, int uid, int seq,
530#define audit_log_untrustedstring(a,s) do { ; } while (0) 540#define audit_log_untrustedstring(a,s) do { ; } while (0)
531#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0) 541#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
532#define audit_log_d_path(b,p,d,v) do { ; } while (0) 542#define audit_log_d_path(b,p,d,v) do { ; } while (0)
543#define audit_enabled 0
533#endif 544#endif
534#endif 545#endif
535#endif 546#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3cffc1204663..b579624477f4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -529,6 +529,10 @@ struct signal_struct {
529#ifdef CONFIG_TASKSTATS 529#ifdef CONFIG_TASKSTATS
530 struct taskstats *stats; 530 struct taskstats *stats;
531#endif 531#endif
532#ifdef CONFIG_AUDIT
533 unsigned audit_tty;
534 struct tty_audit_buf *tty_audit_buf;
535#endif
532}; 536};
533 537
534/* Context switch must be unlocked if interrupts are to be enabled */ 538/* Context switch must be unlocked if interrupts are to be enabled */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index deaba9ec5004..691a1748d9d2 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -178,6 +178,7 @@ struct tty_bufhead {
178#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN) 178#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
179 179
180struct device; 180struct device;
181struct signal_struct;
181/* 182/*
182 * Where all of the state associated with a tty is kept while the tty 183 * Where all of the state associated with a tty is kept while the tty
183 * is open. Since the termios state should be kept even if the tty 184 * is open. Since the termios state should be kept even if the tty
@@ -310,6 +311,7 @@ extern void tty_hangup(struct tty_struct * tty);
310extern void tty_vhangup(struct tty_struct * tty); 311extern void tty_vhangup(struct tty_struct * tty);
311extern void tty_unhangup(struct file *filp); 312extern void tty_unhangup(struct file *filp);
312extern int tty_hung_up_p(struct file * filp); 313extern int tty_hung_up_p(struct file * filp);
314extern int is_tty(struct file *filp);
313extern void do_SAK(struct tty_struct *tty); 315extern void do_SAK(struct tty_struct *tty);
314extern void __do_SAK(struct tty_struct *tty); 316extern void __do_SAK(struct tty_struct *tty);
315extern void disassociate_ctty(int priv); 317extern void disassociate_ctty(int priv);
@@ -347,6 +349,37 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
347/* n_tty.c */ 349/* n_tty.c */
348extern struct tty_ldisc tty_ldisc_N_TTY; 350extern struct tty_ldisc tty_ldisc_N_TTY;
349 351
352/* tty_audit.c */
353#ifdef CONFIG_AUDIT
354extern void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
355 size_t size);
356extern void tty_audit_exit(void);
357extern void tty_audit_fork(struct signal_struct *sig);
358extern void tty_audit_push(struct tty_struct *tty);
359extern void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid);
360extern void tty_audit_opening(void);
361#else
362static inline void tty_audit_add_data(struct tty_struct *tty,
363 unsigned char *data, size_t size)
364{
365}
366static inline void tty_audit_exit(void)
367{
368}
369static inline void tty_audit_fork(struct signal_struct *sig)
370{
371}
372static inline void tty_audit_push(struct tty_struct *tty)
373{
374}
375static inline void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
376{
377}
378static inline void tty_audit_opening(void)
379{
380}
381#endif
382
350/* tty_ioctl.c */ 383/* tty_ioctl.c */
351extern int n_tty_ioctl(struct tty_struct * tty, struct file * file, 384extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
352 unsigned int cmd, unsigned long arg); 385 unsigned int cmd, unsigned long arg);
diff --git a/kernel/audit.c b/kernel/audit.c
index d13276d41410..5ce8851facf7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -58,6 +58,7 @@
58#include <linux/selinux.h> 58#include <linux/selinux.h>
59#include <linux/inotify.h> 59#include <linux/inotify.h>
60#include <linux/freezer.h> 60#include <linux/freezer.h>
61#include <linux/tty.h>
61 62
62#include "audit.h" 63#include "audit.h"
63 64
@@ -423,6 +424,31 @@ static int kauditd_thread(void *dummy)
423 return 0; 424 return 0;
424} 425}
425 426
427static int audit_prepare_user_tty(pid_t pid, uid_t loginuid)
428{
429 struct task_struct *tsk;
430 int err;
431
432 read_lock(&tasklist_lock);
433 tsk = find_task_by_pid(pid);
434 err = -ESRCH;
435 if (!tsk)
436 goto out;
437 err = 0;
438
439 spin_lock_irq(&tsk->sighand->siglock);
440 if (!tsk->signal->audit_tty)
441 err = -EPERM;
442 spin_unlock_irq(&tsk->sighand->siglock);
443 if (err)
444 goto out;
445
446 tty_audit_push_task(tsk, loginuid);
447out:
448 read_unlock(&tasklist_lock);
449 return err;
450}
451
426int audit_send_list(void *_dest) 452int audit_send_list(void *_dest)
427{ 453{
428 struct audit_netlink_list *dest = _dest; 454 struct audit_netlink_list *dest = _dest;
@@ -511,6 +537,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
511 case AUDIT_DEL: 537 case AUDIT_DEL:
512 case AUDIT_DEL_RULE: 538 case AUDIT_DEL_RULE:
513 case AUDIT_SIGNAL_INFO: 539 case AUDIT_SIGNAL_INFO:
540 case AUDIT_TTY_GET:
541 case AUDIT_TTY_SET:
514 if (security_netlink_recv(skb, CAP_AUDIT_CONTROL)) 542 if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
515 err = -EPERM; 543 err = -EPERM;
516 break; 544 break;
@@ -622,6 +650,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
622 err = audit_filter_user(&NETLINK_CB(skb), msg_type); 650 err = audit_filter_user(&NETLINK_CB(skb), msg_type);
623 if (err == 1) { 651 if (err == 1) {
624 err = 0; 652 err = 0;
653 if (msg_type == AUDIT_USER_TTY) {
654 err = audit_prepare_user_tty(pid, loginuid);
655 if (err)
656 break;
657 }
625 ab = audit_log_start(NULL, GFP_KERNEL, msg_type); 658 ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
626 if (ab) { 659 if (ab) {
627 audit_log_format(ab, 660 audit_log_format(ab,
@@ -638,8 +671,17 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
638 " subj=%s", ctx); 671 " subj=%s", ctx);
639 kfree(ctx); 672 kfree(ctx);
640 } 673 }
641 audit_log_format(ab, " msg='%.1024s'", 674 if (msg_type != AUDIT_USER_TTY)
642 (char *)data); 675 audit_log_format(ab, " msg='%.1024s'",
676 (char *)data);
677 else {
678 int size;
679
680 audit_log_format(ab, " msg=");
681 size = nlmsg_len(nlh);
682 audit_log_n_untrustedstring(ab, size,
683 data);
684 }
643 audit_set_pid(ab, pid); 685 audit_set_pid(ab, pid);
644 audit_log_end(ab); 686 audit_log_end(ab);
645 } 687 }
@@ -730,6 +772,45 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
730 0, 0, sig_data, sizeof(*sig_data) + len); 772 0, 0, sig_data, sizeof(*sig_data) + len);
731 kfree(sig_data); 773 kfree(sig_data);
732 break; 774 break;
775 case AUDIT_TTY_GET: {
776 struct audit_tty_status s;
777 struct task_struct *tsk;
778
779 read_lock(&tasklist_lock);
780 tsk = find_task_by_pid(pid);
781 if (!tsk)
782 err = -ESRCH;
783 else {
784 spin_lock_irq(&tsk->sighand->siglock);
785 s.enabled = tsk->signal->audit_tty != 0;
786 spin_unlock_irq(&tsk->sighand->siglock);
787 }
788 read_unlock(&tasklist_lock);
789 audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_TTY_GET, 0, 0,
790 &s, sizeof(s));
791 break;
792 }
793 case AUDIT_TTY_SET: {
794 struct audit_tty_status *s;
795 struct task_struct *tsk;
796
797 if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
798 return -EINVAL;
799 s = data;
800 if (s->enabled != 0 && s->enabled != 1)
801 return -EINVAL;
802 read_lock(&tasklist_lock);
803 tsk = find_task_by_pid(pid);
804 if (!tsk)
805 err = -ESRCH;
806 else {
807 spin_lock_irq(&tsk->sighand->siglock);
808 tsk->signal->audit_tty = s->enabled != 0;
809 spin_unlock_irq(&tsk->sighand->siglock);
810 }
811 read_unlock(&tasklist_lock);
812 break;
813 }
733 default: 814 default:
734 err = -EINVAL; 815 err = -EINVAL;
735 break; 816 break;
@@ -1185,7 +1266,7 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
1185} 1266}
1186 1267
1187/** 1268/**
1188 * audit_log_n_unstrustedstring - log a string that may contain random characters 1269 * audit_log_n_untrustedstring - log a string that may contain random characters
1189 * @ab: audit_buffer 1270 * @ab: audit_buffer
1190 * @len: lenth of string (not including trailing null) 1271 * @len: lenth of string (not including trailing null)
1191 * @string: string to be logged 1272 * @string: string to be logged
@@ -1201,25 +1282,24 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
1201const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len, 1282const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
1202 const char *string) 1283 const char *string)
1203{ 1284{
1204 const unsigned char *p = string; 1285 const unsigned char *p;
1205 1286
1206 while (*p) { 1287 for (p = string; p < (const unsigned char *)string + len && *p; p++) {
1207 if (*p == '"' || *p < 0x21 || *p > 0x7f) { 1288 if (*p == '"' || *p < 0x21 || *p > 0x7f) {
1208 audit_log_hex(ab, string, len); 1289 audit_log_hex(ab, string, len);
1209 return string + len + 1; 1290 return string + len + 1;
1210 } 1291 }
1211 p++;
1212 } 1292 }
1213 audit_log_n_string(ab, len, string); 1293 audit_log_n_string(ab, len, string);
1214 return p + 1; 1294 return p + 1;
1215} 1295}
1216 1296
1217/** 1297/**
1218 * audit_log_unstrustedstring - log a string that may contain random characters 1298 * audit_log_untrustedstring - log a string that may contain random characters
1219 * @ab: audit_buffer 1299 * @ab: audit_buffer
1220 * @string: string to be logged 1300 * @string: string to be logged
1221 * 1301 *
1222 * Same as audit_log_n_unstrustedstring(), except that strlen is used to 1302 * Same as audit_log_n_untrustedstring(), except that strlen is used to
1223 * determine string length. 1303 * determine string length.
1224 */ 1304 */
1225const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string) 1305const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
diff --git a/kernel/audit.h b/kernel/audit.h
index 815d6f5c04ee..95877435c347 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -115,7 +115,6 @@ extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
115extern void audit_send_reply(int pid, int seq, int type, 115extern void audit_send_reply(int pid, int seq, int type,
116 int done, int multi, 116 int done, int multi,
117 void *payload, int size); 117 void *payload, int size);
118extern void audit_log_lost(const char *message);
119extern void audit_panic(const char *message); 118extern void audit_panic(const char *message);
120 119
121struct audit_netlink_list { 120struct audit_netlink_list {
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e36481ed61b4..7ccc3da30a91 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -71,9 +71,6 @@
71 71
72extern struct list_head audit_filter_list[]; 72extern struct list_head audit_filter_list[];
73 73
74/* No syscall auditing will take place unless audit_enabled != 0. */
75extern int audit_enabled;
76
77/* AUDIT_NAMES is the number of slots we reserve in the audit_context 74/* AUDIT_NAMES is the number of slots we reserve in the audit_context
78 * for saving names from getname(). */ 75 * for saving names from getname(). */
79#define AUDIT_NAMES 20 76#define AUDIT_NAMES 20
diff --git a/kernel/exit.c b/kernel/exit.c
index 64a5263c8c7b..57626692cd90 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -965,6 +965,8 @@ fastcall NORET_TYPE void do_exit(long code)
965 if (unlikely(tsk->compat_robust_list)) 965 if (unlikely(tsk->compat_robust_list))
966 compat_exit_robust_list(tsk); 966 compat_exit_robust_list(tsk);
967#endif 967#endif
968 if (group_dead)
969 tty_audit_exit();
968 if (unlikely(tsk->audit_context)) 970 if (unlikely(tsk->audit_context))
969 audit_free(tsk); 971 audit_free(tsk);
970 972
diff --git a/kernel/fork.c b/kernel/fork.c
index 344d693fdc78..4015912aaac2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -49,6 +49,7 @@
49#include <linux/delayacct.h> 49#include <linux/delayacct.h>
50#include <linux/taskstats_kern.h> 50#include <linux/taskstats_kern.h>
51#include <linux/random.h> 51#include <linux/random.h>
52#include <linux/tty.h>
52 53
53#include <asm/pgtable.h> 54#include <asm/pgtable.h>
54#include <asm/pgalloc.h> 55#include <asm/pgalloc.h>
@@ -897,6 +898,8 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
897 } 898 }
898 acct_init_pacct(&sig->pacct); 899 acct_init_pacct(&sig->pacct);
899 900
901 tty_audit_fork(sig);
902
900 return 0; 903 return 0;
901} 904}
902 905
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 42f12bd65964..89dcc485653b 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -46,10 +46,6 @@
46#include "netlabel_cipso_v4.h" 46#include "netlabel_cipso_v4.h"
47#include "netlabel_user.h" 47#include "netlabel_user.h"
48 48
49/* do not do any auditing if audit_enabled == 0, see kernel/audit.c for
50 * details */
51extern int audit_enabled;
52
53/* 49/*
54 * NetLabel NETLINK Setup Functions 50 * NetLabel NETLINK Setup Functions
55 */ 51 */
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index ccfe8755735e..eddc7b420109 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -110,6 +110,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
110 { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, 110 { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
111 { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, 111 { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
112 { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, 112 { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
113 { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
114 { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
113}; 115};
114 116
115 117