LCOV - code coverage report
Current view: top level - drivers/tty - tty_audit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 24 153 15.7 %
Date: 2014-02-18 Functions: 5 12 41.7 %
Branches: 9 82 11.0 %

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

Generated by: LCOV version 1.9