Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Creating audit events from TTY input.
0004  *
0005  * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.
0006  *
0007  * Authors: Miloslav Trmac <mitr@redhat.com>
0008  */
0009 
0010 #include <linux/audit.h>
0011 #include <linux/slab.h>
0012 #include <linux/tty.h>
0013 #include "tty.h"
0014 
0015 struct tty_audit_buf {
0016     struct mutex mutex; /* Protects all data below */
0017     dev_t dev;      /* The TTY which the data is from */
0018     unsigned icanon:1;
0019     size_t valid;
0020     unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
0021 };
0022 
0023 static struct tty_audit_buf *tty_audit_buf_ref(void)
0024 {
0025     struct tty_audit_buf *buf;
0026 
0027     buf = current->signal->tty_audit_buf;
0028     WARN_ON(buf == ERR_PTR(-ESRCH));
0029     return buf;
0030 }
0031 
0032 static struct tty_audit_buf *tty_audit_buf_alloc(void)
0033 {
0034     struct tty_audit_buf *buf;
0035 
0036     buf = kmalloc(sizeof(*buf), GFP_KERNEL);
0037     if (!buf)
0038         goto err;
0039     buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
0040     if (!buf->data)
0041         goto err_buf;
0042     mutex_init(&buf->mutex);
0043     buf->dev = MKDEV(0, 0);
0044     buf->icanon = 0;
0045     buf->valid = 0;
0046     return buf;
0047 
0048 err_buf:
0049     kfree(buf);
0050 err:
0051     return NULL;
0052 }
0053 
0054 static void tty_audit_buf_free(struct tty_audit_buf *buf)
0055 {
0056     WARN_ON(buf->valid != 0);
0057     kfree(buf->data);
0058     kfree(buf);
0059 }
0060 
0061 static void tty_audit_log(const char *description, dev_t dev,
0062               unsigned char *data, size_t size)
0063 {
0064     struct audit_buffer *ab;
0065     pid_t pid = task_pid_nr(current);
0066     uid_t uid = from_kuid(&init_user_ns, task_uid(current));
0067     uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current));
0068     unsigned int sessionid = audit_get_sessionid(current);
0069 
0070     ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_TTY);
0071     if (ab) {
0072         char name[sizeof(current->comm)];
0073 
0074         audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d"
0075                  " minor=%d comm=", description, pid, uid,
0076                  loginuid, sessionid, MAJOR(dev), MINOR(dev));
0077         get_task_comm(name, current);
0078         audit_log_untrustedstring(ab, name);
0079         audit_log_format(ab, " data=");
0080         audit_log_n_hex(ab, data, size);
0081         audit_log_end(ab);
0082     }
0083 }
0084 
0085 /*
0086  *  tty_audit_buf_push  -   Push buffered data out
0087  *
0088  *  Generate an audit message from the contents of @buf, which is owned by
0089  *  the current task.  @buf->mutex must be locked.
0090  */
0091 static void tty_audit_buf_push(struct tty_audit_buf *buf)
0092 {
0093     if (buf->valid == 0)
0094         return;
0095     if (audit_enabled == AUDIT_OFF) {
0096         buf->valid = 0;
0097         return;
0098     }
0099     tty_audit_log("tty", buf->dev, buf->data, buf->valid);
0100     buf->valid = 0;
0101 }
0102 
0103 /**
0104  *  tty_audit_exit  -   Handle a task exit
0105  *
0106  *  Make sure all buffered data is written out and deallocate the buffer.
0107  *  Only needs to be called if current->signal->tty_audit_buf != %NULL.
0108  *
0109  *  The process is single-threaded at this point; no other threads share
0110  *  current->signal.
0111  */
0112 void tty_audit_exit(void)
0113 {
0114     struct tty_audit_buf *buf;
0115 
0116     buf = xchg(&current->signal->tty_audit_buf, ERR_PTR(-ESRCH));
0117     if (!buf)
0118         return;
0119 
0120     tty_audit_buf_push(buf);
0121     tty_audit_buf_free(buf);
0122 }
0123 
0124 /*
0125  *  tty_audit_fork  -   Copy TTY audit state for a new task
0126  *
0127  *  Set up TTY audit state in @sig from current.  @sig needs no locking.
0128  */
0129 void tty_audit_fork(struct signal_struct *sig)
0130 {
0131     sig->audit_tty = current->signal->audit_tty;
0132 }
0133 
0134 /*
0135  *  tty_audit_tiocsti   -   Log TIOCSTI
0136  */
0137 void tty_audit_tiocsti(struct tty_struct *tty, char ch)
0138 {
0139     dev_t dev;
0140 
0141     dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
0142     if (tty_audit_push())
0143         return;
0144 
0145     if (audit_enabled)
0146         tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1);
0147 }
0148 
0149 /*
0150  *  tty_audit_push  -   Flush current's pending audit data
0151  *
0152  *  Returns 0 if success, -EPERM if tty audit is disabled
0153  */
0154 int tty_audit_push(void)
0155 {
0156     struct tty_audit_buf *buf;
0157 
0158     if (~current->signal->audit_tty & AUDIT_TTY_ENABLE)
0159         return -EPERM;
0160 
0161     buf = tty_audit_buf_ref();
0162     if (!IS_ERR_OR_NULL(buf)) {
0163         mutex_lock(&buf->mutex);
0164         tty_audit_buf_push(buf);
0165         mutex_unlock(&buf->mutex);
0166     }
0167     return 0;
0168 }
0169 
0170 /*
0171  *  tty_audit_buf_get   -   Get an audit buffer.
0172  *
0173  *  Get an audit buffer, allocate it if necessary.  Return %NULL
0174  *  if out of memory or ERR_PTR(-ESRCH) if tty_audit_exit() has already
0175  *  occurred.  Otherwise, return a new reference to the buffer.
0176  */
0177 static struct tty_audit_buf *tty_audit_buf_get(void)
0178 {
0179     struct tty_audit_buf *buf;
0180 
0181     buf = tty_audit_buf_ref();
0182     if (buf)
0183         return buf;
0184 
0185     buf = tty_audit_buf_alloc();
0186     if (buf == NULL) {
0187         audit_log_lost("out of memory in TTY auditing");
0188         return NULL;
0189     }
0190 
0191     /* Race to use this buffer, free it if another wins */
0192     if (cmpxchg(&current->signal->tty_audit_buf, NULL, buf) != NULL)
0193         tty_audit_buf_free(buf);
0194     return tty_audit_buf_ref();
0195 }
0196 
0197 /*
0198  *  tty_audit_add_data  -   Add data for TTY auditing.
0199  *
0200  *  Audit @data of @size from @tty, if necessary.
0201  */
0202 void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size)
0203 {
0204     struct tty_audit_buf *buf;
0205     unsigned int icanon = !!L_ICANON(tty);
0206     unsigned int audit_tty;
0207     dev_t dev;
0208 
0209     audit_tty = READ_ONCE(current->signal->audit_tty);
0210     if (~audit_tty & AUDIT_TTY_ENABLE)
0211         return;
0212 
0213     if (unlikely(size == 0))
0214         return;
0215 
0216     if (tty->driver->type == TTY_DRIVER_TYPE_PTY
0217         && tty->driver->subtype == PTY_TYPE_MASTER)
0218         return;
0219 
0220     if ((~audit_tty & AUDIT_TTY_LOG_PASSWD) && icanon && !L_ECHO(tty))
0221         return;
0222 
0223     buf = tty_audit_buf_get();
0224     if (IS_ERR_OR_NULL(buf))
0225         return;
0226 
0227     mutex_lock(&buf->mutex);
0228     dev = MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
0229     if (buf->dev != dev || buf->icanon != icanon) {
0230         tty_audit_buf_push(buf);
0231         buf->dev = dev;
0232         buf->icanon = icanon;
0233     }
0234     do {
0235         size_t run;
0236 
0237         run = N_TTY_BUF_SIZE - buf->valid;
0238         if (run > size)
0239             run = size;
0240         memcpy(buf->data + buf->valid, data, run);
0241         buf->valid += run;
0242         data += run;
0243         size -= run;
0244         if (buf->valid == N_TTY_BUF_SIZE)
0245             tty_audit_buf_push(buf);
0246     } while (size != 0);
0247     mutex_unlock(&buf->mutex);
0248 }