Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * security/tomoyo/audit.c
0004  *
0005  * Copyright (C) 2005-2011  NTT DATA CORPORATION
0006  */
0007 
0008 #include "common.h"
0009 #include <linux/slab.h>
0010 
0011 /**
0012  * tomoyo_print_bprm - Print "struct linux_binprm" for auditing.
0013  *
0014  * @bprm: Pointer to "struct linux_binprm".
0015  * @dump: Pointer to "struct tomoyo_page_dump".
0016  *
0017  * Returns the contents of @bprm on success, NULL otherwise.
0018  *
0019  * This function uses kzalloc(), so caller must kfree() if this function
0020  * didn't return NULL.
0021  */
0022 static char *tomoyo_print_bprm(struct linux_binprm *bprm,
0023                    struct tomoyo_page_dump *dump)
0024 {
0025     static const int tomoyo_buffer_len = 4096 * 2;
0026     char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS);
0027     char *cp;
0028     char *last_start;
0029     int len;
0030     unsigned long pos = bprm->p;
0031     int offset = pos % PAGE_SIZE;
0032     int argv_count = bprm->argc;
0033     int envp_count = bprm->envc;
0034     bool truncated = false;
0035 
0036     if (!buffer)
0037         return NULL;
0038     len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
0039     cp = buffer + len;
0040     if (!argv_count) {
0041         memmove(cp, "} envp[]={ ", 11);
0042         cp += 11;
0043     }
0044     last_start = cp;
0045     while (argv_count || envp_count) {
0046         if (!tomoyo_dump_page(bprm, pos, dump))
0047             goto out;
0048         pos += PAGE_SIZE - offset;
0049         /* Read. */
0050         while (offset < PAGE_SIZE) {
0051             const char *kaddr = dump->data;
0052             const unsigned char c = kaddr[offset++];
0053 
0054             if (cp == last_start)
0055                 *cp++ = '"';
0056             if (cp >= buffer + tomoyo_buffer_len - 32) {
0057                 /* Reserve some room for "..." string. */
0058                 truncated = true;
0059             } else if (c == '\\') {
0060                 *cp++ = '\\';
0061                 *cp++ = '\\';
0062             } else if (c > ' ' && c < 127) {
0063                 *cp++ = c;
0064             } else if (!c) {
0065                 *cp++ = '"';
0066                 *cp++ = ' ';
0067                 last_start = cp;
0068             } else {
0069                 *cp++ = '\\';
0070                 *cp++ = (c >> 6) + '0';
0071                 *cp++ = ((c >> 3) & 7) + '0';
0072                 *cp++ = (c & 7) + '0';
0073             }
0074             if (c)
0075                 continue;
0076             if (argv_count) {
0077                 if (--argv_count == 0) {
0078                     if (truncated) {
0079                         cp = last_start;
0080                         memmove(cp, "... ", 4);
0081                         cp += 4;
0082                     }
0083                     memmove(cp, "} envp[]={ ", 11);
0084                     cp += 11;
0085                     last_start = cp;
0086                     truncated = false;
0087                 }
0088             } else if (envp_count) {
0089                 if (--envp_count == 0) {
0090                     if (truncated) {
0091                         cp = last_start;
0092                         memmove(cp, "... ", 4);
0093                         cp += 4;
0094                     }
0095                 }
0096             }
0097             if (!argv_count && !envp_count)
0098                 break;
0099         }
0100         offset = 0;
0101     }
0102     *cp++ = '}';
0103     *cp = '\0';
0104     return buffer;
0105 out:
0106     snprintf(buffer, tomoyo_buffer_len - 1,
0107          "argv[]={ ... } envp[]= { ... }");
0108     return buffer;
0109 }
0110 
0111 /**
0112  * tomoyo_filetype - Get string representation of file type.
0113  *
0114  * @mode: Mode value for stat().
0115  *
0116  * Returns file type string.
0117  */
0118 static inline const char *tomoyo_filetype(const umode_t mode)
0119 {
0120     switch (mode & S_IFMT) {
0121     case S_IFREG:
0122     case 0:
0123         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE];
0124     case S_IFDIR:
0125         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY];
0126     case S_IFLNK:
0127         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK];
0128     case S_IFIFO:
0129         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO];
0130     case S_IFSOCK:
0131         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET];
0132     case S_IFBLK:
0133         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV];
0134     case S_IFCHR:
0135         return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV];
0136     }
0137     return "unknown"; /* This should not happen. */
0138 }
0139 
0140 /**
0141  * tomoyo_print_header - Get header line of audit log.
0142  *
0143  * @r: Pointer to "struct tomoyo_request_info".
0144  *
0145  * Returns string representation.
0146  *
0147  * This function uses kmalloc(), so caller must kfree() if this function
0148  * didn't return NULL.
0149  */
0150 static char *tomoyo_print_header(struct tomoyo_request_info *r)
0151 {
0152     struct tomoyo_time stamp;
0153     const pid_t gpid = task_pid_nr(current);
0154     struct tomoyo_obj_info *obj = r->obj;
0155     static const int tomoyo_buffer_len = 4096;
0156     char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
0157     int pos;
0158     u8 i;
0159 
0160     if (!buffer)
0161         return NULL;
0162 
0163     tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
0164 
0165     pos = snprintf(buffer, tomoyo_buffer_len - 1,
0166                "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s granted=%s (global-pid=%u) task={ pid=%u ppid=%u uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
0167                stamp.year, stamp.month, stamp.day, stamp.hour,
0168                stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
0169                str_yes_no(r->granted), gpid, tomoyo_sys_getpid(),
0170                tomoyo_sys_getppid(),
0171                from_kuid(&init_user_ns, current_uid()),
0172                from_kgid(&init_user_ns, current_gid()),
0173                from_kuid(&init_user_ns, current_euid()),
0174                from_kgid(&init_user_ns, current_egid()),
0175                from_kuid(&init_user_ns, current_suid()),
0176                from_kgid(&init_user_ns, current_sgid()),
0177                from_kuid(&init_user_ns, current_fsuid()),
0178                from_kgid(&init_user_ns, current_fsgid()));
0179     if (!obj)
0180         goto no_obj_info;
0181     if (!obj->validate_done) {
0182         tomoyo_get_attributes(obj);
0183         obj->validate_done = true;
0184     }
0185     for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
0186         struct tomoyo_mini_stat *stat;
0187         unsigned int dev;
0188         umode_t mode;
0189 
0190         if (!obj->stat_valid[i])
0191             continue;
0192         stat = &obj->stat[i];
0193         dev = stat->dev;
0194         mode = stat->mode;
0195         if (i & 1) {
0196             pos += snprintf(buffer + pos,
0197                     tomoyo_buffer_len - 1 - pos,
0198                     " path%u.parent={ uid=%u gid=%u ino=%lu perm=0%o }",
0199                     (i >> 1) + 1,
0200                     from_kuid(&init_user_ns, stat->uid),
0201                     from_kgid(&init_user_ns, stat->gid),
0202                     (unsigned long)stat->ino,
0203                     stat->mode & S_IALLUGO);
0204             continue;
0205         }
0206         pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
0207                 " path%u={ uid=%u gid=%u ino=%lu major=%u minor=%u perm=0%o type=%s",
0208                 (i >> 1) + 1,
0209                 from_kuid(&init_user_ns, stat->uid),
0210                 from_kgid(&init_user_ns, stat->gid),
0211                 (unsigned long)stat->ino,
0212                 MAJOR(dev), MINOR(dev),
0213                 mode & S_IALLUGO, tomoyo_filetype(mode));
0214         if (S_ISCHR(mode) || S_ISBLK(mode)) {
0215             dev = stat->rdev;
0216             pos += snprintf(buffer + pos,
0217                     tomoyo_buffer_len - 1 - pos,
0218                     " dev_major=%u dev_minor=%u",
0219                     MAJOR(dev), MINOR(dev));
0220         }
0221         pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
0222                 " }");
0223     }
0224 no_obj_info:
0225     if (pos < tomoyo_buffer_len - 1)
0226         return buffer;
0227     kfree(buffer);
0228     return NULL;
0229 }
0230 
0231 /**
0232  * tomoyo_init_log - Allocate buffer for audit logs.
0233  *
0234  * @r:    Pointer to "struct tomoyo_request_info".
0235  * @len:  Buffer size needed for @fmt and @args.
0236  * @fmt:  The printf()'s format string.
0237  * @args: va_list structure for @fmt.
0238  *
0239  * Returns pointer to allocated memory.
0240  *
0241  * This function uses kzalloc(), so caller must kfree() if this function
0242  * didn't return NULL.
0243  */
0244 char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
0245               va_list args)
0246 {
0247     char *buf = NULL;
0248     char *bprm_info = NULL;
0249     const char *header = NULL;
0250     char *realpath = NULL;
0251     const char *symlink = NULL;
0252     int pos;
0253     const char *domainname = r->domain->domainname->name;
0254 
0255     header = tomoyo_print_header(r);
0256     if (!header)
0257         return NULL;
0258     /* +10 is for '\n' etc. and '\0'. */
0259     len += strlen(domainname) + strlen(header) + 10;
0260     if (r->ee) {
0261         struct file *file = r->ee->bprm->file;
0262 
0263         realpath = tomoyo_realpath_from_path(&file->f_path);
0264         bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
0265         if (!realpath || !bprm_info)
0266             goto out;
0267         /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
0268         len += strlen(realpath) + 80 + strlen(bprm_info);
0269     } else if (r->obj && r->obj->symlink_target) {
0270         symlink = r->obj->symlink_target->name;
0271         /* +18 is for " symlink.target=\"%s\"" */
0272         len += 18 + strlen(symlink);
0273     }
0274     len = tomoyo_round2(len);
0275     buf = kzalloc(len, GFP_NOFS);
0276     if (!buf)
0277         goto out;
0278     len--;
0279     pos = snprintf(buf, len, "%s", header);
0280     if (realpath) {
0281         struct linux_binprm *bprm = r->ee->bprm;
0282 
0283         pos += snprintf(buf + pos, len - pos,
0284                 " exec={ realpath=\"%s\" argc=%d envc=%d %s }",
0285                 realpath, bprm->argc, bprm->envc, bprm_info);
0286     } else if (symlink)
0287         pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
0288                 symlink);
0289     pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
0290     vsnprintf(buf + pos, len - pos, fmt, args);
0291 out:
0292     kfree(realpath);
0293     kfree(bprm_info);
0294     kfree(header);
0295     return buf;
0296 }
0297 
0298 /* Wait queue for /sys/kernel/security/tomoyo/audit. */
0299 static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait);
0300 
0301 /* Structure for audit log. */
0302 struct tomoyo_log {
0303     struct list_head list;
0304     char *log;
0305     int size;
0306 };
0307 
0308 /* The list for "struct tomoyo_log". */
0309 static LIST_HEAD(tomoyo_log);
0310 
0311 /* Lock for "struct list_head tomoyo_log". */
0312 static DEFINE_SPINLOCK(tomoyo_log_lock);
0313 
0314 /* Length of "struct list_head tomoyo_log". */
0315 static unsigned int tomoyo_log_count;
0316 
0317 /**
0318  * tomoyo_get_audit - Get audit mode.
0319  *
0320  * @ns:          Pointer to "struct tomoyo_policy_namespace".
0321  * @profile:     Profile number.
0322  * @index:       Index number of functionality.
0323  * @matched_acl: Pointer to "struct tomoyo_acl_info".
0324  * @is_granted:  True if granted log, false otherwise.
0325  *
0326  * Returns true if this request should be audited, false otherwise.
0327  */
0328 static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
0329                  const u8 profile, const u8 index,
0330                  const struct tomoyo_acl_info *matched_acl,
0331                  const bool is_granted)
0332 {
0333     u8 mode;
0334     const u8 category = tomoyo_index2category[index] +
0335         TOMOYO_MAX_MAC_INDEX;
0336     struct tomoyo_profile *p;
0337 
0338     if (!tomoyo_policy_loaded)
0339         return false;
0340     p = tomoyo_profile(ns, profile);
0341     if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
0342         return false;
0343     if (is_granted && matched_acl && matched_acl->cond &&
0344         matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
0345         return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
0346     mode = p->config[index];
0347     if (mode == TOMOYO_CONFIG_USE_DEFAULT)
0348         mode = p->config[category];
0349     if (mode == TOMOYO_CONFIG_USE_DEFAULT)
0350         mode = p->default_config;
0351     if (is_granted)
0352         return mode & TOMOYO_CONFIG_WANT_GRANT_LOG;
0353     return mode & TOMOYO_CONFIG_WANT_REJECT_LOG;
0354 }
0355 
0356 /**
0357  * tomoyo_write_log2 - Write an audit log.
0358  *
0359  * @r:    Pointer to "struct tomoyo_request_info".
0360  * @len:  Buffer size needed for @fmt and @args.
0361  * @fmt:  The printf()'s format string.
0362  * @args: va_list structure for @fmt.
0363  *
0364  * Returns nothing.
0365  */
0366 void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
0367                va_list args)
0368 {
0369     char *buf;
0370     struct tomoyo_log *entry;
0371     bool quota_exceeded = false;
0372 
0373     if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
0374                   r->matched_acl, r->granted))
0375         goto out;
0376     buf = tomoyo_init_log(r, len, fmt, args);
0377     if (!buf)
0378         goto out;
0379     entry = kzalloc(sizeof(*entry), GFP_NOFS);
0380     if (!entry) {
0381         kfree(buf);
0382         goto out;
0383     }
0384     entry->log = buf;
0385     len = tomoyo_round2(strlen(buf) + 1);
0386     /*
0387      * The entry->size is used for memory quota checks.
0388      * Don't go beyond strlen(entry->log).
0389      */
0390     entry->size = len + tomoyo_round2(sizeof(*entry));
0391     spin_lock(&tomoyo_log_lock);
0392     if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] &&
0393         tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >=
0394         tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) {
0395         quota_exceeded = true;
0396     } else {
0397         tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size;
0398         list_add_tail(&entry->list, &tomoyo_log);
0399         tomoyo_log_count++;
0400     }
0401     spin_unlock(&tomoyo_log_lock);
0402     if (quota_exceeded) {
0403         kfree(buf);
0404         kfree(entry);
0405         goto out;
0406     }
0407     wake_up(&tomoyo_log_wait);
0408 out:
0409     return;
0410 }
0411 
0412 /**
0413  * tomoyo_write_log - Write an audit log.
0414  *
0415  * @r:   Pointer to "struct tomoyo_request_info".
0416  * @fmt: The printf()'s format string, followed by parameters.
0417  *
0418  * Returns nothing.
0419  */
0420 void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
0421 {
0422     va_list args;
0423     int len;
0424 
0425     va_start(args, fmt);
0426     len = vsnprintf((char *) &len, 1, fmt, args) + 1;
0427     va_end(args);
0428     va_start(args, fmt);
0429     tomoyo_write_log2(r, len, fmt, args);
0430     va_end(args);
0431 }
0432 
0433 /**
0434  * tomoyo_read_log - Read an audit log.
0435  *
0436  * @head: Pointer to "struct tomoyo_io_buffer".
0437  *
0438  * Returns nothing.
0439  */
0440 void tomoyo_read_log(struct tomoyo_io_buffer *head)
0441 {
0442     struct tomoyo_log *ptr = NULL;
0443 
0444     if (head->r.w_pos)
0445         return;
0446     kfree(head->read_buf);
0447     head->read_buf = NULL;
0448     spin_lock(&tomoyo_log_lock);
0449     if (!list_empty(&tomoyo_log)) {
0450         ptr = list_entry(tomoyo_log.next, typeof(*ptr), list);
0451         list_del(&ptr->list);
0452         tomoyo_log_count--;
0453         tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size;
0454     }
0455     spin_unlock(&tomoyo_log_lock);
0456     if (ptr) {
0457         head->read_buf = ptr->log;
0458         head->r.w[head->r.w_pos++] = head->read_buf;
0459         kfree(ptr);
0460     }
0461 }
0462 
0463 /**
0464  * tomoyo_poll_log - Wait for an audit log.
0465  *
0466  * @file: Pointer to "struct file".
0467  * @wait: Pointer to "poll_table". Maybe NULL.
0468  *
0469  * Returns EPOLLIN | EPOLLRDNORM when ready to read an audit log.
0470  */
0471 __poll_t tomoyo_poll_log(struct file *file, poll_table *wait)
0472 {
0473     if (tomoyo_log_count)
0474         return EPOLLIN | EPOLLRDNORM;
0475     poll_wait(file, &tomoyo_log_wait, wait);
0476     if (tomoyo_log_count)
0477         return EPOLLIN | EPOLLRDNORM;
0478     return 0;
0479 }