Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Creating audit events from TTY input.
4 : *
5 : * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
6 : *
7 : * Authors: Miloslav Trmac <[email protected]>
8 : */
9 :
10 : #include <linux/audit.h>
11 : #include <linux/slab.h>
12 : #include <linux/tty.h>
13 : #include "tty.h"
14 :
15 : #define TTY_AUDIT_BUF_SIZE 4096
16 :
17 : struct tty_audit_buf {
18 : struct mutex mutex; /* Protects all data below */
19 : dev_t dev; /* The TTY which the data is from */
20 : bool icanon;
21 : size_t valid;
22 : u8 *data; /* Allocated size TTY_AUDIT_BUF_SIZE */
23 : };
24 :
25 0 : static struct tty_audit_buf *tty_audit_buf_ref(void)
26 : {
27 0 : struct tty_audit_buf *buf;
28 :
29 0 : buf = current->signal->tty_audit_buf;
30 0 : WARN_ON(buf == ERR_PTR(-ESRCH));
31 0 : return buf;
32 0 : }
33 :
34 0 : static struct tty_audit_buf *tty_audit_buf_alloc(void)
35 : {
36 0 : struct tty_audit_buf *buf;
37 :
38 0 : buf = kzalloc(sizeof(*buf), GFP_KERNEL);
39 0 : if (!buf)
40 0 : goto err;
41 :
42 0 : buf->data = kmalloc(TTY_AUDIT_BUF_SIZE, GFP_KERNEL);
43 0 : if (!buf->data)
44 0 : goto err_buf;
45 :
46 0 : mutex_init(&buf->mutex);
47 :
48 0 : return buf;
49 :
50 : err_buf:
51 0 : kfree(buf);
52 : err:
53 0 : return NULL;
54 0 : }
55 :
56 0 : static void tty_audit_buf_free(struct tty_audit_buf *buf)
57 : {
58 0 : WARN_ON(buf->valid != 0);
59 0 : kfree(buf->data);
60 0 : kfree(buf);
61 0 : }
62 :
63 0 : static void tty_audit_log(const char *description, dev_t dev,
64 : const u8 *data, size_t size)
65 : {
66 0 : struct audit_buffer *ab;
67 0 : pid_t pid = task_pid_nr(current);
68 0 : uid_t uid = from_kuid(&init_user_ns, task_uid(current));
69 0 : uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
70 0 : unsigned int sessionid = audit_get_sessionid(current);
71 0 : char name[TASK_COMM_LEN];
72 :
73 0 : ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_TTY);
74 0 : if (!ab)
75 0 : return;
76 :
77 0 : audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d minor=%d comm=",
78 0 : description, pid, uid, loginuid, sessionid,
79 0 : MAJOR(dev), MINOR(dev));
80 0 : get_task_comm(name, current);
81 0 : audit_log_untrustedstring(ab, name);
82 0 : audit_log_format(ab, " data=");
83 0 : audit_log_n_hex(ab, data, size);
84 0 : audit_log_end(ab);
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 0 : return;
97 0 : if (audit_enabled == AUDIT_OFF) {
98 0 : buf->valid = 0;
99 0 : return;
100 : }
101 0 : tty_audit_log("tty", buf->dev, buf->data, buf->valid);
102 0 : buf->valid = 0;
103 0 : }
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 : * The process is single-threaded at this point; no other threads share
112 : * current->signal.
113 : */
114 29 : void tty_audit_exit(void)
115 : {
116 29 : struct tty_audit_buf *buf;
117 :
118 29 : buf = xchg(¤t->signal->tty_audit_buf, ERR_PTR(-ESRCH));
119 29 : if (!buf)
120 29 : return;
121 :
122 0 : tty_audit_buf_push(buf);
123 0 : tty_audit_buf_free(buf);
124 29 : }
125 :
126 : /*
127 : * tty_audit_fork - Copy TTY audit state for a new task
128 : *
129 : * Set up TTY audit state in @sig from current. @sig needs no locking.
130 : */
131 31 : void tty_audit_fork(struct signal_struct *sig)
132 : {
133 31 : sig->audit_tty = current->signal->audit_tty;
134 31 : }
135 :
136 : /*
137 : * tty_audit_tiocsti - Log TIOCSTI
138 : */
139 0 : void tty_audit_tiocsti(const struct tty_struct *tty, u8 ch)
140 : {
141 0 : dev_t dev;
142 :
143 0 : dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
144 0 : if (tty_audit_push())
145 0 : return;
146 :
147 0 : if (audit_enabled)
148 0 : tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1);
149 0 : }
150 :
151 : /*
152 : * tty_audit_push - Flush current's pending audit data
153 : *
154 : * Returns 0 if success, -EPERM if tty audit is disabled
155 : */
156 0 : int tty_audit_push(void)
157 : {
158 0 : struct tty_audit_buf *buf;
159 :
160 0 : if (~current->signal->audit_tty & AUDIT_TTY_ENABLE)
161 0 : return -EPERM;
162 :
163 0 : buf = tty_audit_buf_ref();
164 0 : if (!IS_ERR_OR_NULL(buf)) {
165 0 : mutex_lock(&buf->mutex);
166 0 : tty_audit_buf_push(buf);
167 0 : mutex_unlock(&buf->mutex);
168 0 : }
169 0 : return 0;
170 0 : }
171 :
172 : /*
173 : * tty_audit_buf_get - Get an audit buffer.
174 : *
175 : * Get an audit buffer, allocate it if necessary. Return %NULL
176 : * if out of memory or ERR_PTR(-ESRCH) if tty_audit_exit() has already
177 : * occurred. Otherwise, return a new reference to the buffer.
178 : */
179 0 : static struct tty_audit_buf *tty_audit_buf_get(void)
180 : {
181 0 : struct tty_audit_buf *buf;
182 :
183 0 : buf = tty_audit_buf_ref();
184 0 : if (buf)
185 0 : return buf;
186 :
187 0 : buf = tty_audit_buf_alloc();
188 0 : if (buf == NULL) {
189 0 : audit_log_lost("out of memory in TTY auditing");
190 0 : return NULL;
191 : }
192 :
193 : /* Race to use this buffer, free it if another wins */
194 0 : if (cmpxchg(¤t->signal->tty_audit_buf, NULL, buf) != NULL)
195 0 : tty_audit_buf_free(buf);
196 0 : return tty_audit_buf_ref();
197 0 : }
198 :
199 : /*
200 : * tty_audit_add_data - Add data for TTY auditing.
201 : *
202 : * Audit @data of @size from @tty, if necessary.
203 : */
204 25 : void tty_audit_add_data(const struct tty_struct *tty, const void *data,
205 : size_t size)
206 : {
207 25 : struct tty_audit_buf *buf;
208 25 : unsigned int audit_tty;
209 25 : bool icanon = L_ICANON(tty);
210 25 : dev_t dev;
211 :
212 25 : audit_tty = READ_ONCE(current->signal->audit_tty);
213 25 : if (~audit_tty & AUDIT_TTY_ENABLE)
214 25 : return;
215 :
216 0 : if (unlikely(size == 0))
217 0 : return;
218 :
219 0 : if (tty->driver->type == TTY_DRIVER_TYPE_PTY
220 0 : && tty->driver->subtype == PTY_TYPE_MASTER)
221 0 : return;
222 :
223 0 : if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty))
224 0 : return;
225 :
226 0 : buf = tty_audit_buf_get();
227 0 : if (IS_ERR_OR_NULL(buf))
228 0 : return;
229 :
230 0 : mutex_lock(&buf->mutex);
231 0 : dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
232 0 : if (buf->dev != dev || buf->icanon != icanon) {
233 0 : tty_audit_buf_push(buf);
234 0 : buf->dev = dev;
235 0 : buf->icanon = icanon;
236 0 : }
237 0 : do {
238 0 : size_t run;
239 :
240 0 : run = TTY_AUDIT_BUF_SIZE - buf->valid;
241 0 : if (run > size)
242 0 : run = size;
243 0 : memcpy(buf->data + buf->valid, data, run);
244 0 : buf->valid += run;
245 0 : data += run;
246 0 : size -= run;
247 0 : if (buf->valid == TTY_AUDIT_BUF_SIZE)
248 0 : tty_audit_buf_push(buf);
249 0 : } while (size != 0);
250 0 : mutex_unlock(&buf->mutex);
251 25 : }
|