linux/drivers/tty/tty_audit.c
<<
>>
Prefs
   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
  16struct 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
  25static 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
  44err_buf:
  45        kfree(buf);
  46err:
  47        return NULL;
  48}
  49
  50static 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
  57static 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
  63static 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 */
  94static 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 */
 112void 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 */
 133void 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 */
 142void 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(&current->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(&current->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 */
 181int 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 */
 219static 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(&current->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(&current->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(&current->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(&current->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 */
 268void tty_audit_add_data(struct tty_struct *tty, const void *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(&current->sighand->siglock, flags);
 280        audit_log_tty_passwd = current->signal->audit_tty_log_passwd;
 281        spin_unlock_irqrestore(&current->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 */
 325void tty_audit_push(struct tty_struct *tty)
 326{
 327        struct tty_audit_buf *buf;
 328        unsigned long flags;
 329
 330        spin_lock_irqsave(&current->sighand->siglock, flags);
 331        if (likely(!current->signal->audit_tty)) {
 332                spin_unlock_irqrestore(&current->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(&current->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