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