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