LCOV - code coverage report
Current view: top level - drivers/tty - tty_audit.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 13 98 13.3 %
Date: 2020-09-30 20:25:01 Functions: 4 11 36.4 %
Branches: 5 58 8.6 %

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

Generated by: LCOV version 1.14