162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * security/tomoyo/audit.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005-2011  NTT DATA CORPORATION
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "common.h"
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/**
1262306a36Sopenharmony_ci * tomoyo_print_bprm - Print "struct linux_binprm" for auditing.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * @bprm: Pointer to "struct linux_binprm".
1562306a36Sopenharmony_ci * @dump: Pointer to "struct tomoyo_page_dump".
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Returns the contents of @bprm on success, NULL otherwise.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * This function uses kzalloc(), so caller must kfree() if this function
2062306a36Sopenharmony_ci * didn't return NULL.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cistatic char *tomoyo_print_bprm(struct linux_binprm *bprm,
2362306a36Sopenharmony_ci			       struct tomoyo_page_dump *dump)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	static const int tomoyo_buffer_len = 4096 * 2;
2662306a36Sopenharmony_ci	char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS);
2762306a36Sopenharmony_ci	char *cp;
2862306a36Sopenharmony_ci	char *last_start;
2962306a36Sopenharmony_ci	int len;
3062306a36Sopenharmony_ci	unsigned long pos = bprm->p;
3162306a36Sopenharmony_ci	int offset = pos % PAGE_SIZE;
3262306a36Sopenharmony_ci	int argv_count = bprm->argc;
3362306a36Sopenharmony_ci	int envp_count = bprm->envc;
3462306a36Sopenharmony_ci	bool truncated = false;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (!buffer)
3762306a36Sopenharmony_ci		return NULL;
3862306a36Sopenharmony_ci	len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
3962306a36Sopenharmony_ci	cp = buffer + len;
4062306a36Sopenharmony_ci	if (!argv_count) {
4162306a36Sopenharmony_ci		memmove(cp, "} envp[]={ ", 11);
4262306a36Sopenharmony_ci		cp += 11;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci	last_start = cp;
4562306a36Sopenharmony_ci	while (argv_count || envp_count) {
4662306a36Sopenharmony_ci		if (!tomoyo_dump_page(bprm, pos, dump))
4762306a36Sopenharmony_ci			goto out;
4862306a36Sopenharmony_ci		pos += PAGE_SIZE - offset;
4962306a36Sopenharmony_ci		/* Read. */
5062306a36Sopenharmony_ci		while (offset < PAGE_SIZE) {
5162306a36Sopenharmony_ci			const char *kaddr = dump->data;
5262306a36Sopenharmony_ci			const unsigned char c = kaddr[offset++];
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci			if (cp == last_start)
5562306a36Sopenharmony_ci				*cp++ = '"';
5662306a36Sopenharmony_ci			if (cp >= buffer + tomoyo_buffer_len - 32) {
5762306a36Sopenharmony_ci				/* Reserve some room for "..." string. */
5862306a36Sopenharmony_ci				truncated = true;
5962306a36Sopenharmony_ci			} else if (c == '\\') {
6062306a36Sopenharmony_ci				*cp++ = '\\';
6162306a36Sopenharmony_ci				*cp++ = '\\';
6262306a36Sopenharmony_ci			} else if (c > ' ' && c < 127) {
6362306a36Sopenharmony_ci				*cp++ = c;
6462306a36Sopenharmony_ci			} else if (!c) {
6562306a36Sopenharmony_ci				*cp++ = '"';
6662306a36Sopenharmony_ci				*cp++ = ' ';
6762306a36Sopenharmony_ci				last_start = cp;
6862306a36Sopenharmony_ci			} else {
6962306a36Sopenharmony_ci				*cp++ = '\\';
7062306a36Sopenharmony_ci				*cp++ = (c >> 6) + '0';
7162306a36Sopenharmony_ci				*cp++ = ((c >> 3) & 7) + '0';
7262306a36Sopenharmony_ci				*cp++ = (c & 7) + '0';
7362306a36Sopenharmony_ci			}
7462306a36Sopenharmony_ci			if (c)
7562306a36Sopenharmony_ci				continue;
7662306a36Sopenharmony_ci			if (argv_count) {
7762306a36Sopenharmony_ci				if (--argv_count == 0) {
7862306a36Sopenharmony_ci					if (truncated) {
7962306a36Sopenharmony_ci						cp = last_start;
8062306a36Sopenharmony_ci						memmove(cp, "... ", 4);
8162306a36Sopenharmony_ci						cp += 4;
8262306a36Sopenharmony_ci					}
8362306a36Sopenharmony_ci					memmove(cp, "} envp[]={ ", 11);
8462306a36Sopenharmony_ci					cp += 11;
8562306a36Sopenharmony_ci					last_start = cp;
8662306a36Sopenharmony_ci					truncated = false;
8762306a36Sopenharmony_ci				}
8862306a36Sopenharmony_ci			} else if (envp_count) {
8962306a36Sopenharmony_ci				if (--envp_count == 0) {
9062306a36Sopenharmony_ci					if (truncated) {
9162306a36Sopenharmony_ci						cp = last_start;
9262306a36Sopenharmony_ci						memmove(cp, "... ", 4);
9362306a36Sopenharmony_ci						cp += 4;
9462306a36Sopenharmony_ci					}
9562306a36Sopenharmony_ci				}
9662306a36Sopenharmony_ci			}
9762306a36Sopenharmony_ci			if (!argv_count && !envp_count)
9862306a36Sopenharmony_ci				break;
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci		offset = 0;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci	*cp++ = '}';
10362306a36Sopenharmony_ci	*cp = '\0';
10462306a36Sopenharmony_ci	return buffer;
10562306a36Sopenharmony_ciout:
10662306a36Sopenharmony_ci	snprintf(buffer, tomoyo_buffer_len - 1,
10762306a36Sopenharmony_ci		 "argv[]={ ... } envp[]= { ... }");
10862306a36Sopenharmony_ci	return buffer;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/**
11262306a36Sopenharmony_ci * tomoyo_filetype - Get string representation of file type.
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * @mode: Mode value for stat().
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * Returns file type string.
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cistatic inline const char *tomoyo_filetype(const umode_t mode)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	switch (mode & S_IFMT) {
12162306a36Sopenharmony_ci	case S_IFREG:
12262306a36Sopenharmony_ci	case 0:
12362306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE];
12462306a36Sopenharmony_ci	case S_IFDIR:
12562306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY];
12662306a36Sopenharmony_ci	case S_IFLNK:
12762306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK];
12862306a36Sopenharmony_ci	case S_IFIFO:
12962306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO];
13062306a36Sopenharmony_ci	case S_IFSOCK:
13162306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET];
13262306a36Sopenharmony_ci	case S_IFBLK:
13362306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV];
13462306a36Sopenharmony_ci	case S_IFCHR:
13562306a36Sopenharmony_ci		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV];
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	return "unknown"; /* This should not happen. */
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/**
14162306a36Sopenharmony_ci * tomoyo_print_header - Get header line of audit log.
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info".
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * Returns string representation.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * This function uses kmalloc(), so caller must kfree() if this function
14862306a36Sopenharmony_ci * didn't return NULL.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic char *tomoyo_print_header(struct tomoyo_request_info *r)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct tomoyo_time stamp;
15362306a36Sopenharmony_ci	const pid_t gpid = task_pid_nr(current);
15462306a36Sopenharmony_ci	struct tomoyo_obj_info *obj = r->obj;
15562306a36Sopenharmony_ci	static const int tomoyo_buffer_len = 4096;
15662306a36Sopenharmony_ci	char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
15762306a36Sopenharmony_ci	int pos;
15862306a36Sopenharmony_ci	u8 i;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (!buffer)
16162306a36Sopenharmony_ci		return NULL;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	pos = snprintf(buffer, tomoyo_buffer_len - 1,
16662306a36Sopenharmony_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 }",
16762306a36Sopenharmony_ci		       stamp.year, stamp.month, stamp.day, stamp.hour,
16862306a36Sopenharmony_ci		       stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
16962306a36Sopenharmony_ci		       str_yes_no(r->granted), gpid, tomoyo_sys_getpid(),
17062306a36Sopenharmony_ci		       tomoyo_sys_getppid(),
17162306a36Sopenharmony_ci		       from_kuid(&init_user_ns, current_uid()),
17262306a36Sopenharmony_ci		       from_kgid(&init_user_ns, current_gid()),
17362306a36Sopenharmony_ci		       from_kuid(&init_user_ns, current_euid()),
17462306a36Sopenharmony_ci		       from_kgid(&init_user_ns, current_egid()),
17562306a36Sopenharmony_ci		       from_kuid(&init_user_ns, current_suid()),
17662306a36Sopenharmony_ci		       from_kgid(&init_user_ns, current_sgid()),
17762306a36Sopenharmony_ci		       from_kuid(&init_user_ns, current_fsuid()),
17862306a36Sopenharmony_ci		       from_kgid(&init_user_ns, current_fsgid()));
17962306a36Sopenharmony_ci	if (!obj)
18062306a36Sopenharmony_ci		goto no_obj_info;
18162306a36Sopenharmony_ci	if (!obj->validate_done) {
18262306a36Sopenharmony_ci		tomoyo_get_attributes(obj);
18362306a36Sopenharmony_ci		obj->validate_done = true;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
18662306a36Sopenharmony_ci		struct tomoyo_mini_stat *stat;
18762306a36Sopenharmony_ci		unsigned int dev;
18862306a36Sopenharmony_ci		umode_t mode;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		if (!obj->stat_valid[i])
19162306a36Sopenharmony_ci			continue;
19262306a36Sopenharmony_ci		stat = &obj->stat[i];
19362306a36Sopenharmony_ci		dev = stat->dev;
19462306a36Sopenharmony_ci		mode = stat->mode;
19562306a36Sopenharmony_ci		if (i & 1) {
19662306a36Sopenharmony_ci			pos += snprintf(buffer + pos,
19762306a36Sopenharmony_ci					tomoyo_buffer_len - 1 - pos,
19862306a36Sopenharmony_ci					" path%u.parent={ uid=%u gid=%u ino=%lu perm=0%o }",
19962306a36Sopenharmony_ci					(i >> 1) + 1,
20062306a36Sopenharmony_ci					from_kuid(&init_user_ns, stat->uid),
20162306a36Sopenharmony_ci					from_kgid(&init_user_ns, stat->gid),
20262306a36Sopenharmony_ci					(unsigned long)stat->ino,
20362306a36Sopenharmony_ci					stat->mode & S_IALLUGO);
20462306a36Sopenharmony_ci			continue;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
20762306a36Sopenharmony_ci				" path%u={ uid=%u gid=%u ino=%lu major=%u minor=%u perm=0%o type=%s",
20862306a36Sopenharmony_ci				(i >> 1) + 1,
20962306a36Sopenharmony_ci				from_kuid(&init_user_ns, stat->uid),
21062306a36Sopenharmony_ci				from_kgid(&init_user_ns, stat->gid),
21162306a36Sopenharmony_ci				(unsigned long)stat->ino,
21262306a36Sopenharmony_ci				MAJOR(dev), MINOR(dev),
21362306a36Sopenharmony_ci				mode & S_IALLUGO, tomoyo_filetype(mode));
21462306a36Sopenharmony_ci		if (S_ISCHR(mode) || S_ISBLK(mode)) {
21562306a36Sopenharmony_ci			dev = stat->rdev;
21662306a36Sopenharmony_ci			pos += snprintf(buffer + pos,
21762306a36Sopenharmony_ci					tomoyo_buffer_len - 1 - pos,
21862306a36Sopenharmony_ci					" dev_major=%u dev_minor=%u",
21962306a36Sopenharmony_ci					MAJOR(dev), MINOR(dev));
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
22262306a36Sopenharmony_ci				" }");
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_cino_obj_info:
22562306a36Sopenharmony_ci	if (pos < tomoyo_buffer_len - 1)
22662306a36Sopenharmony_ci		return buffer;
22762306a36Sopenharmony_ci	kfree(buffer);
22862306a36Sopenharmony_ci	return NULL;
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/**
23262306a36Sopenharmony_ci * tomoyo_init_log - Allocate buffer for audit logs.
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci * @r:    Pointer to "struct tomoyo_request_info".
23562306a36Sopenharmony_ci * @len:  Buffer size needed for @fmt and @args.
23662306a36Sopenharmony_ci * @fmt:  The printf()'s format string.
23762306a36Sopenharmony_ci * @args: va_list structure for @fmt.
23862306a36Sopenharmony_ci *
23962306a36Sopenharmony_ci * Returns pointer to allocated memory.
24062306a36Sopenharmony_ci *
24162306a36Sopenharmony_ci * This function uses kzalloc(), so caller must kfree() if this function
24262306a36Sopenharmony_ci * didn't return NULL.
24362306a36Sopenharmony_ci */
24462306a36Sopenharmony_cichar *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
24562306a36Sopenharmony_ci		      va_list args)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	char *buf = NULL;
24862306a36Sopenharmony_ci	char *bprm_info = NULL;
24962306a36Sopenharmony_ci	const char *header = NULL;
25062306a36Sopenharmony_ci	char *realpath = NULL;
25162306a36Sopenharmony_ci	const char *symlink = NULL;
25262306a36Sopenharmony_ci	int pos;
25362306a36Sopenharmony_ci	const char *domainname = r->domain->domainname->name;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	header = tomoyo_print_header(r);
25662306a36Sopenharmony_ci	if (!header)
25762306a36Sopenharmony_ci		return NULL;
25862306a36Sopenharmony_ci	/* +10 is for '\n' etc. and '\0'. */
25962306a36Sopenharmony_ci	len += strlen(domainname) + strlen(header) + 10;
26062306a36Sopenharmony_ci	if (r->ee) {
26162306a36Sopenharmony_ci		struct file *file = r->ee->bprm->file;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		realpath = tomoyo_realpath_from_path(&file->f_path);
26462306a36Sopenharmony_ci		bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
26562306a36Sopenharmony_ci		if (!realpath || !bprm_info)
26662306a36Sopenharmony_ci			goto out;
26762306a36Sopenharmony_ci		/* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
26862306a36Sopenharmony_ci		len += strlen(realpath) + 80 + strlen(bprm_info);
26962306a36Sopenharmony_ci	} else if (r->obj && r->obj->symlink_target) {
27062306a36Sopenharmony_ci		symlink = r->obj->symlink_target->name;
27162306a36Sopenharmony_ci		/* +18 is for " symlink.target=\"%s\"" */
27262306a36Sopenharmony_ci		len += 18 + strlen(symlink);
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	len = kmalloc_size_roundup(len);
27562306a36Sopenharmony_ci	buf = kzalloc(len, GFP_NOFS);
27662306a36Sopenharmony_ci	if (!buf)
27762306a36Sopenharmony_ci		goto out;
27862306a36Sopenharmony_ci	len--;
27962306a36Sopenharmony_ci	pos = snprintf(buf, len, "%s", header);
28062306a36Sopenharmony_ci	if (realpath) {
28162306a36Sopenharmony_ci		struct linux_binprm *bprm = r->ee->bprm;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		pos += snprintf(buf + pos, len - pos,
28462306a36Sopenharmony_ci				" exec={ realpath=\"%s\" argc=%d envc=%d %s }",
28562306a36Sopenharmony_ci				realpath, bprm->argc, bprm->envc, bprm_info);
28662306a36Sopenharmony_ci	} else if (symlink)
28762306a36Sopenharmony_ci		pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
28862306a36Sopenharmony_ci				symlink);
28962306a36Sopenharmony_ci	pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
29062306a36Sopenharmony_ci	vsnprintf(buf + pos, len - pos, fmt, args);
29162306a36Sopenharmony_ciout:
29262306a36Sopenharmony_ci	kfree(realpath);
29362306a36Sopenharmony_ci	kfree(bprm_info);
29462306a36Sopenharmony_ci	kfree(header);
29562306a36Sopenharmony_ci	return buf;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci/* Wait queue for /sys/kernel/security/tomoyo/audit. */
29962306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/* Structure for audit log. */
30262306a36Sopenharmony_cistruct tomoyo_log {
30362306a36Sopenharmony_ci	struct list_head list;
30462306a36Sopenharmony_ci	char *log;
30562306a36Sopenharmony_ci	int size;
30662306a36Sopenharmony_ci};
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/* The list for "struct tomoyo_log". */
30962306a36Sopenharmony_cistatic LIST_HEAD(tomoyo_log);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/* Lock for "struct list_head tomoyo_log". */
31262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(tomoyo_log_lock);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/* Length of "struct list_head tomoyo_log". */
31562306a36Sopenharmony_cistatic unsigned int tomoyo_log_count;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/**
31862306a36Sopenharmony_ci * tomoyo_get_audit - Get audit mode.
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * @ns:          Pointer to "struct tomoyo_policy_namespace".
32162306a36Sopenharmony_ci * @profile:     Profile number.
32262306a36Sopenharmony_ci * @index:       Index number of functionality.
32362306a36Sopenharmony_ci * @matched_acl: Pointer to "struct tomoyo_acl_info".
32462306a36Sopenharmony_ci * @is_granted:  True if granted log, false otherwise.
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * Returns true if this request should be audited, false otherwise.
32762306a36Sopenharmony_ci */
32862306a36Sopenharmony_cistatic bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
32962306a36Sopenharmony_ci			     const u8 profile, const u8 index,
33062306a36Sopenharmony_ci			     const struct tomoyo_acl_info *matched_acl,
33162306a36Sopenharmony_ci			     const bool is_granted)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	u8 mode;
33462306a36Sopenharmony_ci	const u8 category = tomoyo_index2category[index] +
33562306a36Sopenharmony_ci		TOMOYO_MAX_MAC_INDEX;
33662306a36Sopenharmony_ci	struct tomoyo_profile *p;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (!tomoyo_policy_loaded)
33962306a36Sopenharmony_ci		return false;
34062306a36Sopenharmony_ci	p = tomoyo_profile(ns, profile);
34162306a36Sopenharmony_ci	if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
34262306a36Sopenharmony_ci		return false;
34362306a36Sopenharmony_ci	if (is_granted && matched_acl && matched_acl->cond &&
34462306a36Sopenharmony_ci	    matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
34562306a36Sopenharmony_ci		return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
34662306a36Sopenharmony_ci	mode = p->config[index];
34762306a36Sopenharmony_ci	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
34862306a36Sopenharmony_ci		mode = p->config[category];
34962306a36Sopenharmony_ci	if (mode == TOMOYO_CONFIG_USE_DEFAULT)
35062306a36Sopenharmony_ci		mode = p->default_config;
35162306a36Sopenharmony_ci	if (is_granted)
35262306a36Sopenharmony_ci		return mode & TOMOYO_CONFIG_WANT_GRANT_LOG;
35362306a36Sopenharmony_ci	return mode & TOMOYO_CONFIG_WANT_REJECT_LOG;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * tomoyo_write_log2 - Write an audit log.
35862306a36Sopenharmony_ci *
35962306a36Sopenharmony_ci * @r:    Pointer to "struct tomoyo_request_info".
36062306a36Sopenharmony_ci * @len:  Buffer size needed for @fmt and @args.
36162306a36Sopenharmony_ci * @fmt:  The printf()'s format string.
36262306a36Sopenharmony_ci * @args: va_list structure for @fmt.
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * Returns nothing.
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_civoid tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
36762306a36Sopenharmony_ci		       va_list args)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	char *buf;
37062306a36Sopenharmony_ci	struct tomoyo_log *entry;
37162306a36Sopenharmony_ci	bool quota_exceeded = false;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
37462306a36Sopenharmony_ci			      r->matched_acl, r->granted))
37562306a36Sopenharmony_ci		goto out;
37662306a36Sopenharmony_ci	buf = tomoyo_init_log(r, len, fmt, args);
37762306a36Sopenharmony_ci	if (!buf)
37862306a36Sopenharmony_ci		goto out;
37962306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_NOFS);
38062306a36Sopenharmony_ci	if (!entry) {
38162306a36Sopenharmony_ci		kfree(buf);
38262306a36Sopenharmony_ci		goto out;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	entry->log = buf;
38562306a36Sopenharmony_ci	len = kmalloc_size_roundup(strlen(buf) + 1);
38662306a36Sopenharmony_ci	/*
38762306a36Sopenharmony_ci	 * The entry->size is used for memory quota checks.
38862306a36Sopenharmony_ci	 * Don't go beyond strlen(entry->log).
38962306a36Sopenharmony_ci	 */
39062306a36Sopenharmony_ci	entry->size = len + kmalloc_size_roundup(sizeof(*entry));
39162306a36Sopenharmony_ci	spin_lock(&tomoyo_log_lock);
39262306a36Sopenharmony_ci	if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] &&
39362306a36Sopenharmony_ci	    tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >=
39462306a36Sopenharmony_ci	    tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) {
39562306a36Sopenharmony_ci		quota_exceeded = true;
39662306a36Sopenharmony_ci	} else {
39762306a36Sopenharmony_ci		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size;
39862306a36Sopenharmony_ci		list_add_tail(&entry->list, &tomoyo_log);
39962306a36Sopenharmony_ci		tomoyo_log_count++;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci	spin_unlock(&tomoyo_log_lock);
40262306a36Sopenharmony_ci	if (quota_exceeded) {
40362306a36Sopenharmony_ci		kfree(buf);
40462306a36Sopenharmony_ci		kfree(entry);
40562306a36Sopenharmony_ci		goto out;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci	wake_up(&tomoyo_log_wait);
40862306a36Sopenharmony_ciout:
40962306a36Sopenharmony_ci	return;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/**
41362306a36Sopenharmony_ci * tomoyo_write_log - Write an audit log.
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci * @r:   Pointer to "struct tomoyo_request_info".
41662306a36Sopenharmony_ci * @fmt: The printf()'s format string, followed by parameters.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * Returns nothing.
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_civoid tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	va_list args;
42362306a36Sopenharmony_ci	int len;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	va_start(args, fmt);
42662306a36Sopenharmony_ci	len = vsnprintf(NULL, 0, fmt, args) + 1;
42762306a36Sopenharmony_ci	va_end(args);
42862306a36Sopenharmony_ci	va_start(args, fmt);
42962306a36Sopenharmony_ci	tomoyo_write_log2(r, len, fmt, args);
43062306a36Sopenharmony_ci	va_end(args);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/**
43462306a36Sopenharmony_ci * tomoyo_read_log - Read an audit log.
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
43762306a36Sopenharmony_ci *
43862306a36Sopenharmony_ci * Returns nothing.
43962306a36Sopenharmony_ci */
44062306a36Sopenharmony_civoid tomoyo_read_log(struct tomoyo_io_buffer *head)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct tomoyo_log *ptr = NULL;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (head->r.w_pos)
44562306a36Sopenharmony_ci		return;
44662306a36Sopenharmony_ci	kfree(head->read_buf);
44762306a36Sopenharmony_ci	head->read_buf = NULL;
44862306a36Sopenharmony_ci	spin_lock(&tomoyo_log_lock);
44962306a36Sopenharmony_ci	if (!list_empty(&tomoyo_log)) {
45062306a36Sopenharmony_ci		ptr = list_entry(tomoyo_log.next, typeof(*ptr), list);
45162306a36Sopenharmony_ci		list_del(&ptr->list);
45262306a36Sopenharmony_ci		tomoyo_log_count--;
45362306a36Sopenharmony_ci		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci	spin_unlock(&tomoyo_log_lock);
45662306a36Sopenharmony_ci	if (ptr) {
45762306a36Sopenharmony_ci		head->read_buf = ptr->log;
45862306a36Sopenharmony_ci		head->r.w[head->r.w_pos++] = head->read_buf;
45962306a36Sopenharmony_ci		kfree(ptr);
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci/**
46462306a36Sopenharmony_ci * tomoyo_poll_log - Wait for an audit log.
46562306a36Sopenharmony_ci *
46662306a36Sopenharmony_ci * @file: Pointer to "struct file".
46762306a36Sopenharmony_ci * @wait: Pointer to "poll_table". Maybe NULL.
46862306a36Sopenharmony_ci *
46962306a36Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM when ready to read an audit log.
47062306a36Sopenharmony_ci */
47162306a36Sopenharmony_ci__poll_t tomoyo_poll_log(struct file *file, poll_table *wait)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	if (tomoyo_log_count)
47462306a36Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
47562306a36Sopenharmony_ci	poll_wait(file, &tomoyo_log_wait, wait);
47662306a36Sopenharmony_ci	if (tomoyo_log_count)
47762306a36Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
47862306a36Sopenharmony_ci	return 0;
47962306a36Sopenharmony_ci}
480