18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * security/tomoyo/audit.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2011  NTT DATA CORPORATION
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "common.h"
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/**
128c2ecf20Sopenharmony_ci * tomoyo_print_bprm - Print "struct linux_binprm" for auditing.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * @bprm: Pointer to "struct linux_binprm".
158c2ecf20Sopenharmony_ci * @dump: Pointer to "struct tomoyo_page_dump".
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Returns the contents of @bprm on success, NULL otherwise.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * This function uses kzalloc(), so caller must kfree() if this function
208c2ecf20Sopenharmony_ci * didn't return NULL.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cistatic char *tomoyo_print_bprm(struct linux_binprm *bprm,
238c2ecf20Sopenharmony_ci			       struct tomoyo_page_dump *dump)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	static const int tomoyo_buffer_len = 4096 * 2;
268c2ecf20Sopenharmony_ci	char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS);
278c2ecf20Sopenharmony_ci	char *cp;
288c2ecf20Sopenharmony_ci	char *last_start;
298c2ecf20Sopenharmony_ci	int len;
308c2ecf20Sopenharmony_ci	unsigned long pos = bprm->p;
318c2ecf20Sopenharmony_ci	int offset = pos % PAGE_SIZE;
328c2ecf20Sopenharmony_ci	int argv_count = bprm->argc;
338c2ecf20Sopenharmony_ci	int envp_count = bprm->envc;
348c2ecf20Sopenharmony_ci	bool truncated = false;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (!buffer)
378c2ecf20Sopenharmony_ci		return NULL;
388c2ecf20Sopenharmony_ci	len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
398c2ecf20Sopenharmony_ci	cp = buffer + len;
408c2ecf20Sopenharmony_ci	if (!argv_count) {
418c2ecf20Sopenharmony_ci		memmove(cp, "} envp[]={ ", 11);
428c2ecf20Sopenharmony_ci		cp += 11;
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci	last_start = cp;
458c2ecf20Sopenharmony_ci	while (argv_count || envp_count) {
468c2ecf20Sopenharmony_ci		if (!tomoyo_dump_page(bprm, pos, dump))
478c2ecf20Sopenharmony_ci			goto out;
488c2ecf20Sopenharmony_ci		pos += PAGE_SIZE - offset;
498c2ecf20Sopenharmony_ci		/* Read. */
508c2ecf20Sopenharmony_ci		while (offset < PAGE_SIZE) {
518c2ecf20Sopenharmony_ci			const char *kaddr = dump->data;
528c2ecf20Sopenharmony_ci			const unsigned char c = kaddr[offset++];
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci			if (cp == last_start)
558c2ecf20Sopenharmony_ci				*cp++ = '"';
568c2ecf20Sopenharmony_ci			if (cp >= buffer + tomoyo_buffer_len - 32) {
578c2ecf20Sopenharmony_ci				/* Reserve some room for "..." string. */
588c2ecf20Sopenharmony_ci				truncated = true;
598c2ecf20Sopenharmony_ci			} else if (c == '\\') {
608c2ecf20Sopenharmony_ci				*cp++ = '\\';
618c2ecf20Sopenharmony_ci				*cp++ = '\\';
628c2ecf20Sopenharmony_ci			} else if (c > ' ' && c < 127) {
638c2ecf20Sopenharmony_ci				*cp++ = c;
648c2ecf20Sopenharmony_ci			} else if (!c) {
658c2ecf20Sopenharmony_ci				*cp++ = '"';
668c2ecf20Sopenharmony_ci				*cp++ = ' ';
678c2ecf20Sopenharmony_ci				last_start = cp;
688c2ecf20Sopenharmony_ci			} else {
698c2ecf20Sopenharmony_ci				*cp++ = '\\';
708c2ecf20Sopenharmony_ci				*cp++ = (c >> 6) + '0';
718c2ecf20Sopenharmony_ci				*cp++ = ((c >> 3) & 7) + '0';
728c2ecf20Sopenharmony_ci				*cp++ = (c & 7) + '0';
738c2ecf20Sopenharmony_ci			}
748c2ecf20Sopenharmony_ci			if (c)
758c2ecf20Sopenharmony_ci				continue;
768c2ecf20Sopenharmony_ci			if (argv_count) {
778c2ecf20Sopenharmony_ci				if (--argv_count == 0) {
788c2ecf20Sopenharmony_ci					if (truncated) {
798c2ecf20Sopenharmony_ci						cp = last_start;
808c2ecf20Sopenharmony_ci						memmove(cp, "... ", 4);
818c2ecf20Sopenharmony_ci						cp += 4;
828c2ecf20Sopenharmony_ci					}
838c2ecf20Sopenharmony_ci					memmove(cp, "} envp[]={ ", 11);
848c2ecf20Sopenharmony_ci					cp += 11;
858c2ecf20Sopenharmony_ci					last_start = cp;
868c2ecf20Sopenharmony_ci					truncated = false;
878c2ecf20Sopenharmony_ci				}
888c2ecf20Sopenharmony_ci			} else if (envp_count) {
898c2ecf20Sopenharmony_ci				if (--envp_count == 0) {
908c2ecf20Sopenharmony_ci					if (truncated) {
918c2ecf20Sopenharmony_ci						cp = last_start;
928c2ecf20Sopenharmony_ci						memmove(cp, "... ", 4);
938c2ecf20Sopenharmony_ci						cp += 4;
948c2ecf20Sopenharmony_ci					}
958c2ecf20Sopenharmony_ci				}
968c2ecf20Sopenharmony_ci			}
978c2ecf20Sopenharmony_ci			if (!argv_count && !envp_count)
988c2ecf20Sopenharmony_ci				break;
998c2ecf20Sopenharmony_ci		}
1008c2ecf20Sopenharmony_ci		offset = 0;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci	*cp++ = '}';
1038c2ecf20Sopenharmony_ci	*cp = '\0';
1048c2ecf20Sopenharmony_ci	return buffer;
1058c2ecf20Sopenharmony_ciout:
1068c2ecf20Sopenharmony_ci	snprintf(buffer, tomoyo_buffer_len - 1,
1078c2ecf20Sopenharmony_ci		 "argv[]={ ... } envp[]= { ... }");
1088c2ecf20Sopenharmony_ci	return buffer;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/**
1128c2ecf20Sopenharmony_ci * tomoyo_filetype - Get string representation of file type.
1138c2ecf20Sopenharmony_ci *
1148c2ecf20Sopenharmony_ci * @mode: Mode value for stat().
1158c2ecf20Sopenharmony_ci *
1168c2ecf20Sopenharmony_ci * Returns file type string.
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_cistatic inline const char *tomoyo_filetype(const umode_t mode)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	switch (mode & S_IFMT) {
1218c2ecf20Sopenharmony_ci	case S_IFREG:
1228c2ecf20Sopenharmony_ci	case 0:
1238c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE];
1248c2ecf20Sopenharmony_ci	case S_IFDIR:
1258c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY];
1268c2ecf20Sopenharmony_ci	case S_IFLNK:
1278c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK];
1288c2ecf20Sopenharmony_ci	case S_IFIFO:
1298c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO];
1308c2ecf20Sopenharmony_ci	case S_IFSOCK:
1318c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET];
1328c2ecf20Sopenharmony_ci	case S_IFBLK:
1338c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV];
1348c2ecf20Sopenharmony_ci	case S_IFCHR:
1358c2ecf20Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV];
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	return "unknown"; /* This should not happen. */
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/**
1418c2ecf20Sopenharmony_ci * tomoyo_print_header - Get header line of audit log.
1428c2ecf20Sopenharmony_ci *
1438c2ecf20Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info".
1448c2ecf20Sopenharmony_ci *
1458c2ecf20Sopenharmony_ci * Returns string representation.
1468c2ecf20Sopenharmony_ci *
1478c2ecf20Sopenharmony_ci * This function uses kmalloc(), so caller must kfree() if this function
1488c2ecf20Sopenharmony_ci * didn't return NULL.
1498c2ecf20Sopenharmony_ci */
1508c2ecf20Sopenharmony_cistatic char *tomoyo_print_header(struct tomoyo_request_info *r)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct tomoyo_time stamp;
1538c2ecf20Sopenharmony_ci	const pid_t gpid = task_pid_nr(current);
1548c2ecf20Sopenharmony_ci	struct tomoyo_obj_info *obj = r->obj;
1558c2ecf20Sopenharmony_ci	static const int tomoyo_buffer_len = 4096;
1568c2ecf20Sopenharmony_ci	char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
1578c2ecf20Sopenharmony_ci	int pos;
1588c2ecf20Sopenharmony_ci	u8 i;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (!buffer)
1618c2ecf20Sopenharmony_ci		return NULL;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	pos = snprintf(buffer, tomoyo_buffer_len - 1,
1668c2ecf20Sopenharmony_ci		       "#%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 }",
1678c2ecf20Sopenharmony_ci		       stamp.year, stamp.month, stamp.day, stamp.hour,
1688c2ecf20Sopenharmony_ci		       stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
1698c2ecf20Sopenharmony_ci		       tomoyo_yesno(r->granted), gpid, tomoyo_sys_getpid(),
1708c2ecf20Sopenharmony_ci		       tomoyo_sys_getppid(),
1718c2ecf20Sopenharmony_ci		       from_kuid(&init_user_ns, current_uid()),
1728c2ecf20Sopenharmony_ci		       from_kgid(&init_user_ns, current_gid()),
1738c2ecf20Sopenharmony_ci		       from_kuid(&init_user_ns, current_euid()),
1748c2ecf20Sopenharmony_ci		       from_kgid(&init_user_ns, current_egid()),
1758c2ecf20Sopenharmony_ci		       from_kuid(&init_user_ns, current_suid()),
1768c2ecf20Sopenharmony_ci		       from_kgid(&init_user_ns, current_sgid()),
1778c2ecf20Sopenharmony_ci		       from_kuid(&init_user_ns, current_fsuid()),
1788c2ecf20Sopenharmony_ci		       from_kgid(&init_user_ns, current_fsgid()));
1798c2ecf20Sopenharmony_ci	if (!obj)
1808c2ecf20Sopenharmony_ci		goto no_obj_info;
1818c2ecf20Sopenharmony_ci	if (!obj->validate_done) {
1828c2ecf20Sopenharmony_ci		tomoyo_get_attributes(obj);
1838c2ecf20Sopenharmony_ci		obj->validate_done = true;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
1868c2ecf20Sopenharmony_ci		struct tomoyo_mini_stat *stat;
1878c2ecf20Sopenharmony_ci		unsigned int dev;
1888c2ecf20Sopenharmony_ci		umode_t mode;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		if (!obj->stat_valid[i])
1918c2ecf20Sopenharmony_ci			continue;
1928c2ecf20Sopenharmony_ci		stat = &obj->stat[i];
1938c2ecf20Sopenharmony_ci		dev = stat->dev;
1948c2ecf20Sopenharmony_ci		mode = stat->mode;
1958c2ecf20Sopenharmony_ci		if (i & 1) {
1968c2ecf20Sopenharmony_ci			pos += snprintf(buffer + pos,
1978c2ecf20Sopenharmony_ci					tomoyo_buffer_len - 1 - pos,
1988c2ecf20Sopenharmony_ci					" path%u.parent={ uid=%u gid=%u ino=%lu perm=0%o }",
1998c2ecf20Sopenharmony_ci					(i >> 1) + 1,
2008c2ecf20Sopenharmony_ci					from_kuid(&init_user_ns, stat->uid),
2018c2ecf20Sopenharmony_ci					from_kgid(&init_user_ns, stat->gid),
2028c2ecf20Sopenharmony_ci					(unsigned long)stat->ino,
2038c2ecf20Sopenharmony_ci					stat->mode & S_IALLUGO);
2048c2ecf20Sopenharmony_ci			continue;
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
2078c2ecf20Sopenharmony_ci				" path%u={ uid=%u gid=%u ino=%lu major=%u minor=%u perm=0%o type=%s",
2088c2ecf20Sopenharmony_ci				(i >> 1) + 1,
2098c2ecf20Sopenharmony_ci				from_kuid(&init_user_ns, stat->uid),
2108c2ecf20Sopenharmony_ci				from_kgid(&init_user_ns, stat->gid),
2118c2ecf20Sopenharmony_ci				(unsigned long)stat->ino,
2128c2ecf20Sopenharmony_ci				MAJOR(dev), MINOR(dev),
2138c2ecf20Sopenharmony_ci				mode & S_IALLUGO, tomoyo_filetype(mode));
2148c2ecf20Sopenharmony_ci		if (S_ISCHR(mode) || S_ISBLK(mode)) {
2158c2ecf20Sopenharmony_ci			dev = stat->rdev;
2168c2ecf20Sopenharmony_ci			pos += snprintf(buffer + pos,
2178c2ecf20Sopenharmony_ci					tomoyo_buffer_len - 1 - pos,
2188c2ecf20Sopenharmony_ci					" dev_major=%u dev_minor=%u",
2198c2ecf20Sopenharmony_ci					MAJOR(dev), MINOR(dev));
2208c2ecf20Sopenharmony_ci		}
2218c2ecf20Sopenharmony_ci		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
2228c2ecf20Sopenharmony_ci				" }");
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_cino_obj_info:
2258c2ecf20Sopenharmony_ci	if (pos < tomoyo_buffer_len - 1)
2268c2ecf20Sopenharmony_ci		return buffer;
2278c2ecf20Sopenharmony_ci	kfree(buffer);
2288c2ecf20Sopenharmony_ci	return NULL;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/**
2328c2ecf20Sopenharmony_ci * tomoyo_init_log - Allocate buffer for audit logs.
2338c2ecf20Sopenharmony_ci *
2348c2ecf20Sopenharmony_ci * @r:    Pointer to "struct tomoyo_request_info".
2358c2ecf20Sopenharmony_ci * @len:  Buffer size needed for @fmt and @args.
2368c2ecf20Sopenharmony_ci * @fmt:  The printf()'s format string.
2378c2ecf20Sopenharmony_ci * @args: va_list structure for @fmt.
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci * Returns pointer to allocated memory.
2408c2ecf20Sopenharmony_ci *
2418c2ecf20Sopenharmony_ci * This function uses kzalloc(), so caller must kfree() if this function
2428c2ecf20Sopenharmony_ci * didn't return NULL.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_cichar *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
2458c2ecf20Sopenharmony_ci		      va_list args)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	char *buf = NULL;
2488c2ecf20Sopenharmony_ci	char *bprm_info = NULL;
2498c2ecf20Sopenharmony_ci	const char *header = NULL;
2508c2ecf20Sopenharmony_ci	char *realpath = NULL;
2518c2ecf20Sopenharmony_ci	const char *symlink = NULL;
2528c2ecf20Sopenharmony_ci	int pos;
2538c2ecf20Sopenharmony_ci	const char *domainname = r->domain->domainname->name;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	header = tomoyo_print_header(r);
2568c2ecf20Sopenharmony_ci	if (!header)
2578c2ecf20Sopenharmony_ci		return NULL;
2588c2ecf20Sopenharmony_ci	/* +10 is for '\n' etc. and '\0'. */
2598c2ecf20Sopenharmony_ci	len += strlen(domainname) + strlen(header) + 10;
2608c2ecf20Sopenharmony_ci	if (r->ee) {
2618c2ecf20Sopenharmony_ci		struct file *file = r->ee->bprm->file;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		realpath = tomoyo_realpath_from_path(&file->f_path);
2648c2ecf20Sopenharmony_ci		bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
2658c2ecf20Sopenharmony_ci		if (!realpath || !bprm_info)
2668c2ecf20Sopenharmony_ci			goto out;
2678c2ecf20Sopenharmony_ci		/* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
2688c2ecf20Sopenharmony_ci		len += strlen(realpath) + 80 + strlen(bprm_info);
2698c2ecf20Sopenharmony_ci	} else if (r->obj && r->obj->symlink_target) {
2708c2ecf20Sopenharmony_ci		symlink = r->obj->symlink_target->name;
2718c2ecf20Sopenharmony_ci		/* +18 is for " symlink.target=\"%s\"" */
2728c2ecf20Sopenharmony_ci		len += 18 + strlen(symlink);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	len = tomoyo_round2(len);
2758c2ecf20Sopenharmony_ci	buf = kzalloc(len, GFP_NOFS);
2768c2ecf20Sopenharmony_ci	if (!buf)
2778c2ecf20Sopenharmony_ci		goto out;
2788c2ecf20Sopenharmony_ci	len--;
2798c2ecf20Sopenharmony_ci	pos = snprintf(buf, len, "%s", header);
2808c2ecf20Sopenharmony_ci	if (realpath) {
2818c2ecf20Sopenharmony_ci		struct linux_binprm *bprm = r->ee->bprm;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		pos += snprintf(buf + pos, len - pos,
2848c2ecf20Sopenharmony_ci				" exec={ realpath=\"%s\" argc=%d envc=%d %s }",
2858c2ecf20Sopenharmony_ci				realpath, bprm->argc, bprm->envc, bprm_info);
2868c2ecf20Sopenharmony_ci	} else if (symlink)
2878c2ecf20Sopenharmony_ci		pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
2888c2ecf20Sopenharmony_ci				symlink);
2898c2ecf20Sopenharmony_ci	pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
2908c2ecf20Sopenharmony_ci	vsnprintf(buf + pos, len - pos, fmt, args);
2918c2ecf20Sopenharmony_ciout:
2928c2ecf20Sopenharmony_ci	kfree(realpath);
2938c2ecf20Sopenharmony_ci	kfree(bprm_info);
2948c2ecf20Sopenharmony_ci	kfree(header);
2958c2ecf20Sopenharmony_ci	return buf;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/* Wait queue for /sys/kernel/security/tomoyo/audit. */
2998c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/* Structure for audit log. */
3028c2ecf20Sopenharmony_cistruct tomoyo_log {
3038c2ecf20Sopenharmony_ci	struct list_head list;
3048c2ecf20Sopenharmony_ci	char *log;
3058c2ecf20Sopenharmony_ci	int size;
3068c2ecf20Sopenharmony_ci};
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/* The list for "struct tomoyo_log". */
3098c2ecf20Sopenharmony_cistatic LIST_HEAD(tomoyo_log);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/* Lock for "struct list_head tomoyo_log". */
3128c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(tomoyo_log_lock);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/* Length of "stuct list_head tomoyo_log". */
3158c2ecf20Sopenharmony_cistatic unsigned int tomoyo_log_count;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/**
3188c2ecf20Sopenharmony_ci * tomoyo_get_audit - Get audit mode.
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * @ns:          Pointer to "struct tomoyo_policy_namespace".
3218c2ecf20Sopenharmony_ci * @profile:     Profile number.
3228c2ecf20Sopenharmony_ci * @index:       Index number of functionality.
3238c2ecf20Sopenharmony_ci * @is_granted:  True if granted log, false otherwise.
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * Returns true if this request should be audited, false otherwise.
3268c2ecf20Sopenharmony_ci */
3278c2ecf20Sopenharmony_cistatic bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
3288c2ecf20Sopenharmony_ci			     const u8 profile, const u8 index,
3298c2ecf20Sopenharmony_ci			     const struct tomoyo_acl_info *matched_acl,
3308c2ecf20Sopenharmony_ci			     const bool is_granted)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	u8 mode;
3338c2ecf20Sopenharmony_ci	const u8 category = tomoyo_index2category[index] +
3348c2ecf20Sopenharmony_ci		TOMOYO_MAX_MAC_INDEX;
3358c2ecf20Sopenharmony_ci	struct tomoyo_profile *p;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (!tomoyo_policy_loaded)
3388c2ecf20Sopenharmony_ci		return false;
3398c2ecf20Sopenharmony_ci	p = tomoyo_profile(ns, profile);
3408c2ecf20Sopenharmony_ci	if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
3418c2ecf20Sopenharmony_ci		return false;
3428c2ecf20Sopenharmony_ci	if (is_granted && matched_acl && matched_acl->cond &&
3438c2ecf20Sopenharmony_ci	    matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
3448c2ecf20Sopenharmony_ci		return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
3458c2ecf20Sopenharmony_ci	mode = p->config[index];
3468c2ecf20Sopenharmony_ci	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
3478c2ecf20Sopenharmony_ci		mode = p->config[category];
3488c2ecf20Sopenharmony_ci	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
3498c2ecf20Sopenharmony_ci		mode = p->default_config;
3508c2ecf20Sopenharmony_ci	if (is_granted)
3518c2ecf20Sopenharmony_ci		return mode & TOMOYO_CONFIG_WANT_GRANT_LOG;
3528c2ecf20Sopenharmony_ci	return mode & TOMOYO_CONFIG_WANT_REJECT_LOG;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci/**
3568c2ecf20Sopenharmony_ci * tomoyo_write_log2 - Write an audit log.
3578c2ecf20Sopenharmony_ci *
3588c2ecf20Sopenharmony_ci * @r:    Pointer to "struct tomoyo_request_info".
3598c2ecf20Sopenharmony_ci * @len:  Buffer size needed for @fmt and @args.
3608c2ecf20Sopenharmony_ci * @fmt:  The printf()'s format string.
3618c2ecf20Sopenharmony_ci * @args: va_list structure for @fmt.
3628c2ecf20Sopenharmony_ci *
3638c2ecf20Sopenharmony_ci * Returns nothing.
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_civoid tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
3668c2ecf20Sopenharmony_ci		       va_list args)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	char *buf;
3698c2ecf20Sopenharmony_ci	struct tomoyo_log *entry;
3708c2ecf20Sopenharmony_ci	bool quota_exceeded = false;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
3738c2ecf20Sopenharmony_ci			      r->matched_acl, r->granted))
3748c2ecf20Sopenharmony_ci		goto out;
3758c2ecf20Sopenharmony_ci	buf = tomoyo_init_log(r, len, fmt, args);
3768c2ecf20Sopenharmony_ci	if (!buf)
3778c2ecf20Sopenharmony_ci		goto out;
3788c2ecf20Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_NOFS);
3798c2ecf20Sopenharmony_ci	if (!entry) {
3808c2ecf20Sopenharmony_ci		kfree(buf);
3818c2ecf20Sopenharmony_ci		goto out;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci	entry->log = buf;
3848c2ecf20Sopenharmony_ci	len = tomoyo_round2(strlen(buf) + 1);
3858c2ecf20Sopenharmony_ci	/*
3868c2ecf20Sopenharmony_ci	 * The entry->size is used for memory quota checks.
3878c2ecf20Sopenharmony_ci	 * Don't go beyond strlen(entry->log).
3888c2ecf20Sopenharmony_ci	 */
3898c2ecf20Sopenharmony_ci	entry->size = len + tomoyo_round2(sizeof(*entry));
3908c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_log_lock);
3918c2ecf20Sopenharmony_ci	if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] &&
3928c2ecf20Sopenharmony_ci	    tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >=
3938c2ecf20Sopenharmony_ci	    tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) {
3948c2ecf20Sopenharmony_ci		quota_exceeded = true;
3958c2ecf20Sopenharmony_ci	} else {
3968c2ecf20Sopenharmony_ci		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size;
3978c2ecf20Sopenharmony_ci		list_add_tail(&entry->list, &tomoyo_log);
3988c2ecf20Sopenharmony_ci		tomoyo_log_count++;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_log_lock);
4018c2ecf20Sopenharmony_ci	if (quota_exceeded) {
4028c2ecf20Sopenharmony_ci		kfree(buf);
4038c2ecf20Sopenharmony_ci		kfree(entry);
4048c2ecf20Sopenharmony_ci		goto out;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci	wake_up(&tomoyo_log_wait);
4078c2ecf20Sopenharmony_ciout:
4088c2ecf20Sopenharmony_ci	return;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci/**
4128c2ecf20Sopenharmony_ci * tomoyo_write_log - Write an audit log.
4138c2ecf20Sopenharmony_ci *
4148c2ecf20Sopenharmony_ci * @r:   Pointer to "struct tomoyo_request_info".
4158c2ecf20Sopenharmony_ci * @fmt: The printf()'s format string, followed by parameters.
4168c2ecf20Sopenharmony_ci *
4178c2ecf20Sopenharmony_ci * Returns nothing.
4188c2ecf20Sopenharmony_ci */
4198c2ecf20Sopenharmony_civoid tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	va_list args;
4228c2ecf20Sopenharmony_ci	int len;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	va_start(args, fmt);
4258c2ecf20Sopenharmony_ci	len = vsnprintf((char *) &len, 1, fmt, args) + 1;
4268c2ecf20Sopenharmony_ci	va_end(args);
4278c2ecf20Sopenharmony_ci	va_start(args, fmt);
4288c2ecf20Sopenharmony_ci	tomoyo_write_log2(r, len, fmt, args);
4298c2ecf20Sopenharmony_ci	va_end(args);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci/**
4338c2ecf20Sopenharmony_ci * tomoyo_read_log - Read an audit log.
4348c2ecf20Sopenharmony_ci *
4358c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci * Returns nothing.
4388c2ecf20Sopenharmony_ci */
4398c2ecf20Sopenharmony_civoid tomoyo_read_log(struct tomoyo_io_buffer *head)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct tomoyo_log *ptr = NULL;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (head->r.w_pos)
4448c2ecf20Sopenharmony_ci		return;
4458c2ecf20Sopenharmony_ci	kfree(head->read_buf);
4468c2ecf20Sopenharmony_ci	head->read_buf = NULL;
4478c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_log_lock);
4488c2ecf20Sopenharmony_ci	if (!list_empty(&tomoyo_log)) {
4498c2ecf20Sopenharmony_ci		ptr = list_entry(tomoyo_log.next, typeof(*ptr), list);
4508c2ecf20Sopenharmony_ci		list_del(&ptr->list);
4518c2ecf20Sopenharmony_ci		tomoyo_log_count--;
4528c2ecf20Sopenharmony_ci		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_log_lock);
4558c2ecf20Sopenharmony_ci	if (ptr) {
4568c2ecf20Sopenharmony_ci		head->read_buf = ptr->log;
4578c2ecf20Sopenharmony_ci		head->r.w[head->r.w_pos++] = head->read_buf;
4588c2ecf20Sopenharmony_ci		kfree(ptr);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci/**
4638c2ecf20Sopenharmony_ci * tomoyo_poll_log - Wait for an audit log.
4648c2ecf20Sopenharmony_ci *
4658c2ecf20Sopenharmony_ci * @file: Pointer to "struct file".
4668c2ecf20Sopenharmony_ci * @wait: Pointer to "poll_table". Maybe NULL.
4678c2ecf20Sopenharmony_ci *
4688c2ecf20Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM when ready to read an audit log.
4698c2ecf20Sopenharmony_ci */
4708c2ecf20Sopenharmony_ci__poll_t tomoyo_poll_log(struct file *file, poll_table *wait)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	if (tomoyo_log_count)
4738c2ecf20Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
4748c2ecf20Sopenharmony_ci	poll_wait(file, &tomoyo_log_wait, wait);
4758c2ecf20Sopenharmony_ci	if (tomoyo_log_count)
4768c2ecf20Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci}
479