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/slab.h> 14 #include <linux/tty.h> 15 16 struct 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 25 static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, 26 unsigned icanon) 27 { 28 struct tty_audit_buf *buf; 29 30 buf = kmalloc(sizeof(*buf), GFP_KERNEL); 31 if (!buf) 32 goto err; 33 buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL); 34 if (!buf->data) 35 goto err_buf; 36 atomic_set(&buf->count, 1); 37 mutex_init(&buf->mutex); 38 buf->major = major; 39 buf->minor = minor; 40 buf->icanon = icanon; 41 buf->valid = 0; 42 return buf; 43 44 err_buf: 45 kfree(buf); 46 err: 47 return NULL; 48 } 49 50 static void tty_audit_buf_free(struct tty_audit_buf *buf) 51 { 52 WARN_ON(buf->valid != 0); 53 kfree(buf->data); 54 kfree(buf); 55 } 56 57 static void tty_audit_buf_put(struct tty_audit_buf *buf) 58 { 59 if (atomic_dec_and_test(&buf->count)) 60 tty_audit_buf_free(buf); 61 } 62 63 static void tty_audit_log(const char *description, int major, int minor, 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, minor); 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->major, buf->minor, 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 void tty_audit_exit(void) 113 { 114 struct tty_audit_buf *buf; 115 116 buf = current->signal->tty_audit_buf; 117 current->signal->tty_audit_buf = NULL; 118 if (!buf) 119 return; 120 121 mutex_lock(&buf->mutex); 122 tty_audit_buf_push(buf); 123 mutex_unlock(&buf->mutex); 124 125 tty_audit_buf_put(buf); 126 } 127 128 /** 129 * tty_audit_fork - Copy TTY audit state for a new task 130 * 131 * Set up TTY audit state in @sig from current. @sig needs no locking. 132 */ 133 void tty_audit_fork(struct signal_struct *sig) 134 { 135 sig->audit_tty = current->signal->audit_tty; 136 sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd; 137 } 138 139 /** 140 * tty_audit_tiocsti - Log TIOCSTI 141 */ 142 void tty_audit_tiocsti(struct tty_struct *tty, char ch) 143 { 144 struct tty_audit_buf *buf; 145 int major, minor, should_audit; 146 unsigned long flags; 147 148 spin_lock_irqsave(¤t->sighand->siglock, flags); 149 should_audit = current->signal->audit_tty; 150 buf = current->signal->tty_audit_buf; 151 if (buf) 152 atomic_inc(&buf->count); 153 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 154 155 major = tty->driver->major; 156 minor = tty->driver->minor_start + tty->index; 157 if (buf) { 158 mutex_lock(&buf->mutex); 159 if (buf->major == major && buf->minor == minor) 160 tty_audit_buf_push(buf); 161 mutex_unlock(&buf->mutex); 162 tty_audit_buf_put(buf); 163 } 164 165 if (should_audit && audit_enabled) { 166 kuid_t auid; 167 unsigned int sessionid; 168 169 auid = audit_get_loginuid(current); 170 sessionid = audit_get_sessionid(current); 171 tty_audit_log("ioctl=TIOCSTI", major, minor, &ch, 1); 172 } 173 } 174 175 /** 176 * tty_audit_push_current - Flush current's pending audit data 177 * 178 * Try to lock sighand and get a reference to the tty audit buffer if available. 179 * Flush the buffer or return an appropriate error code. 180 */ 181 int tty_audit_push_current(void) 182 { 183 struct tty_audit_buf *buf = ERR_PTR(-EPERM); 184 struct task_struct *tsk = current; 185 unsigned long flags; 186 187 if (!lock_task_sighand(tsk, &flags)) 188 return -ESRCH; 189 190 if (tsk->signal->audit_tty) { 191 buf = tsk->signal->tty_audit_buf; 192 if (buf) 193 atomic_inc(&buf->count); 194 } 195 unlock_task_sighand(tsk, &flags); 196 197 /* 198 * Return 0 when signal->audit_tty set 199 * but tsk->signal->tty_audit_buf == NULL. 200 */ 201 if (!buf || IS_ERR(buf)) 202 return PTR_ERR(buf); 203 204 mutex_lock(&buf->mutex); 205 tty_audit_buf_push(buf); 206 mutex_unlock(&buf->mutex); 207 208 tty_audit_buf_put(buf); 209 return 0; 210 } 211 212 /** 213 * tty_audit_buf_get - Get an audit buffer. 214 * 215 * Get an audit buffer for @tty, allocate it if necessary. Return %NULL 216 * if TTY auditing is disabled or out of memory. Otherwise, return a new 217 * reference to the buffer. 218 */ 219 static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, 220 unsigned icanon) 221 { 222 struct tty_audit_buf *buf, *buf2; 223 unsigned long flags; 224 225 buf = NULL; 226 buf2 = NULL; 227 spin_lock_irqsave(¤t->sighand->siglock, flags); 228 if (likely(!current->signal->audit_tty)) 229 goto out; 230 buf = current->signal->tty_audit_buf; 231 if (buf) { 232 atomic_inc(&buf->count); 233 goto out; 234 } 235 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 236 237 buf2 = tty_audit_buf_alloc(tty->driver->major, 238 tty->driver->minor_start + tty->index, 239 icanon); 240 if (buf2 == NULL) { 241 audit_log_lost("out of memory in TTY auditing"); 242 return NULL; 243 } 244 245 spin_lock_irqsave(¤t->sighand->siglock, flags); 246 if (!current->signal->audit_tty) 247 goto out; 248 buf = current->signal->tty_audit_buf; 249 if (!buf) { 250 current->signal->tty_audit_buf = buf2; 251 buf = buf2; 252 buf2 = NULL; 253 } 254 atomic_inc(&buf->count); 255 /* Fall through */ 256 out: 257 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 258 if (buf2) 259 tty_audit_buf_free(buf2); 260 return buf; 261 } 262 263 /** 264 * tty_audit_add_data - Add data for TTY auditing. 265 * 266 * Audit @data of @size from @tty, if necessary. 267 */ 268 void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, 269 size_t size, unsigned icanon) 270 { 271 struct tty_audit_buf *buf; 272 int major, minor; 273 int audit_log_tty_passwd; 274 unsigned long flags; 275 276 if (unlikely(size == 0)) 277 return; 278 279 spin_lock_irqsave(¤t->sighand->siglock, flags); 280 audit_log_tty_passwd = current->signal->audit_tty_log_passwd; 281 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 282 if (!audit_log_tty_passwd && icanon && !L_ECHO(tty)) 283 return; 284 285 if (tty->driver->type == TTY_DRIVER_TYPE_PTY 286 && tty->driver->subtype == PTY_TYPE_MASTER) 287 return; 288 289 buf = tty_audit_buf_get(tty, icanon); 290 if (!buf) 291 return; 292 293 mutex_lock(&buf->mutex); 294 major = tty->driver->major; 295 minor = tty->driver->minor_start + tty->index; 296 if (buf->major != major || buf->minor != minor 297 || buf->icanon != icanon) { 298 tty_audit_buf_push(buf); 299 buf->major = major; 300 buf->minor = minor; 301 buf->icanon = icanon; 302 } 303 do { 304 size_t run; 305 306 run = N_TTY_BUF_SIZE - buf->valid; 307 if (run > size) 308 run = size; 309 memcpy(buf->data + buf->valid, data, run); 310 buf->valid += run; 311 data += run; 312 size -= run; 313 if (buf->valid == N_TTY_BUF_SIZE) 314 tty_audit_buf_push(buf); 315 } while (size != 0); 316 mutex_unlock(&buf->mutex); 317 tty_audit_buf_put(buf); 318 } 319 320 /** 321 * tty_audit_push - Push buffered data out 322 * 323 * Make sure no audit data is pending for @tty on the current process. 324 */ 325 void tty_audit_push(struct tty_struct *tty) 326 { 327 struct tty_audit_buf *buf; 328 unsigned long flags; 329 330 spin_lock_irqsave(¤t->sighand->siglock, flags); 331 if (likely(!current->signal->audit_tty)) { 332 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 333 return; 334 } 335 buf = current->signal->tty_audit_buf; 336 if (buf) 337 atomic_inc(&buf->count); 338 spin_unlock_irqrestore(¤t->sighand->siglock, flags); 339 340 if (buf) { 341 int major, minor; 342 343 major = tty->driver->major; 344 minor = tty->driver->minor_start + tty->index; 345 mutex_lock(&buf->mutex); 346 if (buf->major == major && buf->minor == minor) 347 tty_audit_buf_push(buf); 348 mutex_unlock(&buf->mutex); 349 tty_audit_buf_put(buf); 350 } 351 } 352