root/drivers/tty/tty_audit.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tty_audit_buf_ref
  2. tty_audit_buf_alloc
  3. tty_audit_buf_free
  4. tty_audit_log
  5. tty_audit_buf_push
  6. tty_audit_exit
  7. tty_audit_fork
  8. tty_audit_tiocsti
  9. tty_audit_push
  10. tty_audit_buf_get
  11. tty_audit_add_data

   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 static struct tty_audit_buf *tty_audit_buf_ref(void)
  23 {
  24         struct tty_audit_buf *buf;
  25 
  26         buf = current->signal->tty_audit_buf;
  27         WARN_ON(buf == ERR_PTR(-ESRCH));
  28         return buf;
  29 }
  30 
  31 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         if (!buf)
  37                 goto err;
  38         buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
  39         if (!buf->data)
  40                 goto err_buf;
  41         mutex_init(&buf->mutex);
  42         buf->dev = MKDEV(0, 0);
  43         buf->icanon = 0;
  44         buf->valid = 0;
  45         return buf;
  46 
  47 err_buf:
  48         kfree(buf);
  49 err:
  50         return NULL;
  51 }
  52 
  53 static void tty_audit_buf_free(struct tty_audit_buf *buf)
  54 {
  55         WARN_ON(buf->valid != 0);
  56         kfree(buf->data);
  57         kfree(buf);
  58 }
  59 
  60 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         pid_t pid = task_pid_nr(current);
  65         uid_t uid = from_kuid(&init_user_ns, task_uid(current));
  66         uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
  67         unsigned int sessionid = audit_get_sessionid(current);
  68 
  69         ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_TTY);
  70         if (ab) {
  71                 char name[sizeof(current->comm)];
  72 
  73                 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                 get_task_comm(name, current);
  77                 audit_log_untrustedstring(ab, name);
  78                 audit_log_format(ab, " data=");
  79                 audit_log_n_hex(ab, data, size);
  80                 audit_log_end(ab);
  81         }
  82 }
  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 static void tty_audit_buf_push(struct tty_audit_buf *buf)
  91 {
  92         if (buf->valid == 0)
  93                 return;
  94         if (audit_enabled == AUDIT_OFF) {
  95                 buf->valid = 0;
  96                 return;
  97         }
  98         tty_audit_log("tty", buf->dev, buf->data, buf->valid);
  99         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 void tty_audit_exit(void)
 112 {
 113         struct tty_audit_buf *buf;
 114 
 115         buf = xchg(&current->signal->tty_audit_buf, ERR_PTR(-ESRCH));
 116         if (!buf)
 117                 return;
 118 
 119         tty_audit_buf_push(buf);
 120         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 void tty_audit_fork(struct signal_struct *sig)
 129 {
 130         sig->audit_tty = current->signal->audit_tty;
 131 }
 132 
 133 /**
 134  *      tty_audit_tiocsti       -       Log TIOCSTI
 135  */
 136 void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 137 {
 138         dev_t dev;
 139 
 140         dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
 141         if (tty_audit_push())
 142                 return;
 143 
 144         if (audit_enabled)
 145                 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 int tty_audit_push(void)
 154 {
 155         struct tty_audit_buf *buf;
 156 
 157         if (~current->signal->audit_tty & AUDIT_TTY_ENABLE)
 158                 return -EPERM;
 159 
 160         buf = tty_audit_buf_ref();
 161         if (!IS_ERR_OR_NULL(buf)) {
 162                 mutex_lock(&buf->mutex);
 163                 tty_audit_buf_push(buf);
 164                 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 static struct tty_audit_buf *tty_audit_buf_get(void)
 177 {
 178         struct tty_audit_buf *buf;
 179 
 180         buf = tty_audit_buf_ref();
 181         if (buf)
 182                 return buf;
 183 
 184         buf = tty_audit_buf_alloc();
 185         if (buf == NULL) {
 186                 audit_log_lost("out of memory in TTY auditing");
 187                 return NULL;
 188         }
 189 
 190         /* Race to use this buffer, free it if another wins */
 191         if (cmpxchg(&current->signal->tty_audit_buf, NULL, buf) != NULL)
 192                 tty_audit_buf_free(buf);
 193         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 void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size)
 202 {
 203         struct tty_audit_buf *buf;
 204         unsigned int icanon = !!L_ICANON(tty);
 205         unsigned int audit_tty;
 206         dev_t dev;
 207 
 208         audit_tty = READ_ONCE(current->signal->audit_tty);
 209         if (~audit_tty & AUDIT_TTY_ENABLE)
 210                 return;
 211 
 212         if (unlikely(size == 0))
 213                 return;
 214 
 215         if (tty->driver->type == TTY_DRIVER_TYPE_PTY
 216             && tty->driver->subtype == PTY_TYPE_MASTER)
 217                 return;
 218 
 219         if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty))
 220                 return;
 221 
 222         buf = tty_audit_buf_get();
 223         if (IS_ERR_OR_NULL(buf))
 224                 return;
 225 
 226         mutex_lock(&buf->mutex);
 227         dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
 228         if (buf->dev != dev || buf->icanon != icanon) {
 229                 tty_audit_buf_push(buf);
 230                 buf->dev = dev;
 231                 buf->icanon = icanon;
 232         }
 233         do {
 234                 size_t run;
 235 
 236                 run = N_TTY_BUF_SIZE - buf->valid;
 237                 if (run > size)
 238                         run = size;
 239                 memcpy(buf->data + buf->valid, data, run);
 240                 buf->valid += run;
 241                 data += run;
 242                 size -= run;
 243                 if (buf->valid == N_TTY_BUF_SIZE)
 244                         tty_audit_buf_push(buf);
 245         } while (size != 0);
 246         mutex_unlock(&buf->mutex);
 247 }

/* [<][>][^][v][top][bottom][index][help] */