LCOV - code coverage report
Current view: top level - tty - tty_audit.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 13.3 % 135 18
Test Date: 2025-08-26 15:45:50 Functions: 27.3 % 11 3

            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 <[email protected]>
       8              :  */
       9              : 
      10              : #include <linux/audit.h>
      11              : #include <linux/slab.h>
      12              : #include <linux/tty.h>
      13              : #include "tty.h"
      14              : 
      15              : #define TTY_AUDIT_BUF_SIZE      4096
      16              : 
      17              : struct tty_audit_buf {
      18              :         struct mutex mutex;     /* Protects all data below */
      19              :         dev_t dev;              /* The TTY which the data is from */
      20              :         bool icanon;
      21              :         size_t valid;
      22              :         u8 *data;               /* Allocated size TTY_AUDIT_BUF_SIZE */
      23              : };
      24              : 
      25            0 : static struct tty_audit_buf *tty_audit_buf_ref(void)
      26              : {
      27            0 :         struct tty_audit_buf *buf;
      28              : 
      29            0 :         buf = current->signal->tty_audit_buf;
      30            0 :         WARN_ON(buf == ERR_PTR(-ESRCH));
      31            0 :         return buf;
      32            0 : }
      33              : 
      34            0 : static struct tty_audit_buf *tty_audit_buf_alloc(void)
      35              : {
      36            0 :         struct tty_audit_buf *buf;
      37              : 
      38            0 :         buf = kzalloc(sizeof(*buf), GFP_KERNEL);
      39            0 :         if (!buf)
      40            0 :                 goto err;
      41              : 
      42            0 :         buf->data = kmalloc(TTY_AUDIT_BUF_SIZE, GFP_KERNEL);
      43            0 :         if (!buf->data)
      44            0 :                 goto err_buf;
      45              : 
      46            0 :         mutex_init(&buf->mutex);
      47              : 
      48            0 :         return buf;
      49              : 
      50              : err_buf:
      51            0 :         kfree(buf);
      52              : err:
      53            0 :         return NULL;
      54            0 : }
      55              : 
      56            0 : static void tty_audit_buf_free(struct tty_audit_buf *buf)
      57              : {
      58            0 :         WARN_ON(buf->valid != 0);
      59            0 :         kfree(buf->data);
      60            0 :         kfree(buf);
      61            0 : }
      62              : 
      63            0 : static void tty_audit_log(const char *description, dev_t dev,
      64              :                           const u8 *data, size_t size)
      65              : {
      66            0 :         struct audit_buffer *ab;
      67            0 :         pid_t pid = task_pid_nr(current);
      68            0 :         uid_t uid = from_kuid(&init_user_ns, task_uid(current));
      69            0 :         uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
      70            0 :         unsigned int sessionid = audit_get_sessionid(current);
      71            0 :         char name[TASK_COMM_LEN];
      72              : 
      73            0 :         ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_TTY);
      74            0 :         if (!ab)
      75            0 :                 return;
      76              : 
      77            0 :         audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d minor=%d comm=",
      78            0 :                          description, pid, uid, loginuid, sessionid,
      79            0 :                          MAJOR(dev), MINOR(dev));
      80            0 :         get_task_comm(name, current);
      81            0 :         audit_log_untrustedstring(ab, name);
      82            0 :         audit_log_format(ab, " data=");
      83            0 :         audit_log_n_hex(ab, data, size);
      84            0 :         audit_log_end(ab);
      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            0 :                 return;
      97            0 :         if (audit_enabled == AUDIT_OFF) {
      98            0 :                 buf->valid = 0;
      99            0 :                 return;
     100              :         }
     101            0 :         tty_audit_log("tty", buf->dev, buf->data, buf->valid);
     102            0 :         buf->valid = 0;
     103            0 : }
     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              :  *      The process is single-threaded at this point; no other threads share
     112              :  *      current->signal.
     113              :  */
     114           29 : void tty_audit_exit(void)
     115              : {
     116           29 :         struct tty_audit_buf *buf;
     117              : 
     118           29 :         buf = xchg(&current->signal->tty_audit_buf, ERR_PTR(-ESRCH));
     119           29 :         if (!buf)
     120           29 :                 return;
     121              : 
     122            0 :         tty_audit_buf_push(buf);
     123            0 :         tty_audit_buf_free(buf);
     124           29 : }
     125              : 
     126              : /*
     127              :  *      tty_audit_fork  -       Copy TTY audit state for a new task
     128              :  *
     129              :  *      Set up TTY audit state in @sig from current.  @sig needs no locking.
     130              :  */
     131           31 : void tty_audit_fork(struct signal_struct *sig)
     132              : {
     133           31 :         sig->audit_tty = current->signal->audit_tty;
     134           31 : }
     135              : 
     136              : /*
     137              :  *      tty_audit_tiocsti       -       Log TIOCSTI
     138              :  */
     139            0 : void tty_audit_tiocsti(const struct tty_struct *tty, u8 ch)
     140              : {
     141            0 :         dev_t dev;
     142              : 
     143            0 :         dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
     144            0 :         if (tty_audit_push())
     145            0 :                 return;
     146              : 
     147            0 :         if (audit_enabled)
     148            0 :                 tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1);
     149            0 : }
     150              : 
     151              : /*
     152              :  *      tty_audit_push  -       Flush current's pending audit data
     153              :  *
     154              :  *      Returns 0 if success, -EPERM if tty audit is disabled
     155              :  */
     156            0 : int tty_audit_push(void)
     157              : {
     158            0 :         struct tty_audit_buf *buf;
     159              : 
     160            0 :         if (~current->signal->audit_tty & AUDIT_TTY_ENABLE)
     161            0 :                 return -EPERM;
     162              : 
     163            0 :         buf = tty_audit_buf_ref();
     164            0 :         if (!IS_ERR_OR_NULL(buf)) {
     165            0 :                 mutex_lock(&buf->mutex);
     166            0 :                 tty_audit_buf_push(buf);
     167            0 :                 mutex_unlock(&buf->mutex);
     168            0 :         }
     169            0 :         return 0;
     170            0 : }
     171              : 
     172              : /*
     173              :  *      tty_audit_buf_get       -       Get an audit buffer.
     174              :  *
     175              :  *      Get an audit buffer, allocate it if necessary.  Return %NULL
     176              :  *      if out of memory or ERR_PTR(-ESRCH) if tty_audit_exit() has already
     177              :  *      occurred.  Otherwise, return a new reference to the buffer.
     178              :  */
     179            0 : static struct tty_audit_buf *tty_audit_buf_get(void)
     180              : {
     181            0 :         struct tty_audit_buf *buf;
     182              : 
     183            0 :         buf = tty_audit_buf_ref();
     184            0 :         if (buf)
     185            0 :                 return buf;
     186              : 
     187            0 :         buf = tty_audit_buf_alloc();
     188            0 :         if (buf == NULL) {
     189            0 :                 audit_log_lost("out of memory in TTY auditing");
     190            0 :                 return NULL;
     191              :         }
     192              : 
     193              :         /* Race to use this buffer, free it if another wins */
     194            0 :         if (cmpxchg(&current->signal->tty_audit_buf, NULL, buf) != NULL)
     195            0 :                 tty_audit_buf_free(buf);
     196            0 :         return tty_audit_buf_ref();
     197            0 : }
     198              : 
     199              : /*
     200              :  *      tty_audit_add_data      -       Add data for TTY auditing.
     201              :  *
     202              :  *      Audit @data of @size from @tty, if necessary.
     203              :  */
     204           25 : void tty_audit_add_data(const struct tty_struct *tty, const void *data,
     205              :                         size_t size)
     206              : {
     207           25 :         struct tty_audit_buf *buf;
     208           25 :         unsigned int audit_tty;
     209           25 :         bool icanon = L_ICANON(tty);
     210           25 :         dev_t dev;
     211              : 
     212           25 :         audit_tty = READ_ONCE(current->signal->audit_tty);
     213           25 :         if (~audit_tty & AUDIT_TTY_ENABLE)
     214           25 :                 return;
     215              : 
     216            0 :         if (unlikely(size == 0))
     217            0 :                 return;
     218              : 
     219            0 :         if (tty->driver->type == TTY_DRIVER_TYPE_PTY
     220            0 :             && tty->driver->subtype == PTY_TYPE_MASTER)
     221            0 :                 return;
     222              : 
     223            0 :         if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty))
     224            0 :                 return;
     225              : 
     226            0 :         buf = tty_audit_buf_get();
     227            0 :         if (IS_ERR_OR_NULL(buf))
     228            0 :                 return;
     229              : 
     230            0 :         mutex_lock(&buf->mutex);
     231            0 :         dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
     232            0 :         if (buf->dev != dev || buf->icanon != icanon) {
     233            0 :                 tty_audit_buf_push(buf);
     234            0 :                 buf->dev = dev;
     235            0 :                 buf->icanon = icanon;
     236            0 :         }
     237            0 :         do {
     238            0 :                 size_t run;
     239              : 
     240            0 :                 run = TTY_AUDIT_BUF_SIZE - buf->valid;
     241            0 :                 if (run > size)
     242            0 :                         run = size;
     243            0 :                 memcpy(buf->data + buf->valid, data, run);
     244            0 :                 buf->valid += run;
     245            0 :                 data += run;
     246            0 :                 size -= run;
     247            0 :                 if (buf->valid == TTY_AUDIT_BUF_SIZE)
     248            0 :                         tty_audit_buf_push(buf);
     249            0 :         } while (size != 0);
     250            0 :         mutex_unlock(&buf->mutex);
     251           25 : }
        

Generated by: LCOV version 2.0-1