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 : 3 : void tty_audit_exit(void) 112 : : { 113 : : struct tty_audit_buf *buf; 114 : : 115 : 3 : buf = xchg(¤t->signal->tty_audit_buf, ERR_PTR(-ESRCH)); 116 : 3 : if (!buf) 117 : 3 : 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 : 3 : void tty_audit_fork(struct signal_struct *sig) 129 : : { 130 : 3 : sig->audit_tty = current->signal->audit_tty; 131 : 3 : } 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 : 1 : int tty_audit_push(void) 154 : : { 155 : : struct tty_audit_buf *buf; 156 : : 157 : 1 : 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 : 3 : void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size) 202 : : { 203 : : struct tty_audit_buf *buf; 204 : 3 : unsigned int icanon = !!L_ICANON(tty); 205 : : unsigned int audit_tty; 206 : : dev_t dev; 207 : : 208 : 3 : audit_tty = READ_ONCE(current->signal->audit_tty); 209 : 3 : 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 : : }