162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * security/tomoyo/common.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005-2011  NTT DATA CORPORATION
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/uaccess.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/security.h>
1162306a36Sopenharmony_ci#include <linux/string_helpers.h>
1262306a36Sopenharmony_ci#include "common.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* String table for operation mode. */
1562306a36Sopenharmony_ciconst char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
1662306a36Sopenharmony_ci	[TOMOYO_CONFIG_DISABLED]   = "disabled",
1762306a36Sopenharmony_ci	[TOMOYO_CONFIG_LEARNING]   = "learning",
1862306a36Sopenharmony_ci	[TOMOYO_CONFIG_PERMISSIVE] = "permissive",
1962306a36Sopenharmony_ci	[TOMOYO_CONFIG_ENFORCING]  = "enforcing"
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* String table for /sys/kernel/security/tomoyo/profile */
2362306a36Sopenharmony_ciconst char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
2462306a36Sopenharmony_ci				       + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
2562306a36Sopenharmony_ci	/* CONFIG::file group */
2662306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_EXECUTE]    = "execute",
2762306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_OPEN]       = "open",
2862306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_CREATE]     = "create",
2962306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_UNLINK]     = "unlink",
3062306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_GETATTR]    = "getattr",
3162306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_MKDIR]      = "mkdir",
3262306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_RMDIR]      = "rmdir",
3362306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_MKFIFO]     = "mkfifo",
3462306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_MKSOCK]     = "mksock",
3562306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_TRUNCATE]   = "truncate",
3662306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_SYMLINK]    = "symlink",
3762306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_MKBLOCK]    = "mkblock",
3862306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_MKCHAR]     = "mkchar",
3962306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_LINK]       = "link",
4062306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_RENAME]     = "rename",
4162306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_CHMOD]      = "chmod",
4262306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_CHOWN]      = "chown",
4362306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_CHGRP]      = "chgrp",
4462306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_IOCTL]      = "ioctl",
4562306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_CHROOT]     = "chroot",
4662306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_MOUNT]      = "mount",
4762306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_UMOUNT]     = "unmount",
4862306a36Sopenharmony_ci	[TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
4962306a36Sopenharmony_ci	/* CONFIG::network group */
5062306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
5162306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
5262306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
5362306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
5462306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
5562306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
5662306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
5762306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
5862306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
5962306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
6062306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
6162306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
6262306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
6362306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
6462306a36Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
6562306a36Sopenharmony_ci	/* CONFIG::misc group */
6662306a36Sopenharmony_ci	[TOMOYO_MAC_ENVIRON] = "env",
6762306a36Sopenharmony_ci	/* CONFIG group */
6862306a36Sopenharmony_ci	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
6962306a36Sopenharmony_ci	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network",
7062306a36Sopenharmony_ci	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc",
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* String table for conditions. */
7462306a36Sopenharmony_ciconst char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
7562306a36Sopenharmony_ci	[TOMOYO_TASK_UID]             = "task.uid",
7662306a36Sopenharmony_ci	[TOMOYO_TASK_EUID]            = "task.euid",
7762306a36Sopenharmony_ci	[TOMOYO_TASK_SUID]            = "task.suid",
7862306a36Sopenharmony_ci	[TOMOYO_TASK_FSUID]           = "task.fsuid",
7962306a36Sopenharmony_ci	[TOMOYO_TASK_GID]             = "task.gid",
8062306a36Sopenharmony_ci	[TOMOYO_TASK_EGID]            = "task.egid",
8162306a36Sopenharmony_ci	[TOMOYO_TASK_SGID]            = "task.sgid",
8262306a36Sopenharmony_ci	[TOMOYO_TASK_FSGID]           = "task.fsgid",
8362306a36Sopenharmony_ci	[TOMOYO_TASK_PID]             = "task.pid",
8462306a36Sopenharmony_ci	[TOMOYO_TASK_PPID]            = "task.ppid",
8562306a36Sopenharmony_ci	[TOMOYO_EXEC_ARGC]            = "exec.argc",
8662306a36Sopenharmony_ci	[TOMOYO_EXEC_ENVC]            = "exec.envc",
8762306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_SOCKET]       = "socket",
8862306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_SYMLINK]      = "symlink",
8962306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_FILE]         = "file",
9062306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_BLOCK_DEV]    = "block",
9162306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_DIRECTORY]    = "directory",
9262306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_CHAR_DEV]     = "char",
9362306a36Sopenharmony_ci	[TOMOYO_TYPE_IS_FIFO]         = "fifo",
9462306a36Sopenharmony_ci	[TOMOYO_MODE_SETUID]          = "setuid",
9562306a36Sopenharmony_ci	[TOMOYO_MODE_SETGID]          = "setgid",
9662306a36Sopenharmony_ci	[TOMOYO_MODE_STICKY]          = "sticky",
9762306a36Sopenharmony_ci	[TOMOYO_MODE_OWNER_READ]      = "owner_read",
9862306a36Sopenharmony_ci	[TOMOYO_MODE_OWNER_WRITE]     = "owner_write",
9962306a36Sopenharmony_ci	[TOMOYO_MODE_OWNER_EXECUTE]   = "owner_execute",
10062306a36Sopenharmony_ci	[TOMOYO_MODE_GROUP_READ]      = "group_read",
10162306a36Sopenharmony_ci	[TOMOYO_MODE_GROUP_WRITE]     = "group_write",
10262306a36Sopenharmony_ci	[TOMOYO_MODE_GROUP_EXECUTE]   = "group_execute",
10362306a36Sopenharmony_ci	[TOMOYO_MODE_OTHERS_READ]     = "others_read",
10462306a36Sopenharmony_ci	[TOMOYO_MODE_OTHERS_WRITE]    = "others_write",
10562306a36Sopenharmony_ci	[TOMOYO_MODE_OTHERS_EXECUTE]  = "others_execute",
10662306a36Sopenharmony_ci	[TOMOYO_EXEC_REALPATH]        = "exec.realpath",
10762306a36Sopenharmony_ci	[TOMOYO_SYMLINK_TARGET]       = "symlink.target",
10862306a36Sopenharmony_ci	[TOMOYO_PATH1_UID]            = "path1.uid",
10962306a36Sopenharmony_ci	[TOMOYO_PATH1_GID]            = "path1.gid",
11062306a36Sopenharmony_ci	[TOMOYO_PATH1_INO]            = "path1.ino",
11162306a36Sopenharmony_ci	[TOMOYO_PATH1_MAJOR]          = "path1.major",
11262306a36Sopenharmony_ci	[TOMOYO_PATH1_MINOR]          = "path1.minor",
11362306a36Sopenharmony_ci	[TOMOYO_PATH1_PERM]           = "path1.perm",
11462306a36Sopenharmony_ci	[TOMOYO_PATH1_TYPE]           = "path1.type",
11562306a36Sopenharmony_ci	[TOMOYO_PATH1_DEV_MAJOR]      = "path1.dev_major",
11662306a36Sopenharmony_ci	[TOMOYO_PATH1_DEV_MINOR]      = "path1.dev_minor",
11762306a36Sopenharmony_ci	[TOMOYO_PATH2_UID]            = "path2.uid",
11862306a36Sopenharmony_ci	[TOMOYO_PATH2_GID]            = "path2.gid",
11962306a36Sopenharmony_ci	[TOMOYO_PATH2_INO]            = "path2.ino",
12062306a36Sopenharmony_ci	[TOMOYO_PATH2_MAJOR]          = "path2.major",
12162306a36Sopenharmony_ci	[TOMOYO_PATH2_MINOR]          = "path2.minor",
12262306a36Sopenharmony_ci	[TOMOYO_PATH2_PERM]           = "path2.perm",
12362306a36Sopenharmony_ci	[TOMOYO_PATH2_TYPE]           = "path2.type",
12462306a36Sopenharmony_ci	[TOMOYO_PATH2_DEV_MAJOR]      = "path2.dev_major",
12562306a36Sopenharmony_ci	[TOMOYO_PATH2_DEV_MINOR]      = "path2.dev_minor",
12662306a36Sopenharmony_ci	[TOMOYO_PATH1_PARENT_UID]     = "path1.parent.uid",
12762306a36Sopenharmony_ci	[TOMOYO_PATH1_PARENT_GID]     = "path1.parent.gid",
12862306a36Sopenharmony_ci	[TOMOYO_PATH1_PARENT_INO]     = "path1.parent.ino",
12962306a36Sopenharmony_ci	[TOMOYO_PATH1_PARENT_PERM]    = "path1.parent.perm",
13062306a36Sopenharmony_ci	[TOMOYO_PATH2_PARENT_UID]     = "path2.parent.uid",
13162306a36Sopenharmony_ci	[TOMOYO_PATH2_PARENT_GID]     = "path2.parent.gid",
13262306a36Sopenharmony_ci	[TOMOYO_PATH2_PARENT_INO]     = "path2.parent.ino",
13362306a36Sopenharmony_ci	[TOMOYO_PATH2_PARENT_PERM]    = "path2.parent.perm",
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* String table for PREFERENCE keyword. */
13762306a36Sopenharmony_cistatic const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
13862306a36Sopenharmony_ci	[TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
13962306a36Sopenharmony_ci	[TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* String table for path operation. */
14362306a36Sopenharmony_ciconst char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
14462306a36Sopenharmony_ci	[TOMOYO_TYPE_EXECUTE]    = "execute",
14562306a36Sopenharmony_ci	[TOMOYO_TYPE_READ]       = "read",
14662306a36Sopenharmony_ci	[TOMOYO_TYPE_WRITE]      = "write",
14762306a36Sopenharmony_ci	[TOMOYO_TYPE_APPEND]     = "append",
14862306a36Sopenharmony_ci	[TOMOYO_TYPE_UNLINK]     = "unlink",
14962306a36Sopenharmony_ci	[TOMOYO_TYPE_GETATTR]    = "getattr",
15062306a36Sopenharmony_ci	[TOMOYO_TYPE_RMDIR]      = "rmdir",
15162306a36Sopenharmony_ci	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
15262306a36Sopenharmony_ci	[TOMOYO_TYPE_SYMLINK]    = "symlink",
15362306a36Sopenharmony_ci	[TOMOYO_TYPE_CHROOT]     = "chroot",
15462306a36Sopenharmony_ci	[TOMOYO_TYPE_UMOUNT]     = "unmount",
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/* String table for socket's operation. */
15862306a36Sopenharmony_ciconst char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = {
15962306a36Sopenharmony_ci	[TOMOYO_NETWORK_BIND]    = "bind",
16062306a36Sopenharmony_ci	[TOMOYO_NETWORK_LISTEN]  = "listen",
16162306a36Sopenharmony_ci	[TOMOYO_NETWORK_CONNECT] = "connect",
16262306a36Sopenharmony_ci	[TOMOYO_NETWORK_SEND]    = "send",
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* String table for categories. */
16662306a36Sopenharmony_cistatic const char * const tomoyo_category_keywords
16762306a36Sopenharmony_ci[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
16862306a36Sopenharmony_ci	[TOMOYO_MAC_CATEGORY_FILE]    = "file",
16962306a36Sopenharmony_ci	[TOMOYO_MAC_CATEGORY_NETWORK] = "network",
17062306a36Sopenharmony_ci	[TOMOYO_MAC_CATEGORY_MISC]    = "misc",
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* Permit policy management by non-root user? */
17462306a36Sopenharmony_cistatic bool tomoyo_manage_by_non_root;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* Utility functions. */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * tomoyo_addprintf - strncat()-like-snprintf().
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * @buffer: Buffer to write to. Must be '\0'-terminated.
18262306a36Sopenharmony_ci * @len:    Size of @buffer.
18362306a36Sopenharmony_ci * @fmt:    The printf()'s format string, followed by parameters.
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci * Returns nothing.
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_ci__printf(3, 4)
18862306a36Sopenharmony_cistatic void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	va_list args;
19162306a36Sopenharmony_ci	const int pos = strlen(buffer);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	va_start(args, fmt);
19462306a36Sopenharmony_ci	vsnprintf(buffer + pos, len - pos - 1, fmt, args);
19562306a36Sopenharmony_ci	va_end(args);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/**
19962306a36Sopenharmony_ci * tomoyo_flush - Flush queued string to userspace's buffer.
20062306a36Sopenharmony_ci *
20162306a36Sopenharmony_ci * @head:   Pointer to "struct tomoyo_io_buffer".
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci * Returns true if all data was flushed, false otherwise.
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_cistatic bool tomoyo_flush(struct tomoyo_io_buffer *head)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	while (head->r.w_pos) {
20862306a36Sopenharmony_ci		const char *w = head->r.w[0];
20962306a36Sopenharmony_ci		size_t len = strlen(w);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		if (len) {
21262306a36Sopenharmony_ci			if (len > head->read_user_buf_avail)
21362306a36Sopenharmony_ci				len = head->read_user_buf_avail;
21462306a36Sopenharmony_ci			if (!len)
21562306a36Sopenharmony_ci				return false;
21662306a36Sopenharmony_ci			if (copy_to_user(head->read_user_buf, w, len))
21762306a36Sopenharmony_ci				return false;
21862306a36Sopenharmony_ci			head->read_user_buf_avail -= len;
21962306a36Sopenharmony_ci			head->read_user_buf += len;
22062306a36Sopenharmony_ci			w += len;
22162306a36Sopenharmony_ci		}
22262306a36Sopenharmony_ci		head->r.w[0] = w;
22362306a36Sopenharmony_ci		if (*w)
22462306a36Sopenharmony_ci			return false;
22562306a36Sopenharmony_ci		/* Add '\0' for audit logs and query. */
22662306a36Sopenharmony_ci		if (head->poll) {
22762306a36Sopenharmony_ci			if (!head->read_user_buf_avail ||
22862306a36Sopenharmony_ci			    copy_to_user(head->read_user_buf, "", 1))
22962306a36Sopenharmony_ci				return false;
23062306a36Sopenharmony_ci			head->read_user_buf_avail--;
23162306a36Sopenharmony_ci			head->read_user_buf++;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci		head->r.w_pos--;
23462306a36Sopenharmony_ci		for (len = 0; len < head->r.w_pos; len++)
23562306a36Sopenharmony_ci			head->r.w[len] = head->r.w[len + 1];
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci	head->r.avail = 0;
23862306a36Sopenharmony_ci	return true;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/**
24262306a36Sopenharmony_ci * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * @head:   Pointer to "struct tomoyo_io_buffer".
24562306a36Sopenharmony_ci * @string: String to print.
24662306a36Sopenharmony_ci *
24762306a36Sopenharmony_ci * Note that @string has to be kept valid until @head is kfree()d.
24862306a36Sopenharmony_ci * This means that char[] allocated on stack memory cannot be passed to
24962306a36Sopenharmony_ci * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_cistatic void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
25462306a36Sopenharmony_ci		head->r.w[head->r.w_pos++] = string;
25562306a36Sopenharmony_ci		tomoyo_flush(head);
25662306a36Sopenharmony_ci	} else
25762306a36Sopenharmony_ci		WARN_ON(1);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
26162306a36Sopenharmony_ci			     ...) __printf(2, 3);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/**
26462306a36Sopenharmony_ci * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
26762306a36Sopenharmony_ci * @fmt:  The printf()'s format string, followed by parameters.
26862306a36Sopenharmony_ci */
26962306a36Sopenharmony_cistatic void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
27062306a36Sopenharmony_ci			     ...)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	va_list args;
27362306a36Sopenharmony_ci	size_t len;
27462306a36Sopenharmony_ci	size_t pos = head->r.avail;
27562306a36Sopenharmony_ci	int size = head->readbuf_size - pos;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (size <= 0)
27862306a36Sopenharmony_ci		return;
27962306a36Sopenharmony_ci	va_start(args, fmt);
28062306a36Sopenharmony_ci	len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
28162306a36Sopenharmony_ci	va_end(args);
28262306a36Sopenharmony_ci	if (pos + len >= head->readbuf_size) {
28362306a36Sopenharmony_ci		WARN_ON(1);
28462306a36Sopenharmony_ci		return;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci	head->r.avail += len;
28762306a36Sopenharmony_ci	tomoyo_set_string(head, head->read_buf + pos);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci/**
29162306a36Sopenharmony_ci * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci * Returns nothing.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic void tomoyo_set_space(struct tomoyo_io_buffer *head)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	tomoyo_set_string(head, " ");
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/**
30362306a36Sopenharmony_ci * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure.
30462306a36Sopenharmony_ci *
30562306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci * Returns nothing.
30862306a36Sopenharmony_ci */
30962306a36Sopenharmony_cistatic bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	tomoyo_set_string(head, "\n");
31262306a36Sopenharmony_ci	return !head->r.w_pos;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/**
31662306a36Sopenharmony_ci * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure.
31762306a36Sopenharmony_ci *
31862306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * Returns nothing.
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic void tomoyo_set_slash(struct tomoyo_io_buffer *head)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	tomoyo_set_string(head, "/");
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/* List of namespaces. */
32862306a36Sopenharmony_ciLIST_HEAD(tomoyo_namespace_list);
32962306a36Sopenharmony_ci/* True if namespace other than tomoyo_kernel_namespace is defined. */
33062306a36Sopenharmony_cistatic bool tomoyo_namespace_enabled;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/**
33362306a36Sopenharmony_ci * tomoyo_init_policy_namespace - Initialize namespace.
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * @ns: Pointer to "struct tomoyo_policy_namespace".
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * Returns nothing.
33862306a36Sopenharmony_ci */
33962306a36Sopenharmony_civoid tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	unsigned int idx;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
34462306a36Sopenharmony_ci		INIT_LIST_HEAD(&ns->acl_group[idx]);
34562306a36Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
34662306a36Sopenharmony_ci		INIT_LIST_HEAD(&ns->group_list[idx]);
34762306a36Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
34862306a36Sopenharmony_ci		INIT_LIST_HEAD(&ns->policy_list[idx]);
34962306a36Sopenharmony_ci	ns->profile_version = 20150505;
35062306a36Sopenharmony_ci	tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
35162306a36Sopenharmony_ci	list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/**
35562306a36Sopenharmony_ci * tomoyo_print_namespace - Print namespace header.
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
35862306a36Sopenharmony_ci *
35962306a36Sopenharmony_ci * Returns nothing.
36062306a36Sopenharmony_ci */
36162306a36Sopenharmony_cistatic void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	if (!tomoyo_namespace_enabled)
36462306a36Sopenharmony_ci		return;
36562306a36Sopenharmony_ci	tomoyo_set_string(head,
36662306a36Sopenharmony_ci			  container_of(head->r.ns,
36762306a36Sopenharmony_ci				       struct tomoyo_policy_namespace,
36862306a36Sopenharmony_ci				       namespace_list)->name);
36962306a36Sopenharmony_ci	tomoyo_set_space(head);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/**
37362306a36Sopenharmony_ci * tomoyo_print_name_union - Print a tomoyo_name_union.
37462306a36Sopenharmony_ci *
37562306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
37662306a36Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_name_union".
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_cistatic void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
37962306a36Sopenharmony_ci				    const struct tomoyo_name_union *ptr)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	tomoyo_set_space(head);
38262306a36Sopenharmony_ci	if (ptr->group) {
38362306a36Sopenharmony_ci		tomoyo_set_string(head, "@");
38462306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->group->group_name->name);
38562306a36Sopenharmony_ci	} else {
38662306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->filename->name);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/**
39162306a36Sopenharmony_ci * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote.
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
39462306a36Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_name_union".
39562306a36Sopenharmony_ci *
39662306a36Sopenharmony_ci * Returns nothing.
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_cistatic void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head,
39962306a36Sopenharmony_ci					   const struct tomoyo_name_union *ptr)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	if (ptr->group) {
40262306a36Sopenharmony_ci		tomoyo_set_string(head, "@");
40362306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->group->group_name->name);
40462306a36Sopenharmony_ci	} else {
40562306a36Sopenharmony_ci		tomoyo_set_string(head, "\"");
40662306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->filename->name);
40762306a36Sopenharmony_ci		tomoyo_set_string(head, "\"");
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/**
41262306a36Sopenharmony_ci * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
41562306a36Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_number_union".
41662306a36Sopenharmony_ci *
41762306a36Sopenharmony_ci * Returns nothing.
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_cistatic void tomoyo_print_number_union_nospace
42062306a36Sopenharmony_ci(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	if (ptr->group) {
42362306a36Sopenharmony_ci		tomoyo_set_string(head, "@");
42462306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->group->group_name->name);
42562306a36Sopenharmony_ci	} else {
42662306a36Sopenharmony_ci		int i;
42762306a36Sopenharmony_ci		unsigned long min = ptr->values[0];
42862306a36Sopenharmony_ci		const unsigned long max = ptr->values[1];
42962306a36Sopenharmony_ci		u8 min_type = ptr->value_type[0];
43062306a36Sopenharmony_ci		const u8 max_type = ptr->value_type[1];
43162306a36Sopenharmony_ci		char buffer[128];
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		buffer[0] = '\0';
43462306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
43562306a36Sopenharmony_ci			switch (min_type) {
43662306a36Sopenharmony_ci			case TOMOYO_VALUE_TYPE_HEXADECIMAL:
43762306a36Sopenharmony_ci				tomoyo_addprintf(buffer, sizeof(buffer),
43862306a36Sopenharmony_ci						 "0x%lX", min);
43962306a36Sopenharmony_ci				break;
44062306a36Sopenharmony_ci			case TOMOYO_VALUE_TYPE_OCTAL:
44162306a36Sopenharmony_ci				tomoyo_addprintf(buffer, sizeof(buffer),
44262306a36Sopenharmony_ci						 "0%lo", min);
44362306a36Sopenharmony_ci				break;
44462306a36Sopenharmony_ci			default:
44562306a36Sopenharmony_ci				tomoyo_addprintf(buffer, sizeof(buffer), "%lu",
44662306a36Sopenharmony_ci						 min);
44762306a36Sopenharmony_ci				break;
44862306a36Sopenharmony_ci			}
44962306a36Sopenharmony_ci			if (min == max && min_type == max_type)
45062306a36Sopenharmony_ci				break;
45162306a36Sopenharmony_ci			tomoyo_addprintf(buffer, sizeof(buffer), "-");
45262306a36Sopenharmony_ci			min_type = max_type;
45362306a36Sopenharmony_ci			min = max;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci		tomoyo_io_printf(head, "%s", buffer);
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/**
46062306a36Sopenharmony_ci * tomoyo_print_number_union - Print a tomoyo_number_union.
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
46362306a36Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_number_union".
46462306a36Sopenharmony_ci *
46562306a36Sopenharmony_ci * Returns nothing.
46662306a36Sopenharmony_ci */
46762306a36Sopenharmony_cistatic void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
46862306a36Sopenharmony_ci				      const struct tomoyo_number_union *ptr)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	tomoyo_set_space(head);
47162306a36Sopenharmony_ci	tomoyo_print_number_union_nospace(head, ptr);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci/**
47562306a36Sopenharmony_ci * tomoyo_assign_profile - Create a new profile.
47662306a36Sopenharmony_ci *
47762306a36Sopenharmony_ci * @ns:      Pointer to "struct tomoyo_policy_namespace".
47862306a36Sopenharmony_ci * @profile: Profile number to create.
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
48162306a36Sopenharmony_ci */
48262306a36Sopenharmony_cistatic struct tomoyo_profile *tomoyo_assign_profile
48362306a36Sopenharmony_ci(struct tomoyo_policy_namespace *ns, const unsigned int profile)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct tomoyo_profile *ptr;
48662306a36Sopenharmony_ci	struct tomoyo_profile *entry;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (profile >= TOMOYO_MAX_PROFILES)
48962306a36Sopenharmony_ci		return NULL;
49062306a36Sopenharmony_ci	ptr = ns->profile_ptr[profile];
49162306a36Sopenharmony_ci	if (ptr)
49262306a36Sopenharmony_ci		return ptr;
49362306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_NOFS | __GFP_NOWARN);
49462306a36Sopenharmony_ci	if (mutex_lock_interruptible(&tomoyo_policy_lock))
49562306a36Sopenharmony_ci		goto out;
49662306a36Sopenharmony_ci	ptr = ns->profile_ptr[profile];
49762306a36Sopenharmony_ci	if (!ptr && tomoyo_memory_ok(entry)) {
49862306a36Sopenharmony_ci		ptr = entry;
49962306a36Sopenharmony_ci		ptr->default_config = TOMOYO_CONFIG_DISABLED |
50062306a36Sopenharmony_ci			TOMOYO_CONFIG_WANT_GRANT_LOG |
50162306a36Sopenharmony_ci			TOMOYO_CONFIG_WANT_REJECT_LOG;
50262306a36Sopenharmony_ci		memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
50362306a36Sopenharmony_ci		       sizeof(ptr->config));
50462306a36Sopenharmony_ci		ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] =
50562306a36Sopenharmony_ci			CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG;
50662306a36Sopenharmony_ci		ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] =
50762306a36Sopenharmony_ci			CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY;
50862306a36Sopenharmony_ci		mb(); /* Avoid out-of-order execution. */
50962306a36Sopenharmony_ci		ns->profile_ptr[profile] = ptr;
51062306a36Sopenharmony_ci		entry = NULL;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci	mutex_unlock(&tomoyo_policy_lock);
51362306a36Sopenharmony_ci out:
51462306a36Sopenharmony_ci	kfree(entry);
51562306a36Sopenharmony_ci	return ptr;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/**
51962306a36Sopenharmony_ci * tomoyo_profile - Find a profile.
52062306a36Sopenharmony_ci *
52162306a36Sopenharmony_ci * @ns:      Pointer to "struct tomoyo_policy_namespace".
52262306a36Sopenharmony_ci * @profile: Profile number to find.
52362306a36Sopenharmony_ci *
52462306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_profile".
52562306a36Sopenharmony_ci */
52662306a36Sopenharmony_cistruct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
52762306a36Sopenharmony_ci				      const u8 profile)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	static struct tomoyo_profile tomoyo_null_profile;
53062306a36Sopenharmony_ci	struct tomoyo_profile *ptr = ns->profile_ptr[profile];
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (!ptr)
53362306a36Sopenharmony_ci		ptr = &tomoyo_null_profile;
53462306a36Sopenharmony_ci	return ptr;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci/**
53862306a36Sopenharmony_ci * tomoyo_find_yesno - Find values for specified keyword.
53962306a36Sopenharmony_ci *
54062306a36Sopenharmony_ci * @string: String to check.
54162306a36Sopenharmony_ci * @find:   Name of keyword.
54262306a36Sopenharmony_ci *
54362306a36Sopenharmony_ci * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
54462306a36Sopenharmony_ci */
54562306a36Sopenharmony_cistatic s8 tomoyo_find_yesno(const char *string, const char *find)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	const char *cp = strstr(string, find);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (cp) {
55062306a36Sopenharmony_ci		cp += strlen(find);
55162306a36Sopenharmony_ci		if (!strncmp(cp, "=yes", 4))
55262306a36Sopenharmony_ci			return 1;
55362306a36Sopenharmony_ci		else if (!strncmp(cp, "=no", 3))
55462306a36Sopenharmony_ci			return 0;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci	return -1;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci/**
56062306a36Sopenharmony_ci * tomoyo_set_uint - Set value for specified preference.
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * @i:      Pointer to "unsigned int".
56362306a36Sopenharmony_ci * @string: String to check.
56462306a36Sopenharmony_ci * @find:   Name of keyword.
56562306a36Sopenharmony_ci *
56662306a36Sopenharmony_ci * Returns nothing.
56762306a36Sopenharmony_ci */
56862306a36Sopenharmony_cistatic void tomoyo_set_uint(unsigned int *i, const char *string,
56962306a36Sopenharmony_ci			    const char *find)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	const char *cp = strstr(string, find);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (cp)
57462306a36Sopenharmony_ci		sscanf(cp + strlen(find), "=%u", i);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/**
57862306a36Sopenharmony_ci * tomoyo_set_mode - Set mode for specified profile.
57962306a36Sopenharmony_ci *
58062306a36Sopenharmony_ci * @name:    Name of functionality.
58162306a36Sopenharmony_ci * @value:   Mode for @name.
58262306a36Sopenharmony_ci * @profile: Pointer to "struct tomoyo_profile".
58362306a36Sopenharmony_ci *
58462306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
58562306a36Sopenharmony_ci */
58662306a36Sopenharmony_cistatic int tomoyo_set_mode(char *name, const char *value,
58762306a36Sopenharmony_ci			   struct tomoyo_profile *profile)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	u8 i;
59062306a36Sopenharmony_ci	u8 config;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (!strcmp(name, "CONFIG")) {
59362306a36Sopenharmony_ci		i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
59462306a36Sopenharmony_ci		config = profile->default_config;
59562306a36Sopenharmony_ci	} else if (tomoyo_str_starts(&name, "CONFIG::")) {
59662306a36Sopenharmony_ci		config = 0;
59762306a36Sopenharmony_ci		for (i = 0; i < TOMOYO_MAX_MAC_INDEX
59862306a36Sopenharmony_ci			     + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
59962306a36Sopenharmony_ci			int len = 0;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci			if (i < TOMOYO_MAX_MAC_INDEX) {
60262306a36Sopenharmony_ci				const u8 c = tomoyo_index2category[i];
60362306a36Sopenharmony_ci				const char *category =
60462306a36Sopenharmony_ci					tomoyo_category_keywords[c];
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci				len = strlen(category);
60762306a36Sopenharmony_ci				if (strncmp(name, category, len) ||
60862306a36Sopenharmony_ci				    name[len++] != ':' || name[len++] != ':')
60962306a36Sopenharmony_ci					continue;
61062306a36Sopenharmony_ci			}
61162306a36Sopenharmony_ci			if (strcmp(name + len, tomoyo_mac_keywords[i]))
61262306a36Sopenharmony_ci				continue;
61362306a36Sopenharmony_ci			config = profile->config[i];
61462306a36Sopenharmony_ci			break;
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci		if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
61762306a36Sopenharmony_ci			return -EINVAL;
61862306a36Sopenharmony_ci	} else {
61962306a36Sopenharmony_ci		return -EINVAL;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci	if (strstr(value, "use_default")) {
62262306a36Sopenharmony_ci		config = TOMOYO_CONFIG_USE_DEFAULT;
62362306a36Sopenharmony_ci	} else {
62462306a36Sopenharmony_ci		u8 mode;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		for (mode = 0; mode < 4; mode++)
62762306a36Sopenharmony_ci			if (strstr(value, tomoyo_mode[mode]))
62862306a36Sopenharmony_ci				/*
62962306a36Sopenharmony_ci				 * Update lower 3 bits in order to distinguish
63062306a36Sopenharmony_ci				 * 'config' from 'TOMOYO_CONFIG_USE_DEFAULT'.
63162306a36Sopenharmony_ci				 */
63262306a36Sopenharmony_ci				config = (config & ~7) | mode;
63362306a36Sopenharmony_ci		if (config != TOMOYO_CONFIG_USE_DEFAULT) {
63462306a36Sopenharmony_ci			switch (tomoyo_find_yesno(value, "grant_log")) {
63562306a36Sopenharmony_ci			case 1:
63662306a36Sopenharmony_ci				config |= TOMOYO_CONFIG_WANT_GRANT_LOG;
63762306a36Sopenharmony_ci				break;
63862306a36Sopenharmony_ci			case 0:
63962306a36Sopenharmony_ci				config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG;
64062306a36Sopenharmony_ci				break;
64162306a36Sopenharmony_ci			}
64262306a36Sopenharmony_ci			switch (tomoyo_find_yesno(value, "reject_log")) {
64362306a36Sopenharmony_ci			case 1:
64462306a36Sopenharmony_ci				config |= TOMOYO_CONFIG_WANT_REJECT_LOG;
64562306a36Sopenharmony_ci				break;
64662306a36Sopenharmony_ci			case 0:
64762306a36Sopenharmony_ci				config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG;
64862306a36Sopenharmony_ci				break;
64962306a36Sopenharmony_ci			}
65062306a36Sopenharmony_ci		}
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci	if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
65362306a36Sopenharmony_ci		profile->config[i] = config;
65462306a36Sopenharmony_ci	else if (config != TOMOYO_CONFIG_USE_DEFAULT)
65562306a36Sopenharmony_ci		profile->default_config = config;
65662306a36Sopenharmony_ci	return 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/**
66062306a36Sopenharmony_ci * tomoyo_write_profile - Write profile table.
66162306a36Sopenharmony_ci *
66262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
66362306a36Sopenharmony_ci *
66462306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_cistatic int tomoyo_write_profile(struct tomoyo_io_buffer *head)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	char *data = head->write_buf;
66962306a36Sopenharmony_ci	unsigned int i;
67062306a36Sopenharmony_ci	char *cp;
67162306a36Sopenharmony_ci	struct tomoyo_profile *profile;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
67462306a36Sopenharmony_ci	    == 1)
67562306a36Sopenharmony_ci		return 0;
67662306a36Sopenharmony_ci	i = simple_strtoul(data, &cp, 10);
67762306a36Sopenharmony_ci	if (*cp != '-')
67862306a36Sopenharmony_ci		return -EINVAL;
67962306a36Sopenharmony_ci	data = cp + 1;
68062306a36Sopenharmony_ci	profile = tomoyo_assign_profile(head->w.ns, i);
68162306a36Sopenharmony_ci	if (!profile)
68262306a36Sopenharmony_ci		return -EINVAL;
68362306a36Sopenharmony_ci	cp = strchr(data, '=');
68462306a36Sopenharmony_ci	if (!cp)
68562306a36Sopenharmony_ci		return -EINVAL;
68662306a36Sopenharmony_ci	*cp++ = '\0';
68762306a36Sopenharmony_ci	if (!strcmp(data, "COMMENT")) {
68862306a36Sopenharmony_ci		static DEFINE_SPINLOCK(lock);
68962306a36Sopenharmony_ci		const struct tomoyo_path_info *new_comment
69062306a36Sopenharmony_ci			= tomoyo_get_name(cp);
69162306a36Sopenharmony_ci		const struct tomoyo_path_info *old_comment;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		if (!new_comment)
69462306a36Sopenharmony_ci			return -ENOMEM;
69562306a36Sopenharmony_ci		spin_lock(&lock);
69662306a36Sopenharmony_ci		old_comment = profile->comment;
69762306a36Sopenharmony_ci		profile->comment = new_comment;
69862306a36Sopenharmony_ci		spin_unlock(&lock);
69962306a36Sopenharmony_ci		tomoyo_put_name(old_comment);
70062306a36Sopenharmony_ci		return 0;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci	if (!strcmp(data, "PREFERENCE")) {
70362306a36Sopenharmony_ci		for (i = 0; i < TOMOYO_MAX_PREF; i++)
70462306a36Sopenharmony_ci			tomoyo_set_uint(&profile->pref[i], cp,
70562306a36Sopenharmony_ci					tomoyo_pref_keywords[i]);
70662306a36Sopenharmony_ci		return 0;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci	return tomoyo_set_mode(data, cp, profile);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci/**
71262306a36Sopenharmony_ci * tomoyo_print_config - Print mode for specified functionality.
71362306a36Sopenharmony_ci *
71462306a36Sopenharmony_ci * @head:   Pointer to "struct tomoyo_io_buffer".
71562306a36Sopenharmony_ci * @config: Mode for that functionality.
71662306a36Sopenharmony_ci *
71762306a36Sopenharmony_ci * Returns nothing.
71862306a36Sopenharmony_ci *
71962306a36Sopenharmony_ci * Caller prints functionality's name.
72062306a36Sopenharmony_ci */
72162306a36Sopenharmony_cistatic void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
72462306a36Sopenharmony_ci			 tomoyo_mode[config & 3],
72562306a36Sopenharmony_ci			 str_yes_no(config & TOMOYO_CONFIG_WANT_GRANT_LOG),
72662306a36Sopenharmony_ci			 str_yes_no(config & TOMOYO_CONFIG_WANT_REJECT_LOG));
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci/**
73062306a36Sopenharmony_ci * tomoyo_read_profile - Read profile table.
73162306a36Sopenharmony_ci *
73262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
73362306a36Sopenharmony_ci *
73462306a36Sopenharmony_ci * Returns nothing.
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_cistatic void tomoyo_read_profile(struct tomoyo_io_buffer *head)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	u8 index;
73962306a36Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
74062306a36Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
74162306a36Sopenharmony_ci	const struct tomoyo_profile *profile;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (head->r.eof)
74462306a36Sopenharmony_ci		return;
74562306a36Sopenharmony_ci next:
74662306a36Sopenharmony_ci	index = head->r.index;
74762306a36Sopenharmony_ci	profile = ns->profile_ptr[index];
74862306a36Sopenharmony_ci	switch (head->r.step) {
74962306a36Sopenharmony_ci	case 0:
75062306a36Sopenharmony_ci		tomoyo_print_namespace(head);
75162306a36Sopenharmony_ci		tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
75262306a36Sopenharmony_ci				 ns->profile_version);
75362306a36Sopenharmony_ci		head->r.step++;
75462306a36Sopenharmony_ci		break;
75562306a36Sopenharmony_ci	case 1:
75662306a36Sopenharmony_ci		for ( ; head->r.index < TOMOYO_MAX_PROFILES;
75762306a36Sopenharmony_ci		      head->r.index++)
75862306a36Sopenharmony_ci			if (ns->profile_ptr[head->r.index])
75962306a36Sopenharmony_ci				break;
76062306a36Sopenharmony_ci		if (head->r.index == TOMOYO_MAX_PROFILES) {
76162306a36Sopenharmony_ci			head->r.eof = true;
76262306a36Sopenharmony_ci			return;
76362306a36Sopenharmony_ci		}
76462306a36Sopenharmony_ci		head->r.step++;
76562306a36Sopenharmony_ci		break;
76662306a36Sopenharmony_ci	case 2:
76762306a36Sopenharmony_ci		{
76862306a36Sopenharmony_ci			u8 i;
76962306a36Sopenharmony_ci			const struct tomoyo_path_info *comment =
77062306a36Sopenharmony_ci				profile->comment;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci			tomoyo_print_namespace(head);
77362306a36Sopenharmony_ci			tomoyo_io_printf(head, "%u-COMMENT=", index);
77462306a36Sopenharmony_ci			tomoyo_set_string(head, comment ? comment->name : "");
77562306a36Sopenharmony_ci			tomoyo_set_lf(head);
77662306a36Sopenharmony_ci			tomoyo_print_namespace(head);
77762306a36Sopenharmony_ci			tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
77862306a36Sopenharmony_ci			for (i = 0; i < TOMOYO_MAX_PREF; i++)
77962306a36Sopenharmony_ci				tomoyo_io_printf(head, "%s=%u ",
78062306a36Sopenharmony_ci						 tomoyo_pref_keywords[i],
78162306a36Sopenharmony_ci						 profile->pref[i]);
78262306a36Sopenharmony_ci			tomoyo_set_string(head, "}\n");
78362306a36Sopenharmony_ci			head->r.step++;
78462306a36Sopenharmony_ci		}
78562306a36Sopenharmony_ci		break;
78662306a36Sopenharmony_ci	case 3:
78762306a36Sopenharmony_ci		{
78862306a36Sopenharmony_ci			tomoyo_print_namespace(head);
78962306a36Sopenharmony_ci			tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
79062306a36Sopenharmony_ci			tomoyo_print_config(head, profile->default_config);
79162306a36Sopenharmony_ci			head->r.bit = 0;
79262306a36Sopenharmony_ci			head->r.step++;
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci		break;
79562306a36Sopenharmony_ci	case 4:
79662306a36Sopenharmony_ci		for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
79762306a36Sopenharmony_ci			      + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
79862306a36Sopenharmony_ci			const u8 i = head->r.bit;
79962306a36Sopenharmony_ci			const u8 config = profile->config[i];
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci			if (config == TOMOYO_CONFIG_USE_DEFAULT)
80262306a36Sopenharmony_ci				continue;
80362306a36Sopenharmony_ci			tomoyo_print_namespace(head);
80462306a36Sopenharmony_ci			if (i < TOMOYO_MAX_MAC_INDEX)
80562306a36Sopenharmony_ci				tomoyo_io_printf(head, "%u-CONFIG::%s::%s",
80662306a36Sopenharmony_ci						 index,
80762306a36Sopenharmony_ci						 tomoyo_category_keywords
80862306a36Sopenharmony_ci						 [tomoyo_index2category[i]],
80962306a36Sopenharmony_ci						 tomoyo_mac_keywords[i]);
81062306a36Sopenharmony_ci			else
81162306a36Sopenharmony_ci				tomoyo_io_printf(head, "%u-CONFIG::%s", index,
81262306a36Sopenharmony_ci						 tomoyo_mac_keywords[i]);
81362306a36Sopenharmony_ci			tomoyo_print_config(head, config);
81462306a36Sopenharmony_ci			head->r.bit++;
81562306a36Sopenharmony_ci			break;
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci		if (head->r.bit == TOMOYO_MAX_MAC_INDEX
81862306a36Sopenharmony_ci		    + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
81962306a36Sopenharmony_ci			head->r.index++;
82062306a36Sopenharmony_ci			head->r.step = 1;
82162306a36Sopenharmony_ci		}
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci	if (tomoyo_flush(head))
82562306a36Sopenharmony_ci		goto next;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci/**
82962306a36Sopenharmony_ci * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry.
83062306a36Sopenharmony_ci *
83162306a36Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_head".
83262306a36Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_head".
83362306a36Sopenharmony_ci *
83462306a36Sopenharmony_ci * Returns true if @a == @b, false otherwise.
83562306a36Sopenharmony_ci */
83662306a36Sopenharmony_cistatic bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
83762306a36Sopenharmony_ci				const struct tomoyo_acl_head *b)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	return container_of(a, struct tomoyo_manager, head)->manager ==
84062306a36Sopenharmony_ci		container_of(b, struct tomoyo_manager, head)->manager;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/**
84462306a36Sopenharmony_ci * tomoyo_update_manager_entry - Add a manager entry.
84562306a36Sopenharmony_ci *
84662306a36Sopenharmony_ci * @manager:   The path to manager or the domainnamme.
84762306a36Sopenharmony_ci * @is_delete: True if it is a delete request.
84862306a36Sopenharmony_ci *
84962306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
85062306a36Sopenharmony_ci *
85162306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
85262306a36Sopenharmony_ci */
85362306a36Sopenharmony_cistatic int tomoyo_update_manager_entry(const char *manager,
85462306a36Sopenharmony_ci				       const bool is_delete)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	struct tomoyo_manager e = { };
85762306a36Sopenharmony_ci	struct tomoyo_acl_param param = {
85862306a36Sopenharmony_ci		/* .ns = &tomoyo_kernel_namespace, */
85962306a36Sopenharmony_ci		.is_delete = is_delete,
86062306a36Sopenharmony_ci		.list = &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER],
86162306a36Sopenharmony_ci	};
86262306a36Sopenharmony_ci	int error = is_delete ? -ENOENT : -ENOMEM;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (!tomoyo_correct_domain(manager) &&
86562306a36Sopenharmony_ci	    !tomoyo_correct_word(manager))
86662306a36Sopenharmony_ci		return -EINVAL;
86762306a36Sopenharmony_ci	e.manager = tomoyo_get_name(manager);
86862306a36Sopenharmony_ci	if (e.manager) {
86962306a36Sopenharmony_ci		error = tomoyo_update_policy(&e.head, sizeof(e), &param,
87062306a36Sopenharmony_ci					     tomoyo_same_manager);
87162306a36Sopenharmony_ci		tomoyo_put_name(e.manager);
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci	return error;
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci/**
87762306a36Sopenharmony_ci * tomoyo_write_manager - Write manager policy.
87862306a36Sopenharmony_ci *
87962306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
88062306a36Sopenharmony_ci *
88162306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
88262306a36Sopenharmony_ci *
88362306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
88462306a36Sopenharmony_ci */
88562306a36Sopenharmony_cistatic int tomoyo_write_manager(struct tomoyo_io_buffer *head)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	char *data = head->write_buf;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (!strcmp(data, "manage_by_non_root")) {
89062306a36Sopenharmony_ci		tomoyo_manage_by_non_root = !head->w.is_delete;
89162306a36Sopenharmony_ci		return 0;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci	return tomoyo_update_manager_entry(data, head->w.is_delete);
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci/**
89762306a36Sopenharmony_ci * tomoyo_read_manager - Read manager policy.
89862306a36Sopenharmony_ci *
89962306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
90062306a36Sopenharmony_ci *
90162306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
90262306a36Sopenharmony_ci */
90362306a36Sopenharmony_cistatic void tomoyo_read_manager(struct tomoyo_io_buffer *head)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	if (head->r.eof)
90662306a36Sopenharmony_ci		return;
90762306a36Sopenharmony_ci	list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER]) {
90862306a36Sopenharmony_ci		struct tomoyo_manager *ptr =
90962306a36Sopenharmony_ci			list_entry(head->r.acl, typeof(*ptr), head.list);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		if (ptr->head.is_deleted)
91262306a36Sopenharmony_ci			continue;
91362306a36Sopenharmony_ci		if (!tomoyo_flush(head))
91462306a36Sopenharmony_ci			return;
91562306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->manager->name);
91662306a36Sopenharmony_ci		tomoyo_set_lf(head);
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci	head->r.eof = true;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci/**
92262306a36Sopenharmony_ci * tomoyo_manager - Check whether the current process is a policy manager.
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci * Returns true if the current process is permitted to modify policy
92562306a36Sopenharmony_ci * via /sys/kernel/security/tomoyo/ interface.
92662306a36Sopenharmony_ci *
92762306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
92862306a36Sopenharmony_ci */
92962306a36Sopenharmony_cistatic bool tomoyo_manager(void)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	struct tomoyo_manager *ptr;
93262306a36Sopenharmony_ci	const char *exe;
93362306a36Sopenharmony_ci	const struct task_struct *task = current;
93462306a36Sopenharmony_ci	const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
93562306a36Sopenharmony_ci	bool found = IS_ENABLED(CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (!tomoyo_policy_loaded)
93862306a36Sopenharmony_ci		return true;
93962306a36Sopenharmony_ci	if (!tomoyo_manage_by_non_root &&
94062306a36Sopenharmony_ci	    (!uid_eq(task->cred->uid,  GLOBAL_ROOT_UID) ||
94162306a36Sopenharmony_ci	     !uid_eq(task->cred->euid, GLOBAL_ROOT_UID)))
94262306a36Sopenharmony_ci		return false;
94362306a36Sopenharmony_ci	exe = tomoyo_get_exe();
94462306a36Sopenharmony_ci	if (!exe)
94562306a36Sopenharmony_ci		return false;
94662306a36Sopenharmony_ci	list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], head.list,
94762306a36Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
94862306a36Sopenharmony_ci		if (!ptr->head.is_deleted &&
94962306a36Sopenharmony_ci		    (!tomoyo_pathcmp(domainname, ptr->manager) ||
95062306a36Sopenharmony_ci		     !strcmp(exe, ptr->manager->name))) {
95162306a36Sopenharmony_ci			found = true;
95262306a36Sopenharmony_ci			break;
95362306a36Sopenharmony_ci		}
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci	if (!found) { /* Reduce error messages. */
95662306a36Sopenharmony_ci		static pid_t last_pid;
95762306a36Sopenharmony_ci		const pid_t pid = current->pid;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci		if (last_pid != pid) {
96062306a36Sopenharmony_ci			pr_warn("%s ( %s ) is not permitted to update policies.\n",
96162306a36Sopenharmony_ci				domainname->name, exe);
96262306a36Sopenharmony_ci			last_pid = pid;
96362306a36Sopenharmony_ci		}
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci	kfree(exe);
96662306a36Sopenharmony_ci	return found;
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_cistatic struct tomoyo_domain_info *tomoyo_find_domain_by_qid
97062306a36Sopenharmony_ci(unsigned int serial);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci/**
97362306a36Sopenharmony_ci * tomoyo_select_domain - Parse select command.
97462306a36Sopenharmony_ci *
97562306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
97662306a36Sopenharmony_ci * @data: String to parse.
97762306a36Sopenharmony_ci *
97862306a36Sopenharmony_ci * Returns true on success, false otherwise.
97962306a36Sopenharmony_ci *
98062306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
98162306a36Sopenharmony_ci */
98262306a36Sopenharmony_cistatic bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
98362306a36Sopenharmony_ci				 const char *data)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	unsigned int pid;
98662306a36Sopenharmony_ci	struct tomoyo_domain_info *domain = NULL;
98762306a36Sopenharmony_ci	bool global_pid = false;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (strncmp(data, "select ", 7))
99062306a36Sopenharmony_ci		return false;
99162306a36Sopenharmony_ci	data += 7;
99262306a36Sopenharmony_ci	if (sscanf(data, "pid=%u", &pid) == 1 ||
99362306a36Sopenharmony_ci	    (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
99462306a36Sopenharmony_ci		struct task_struct *p;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci		rcu_read_lock();
99762306a36Sopenharmony_ci		if (global_pid)
99862306a36Sopenharmony_ci			p = find_task_by_pid_ns(pid, &init_pid_ns);
99962306a36Sopenharmony_ci		else
100062306a36Sopenharmony_ci			p = find_task_by_vpid(pid);
100162306a36Sopenharmony_ci		if (p)
100262306a36Sopenharmony_ci			domain = tomoyo_task(p)->domain_info;
100362306a36Sopenharmony_ci		rcu_read_unlock();
100462306a36Sopenharmony_ci	} else if (!strncmp(data, "domain=", 7)) {
100562306a36Sopenharmony_ci		if (tomoyo_domain_def(data + 7))
100662306a36Sopenharmony_ci			domain = tomoyo_find_domain(data + 7);
100762306a36Sopenharmony_ci	} else if (sscanf(data, "Q=%u", &pid) == 1) {
100862306a36Sopenharmony_ci		domain = tomoyo_find_domain_by_qid(pid);
100962306a36Sopenharmony_ci	} else
101062306a36Sopenharmony_ci		return false;
101162306a36Sopenharmony_ci	head->w.domain = domain;
101262306a36Sopenharmony_ci	/* Accessing read_buf is safe because head->io_sem is held. */
101362306a36Sopenharmony_ci	if (!head->read_buf)
101462306a36Sopenharmony_ci		return true; /* Do nothing if open(O_WRONLY). */
101562306a36Sopenharmony_ci	memset(&head->r, 0, sizeof(head->r));
101662306a36Sopenharmony_ci	head->r.print_this_domain_only = true;
101762306a36Sopenharmony_ci	if (domain)
101862306a36Sopenharmony_ci		head->r.domain = &domain->list;
101962306a36Sopenharmony_ci	else
102062306a36Sopenharmony_ci		head->r.eof = true;
102162306a36Sopenharmony_ci	tomoyo_io_printf(head, "# select %s\n", data);
102262306a36Sopenharmony_ci	if (domain && domain->is_deleted)
102362306a36Sopenharmony_ci		tomoyo_io_printf(head, "# This is a deleted domain.\n");
102462306a36Sopenharmony_ci	return true;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci/**
102862306a36Sopenharmony_ci * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry.
102962306a36Sopenharmony_ci *
103062306a36Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_info".
103162306a36Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_info".
103262306a36Sopenharmony_ci *
103362306a36Sopenharmony_ci * Returns true if @a == @b, false otherwise.
103462306a36Sopenharmony_ci */
103562306a36Sopenharmony_cistatic bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
103662306a36Sopenharmony_ci				 const struct tomoyo_acl_info *b)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
103962306a36Sopenharmony_ci	const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	return p1->domainname == p2->domainname;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci/**
104562306a36Sopenharmony_ci * tomoyo_write_task - Update task related list.
104662306a36Sopenharmony_ci *
104762306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
104862306a36Sopenharmony_ci *
104962306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
105062306a36Sopenharmony_ci *
105162306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
105262306a36Sopenharmony_ci */
105362306a36Sopenharmony_cistatic int tomoyo_write_task(struct tomoyo_acl_param *param)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	int error = -EINVAL;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
105862306a36Sopenharmony_ci		struct tomoyo_task_acl e = {
105962306a36Sopenharmony_ci			.head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
106062306a36Sopenharmony_ci			.domainname = tomoyo_get_domainname(param),
106162306a36Sopenharmony_ci		};
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		if (e.domainname)
106462306a36Sopenharmony_ci			error = tomoyo_update_domain(&e.head, sizeof(e), param,
106562306a36Sopenharmony_ci						     tomoyo_same_task_acl,
106662306a36Sopenharmony_ci						     NULL);
106762306a36Sopenharmony_ci		tomoyo_put_name(e.domainname);
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci	return error;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci/**
107362306a36Sopenharmony_ci * tomoyo_delete_domain - Delete a domain.
107462306a36Sopenharmony_ci *
107562306a36Sopenharmony_ci * @domainname: The name of domain.
107662306a36Sopenharmony_ci *
107762306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
107862306a36Sopenharmony_ci *
107962306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
108062306a36Sopenharmony_ci */
108162306a36Sopenharmony_cistatic int tomoyo_delete_domain(char *domainname)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	struct tomoyo_domain_info *domain;
108462306a36Sopenharmony_ci	struct tomoyo_path_info name;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	name.name = domainname;
108762306a36Sopenharmony_ci	tomoyo_fill_path_info(&name);
108862306a36Sopenharmony_ci	if (mutex_lock_interruptible(&tomoyo_policy_lock))
108962306a36Sopenharmony_ci		return -EINTR;
109062306a36Sopenharmony_ci	/* Is there an active domain? */
109162306a36Sopenharmony_ci	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
109262306a36Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
109362306a36Sopenharmony_ci		/* Never delete tomoyo_kernel_domain */
109462306a36Sopenharmony_ci		if (domain == &tomoyo_kernel_domain)
109562306a36Sopenharmony_ci			continue;
109662306a36Sopenharmony_ci		if (domain->is_deleted ||
109762306a36Sopenharmony_ci		    tomoyo_pathcmp(domain->domainname, &name))
109862306a36Sopenharmony_ci			continue;
109962306a36Sopenharmony_ci		domain->is_deleted = true;
110062306a36Sopenharmony_ci		break;
110162306a36Sopenharmony_ci	}
110262306a36Sopenharmony_ci	mutex_unlock(&tomoyo_policy_lock);
110362306a36Sopenharmony_ci	return 0;
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci/**
110762306a36Sopenharmony_ci * tomoyo_write_domain2 - Write domain policy.
110862306a36Sopenharmony_ci *
110962306a36Sopenharmony_ci * @ns:        Pointer to "struct tomoyo_policy_namespace".
111062306a36Sopenharmony_ci * @list:      Pointer to "struct list_head".
111162306a36Sopenharmony_ci * @data:      Policy to be interpreted.
111262306a36Sopenharmony_ci * @is_delete: True if it is a delete request.
111362306a36Sopenharmony_ci *
111462306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
111562306a36Sopenharmony_ci *
111662306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
111762306a36Sopenharmony_ci */
111862306a36Sopenharmony_cistatic int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
111962306a36Sopenharmony_ci				struct list_head *list, char *data,
112062306a36Sopenharmony_ci				const bool is_delete)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	struct tomoyo_acl_param param = {
112362306a36Sopenharmony_ci		.ns = ns,
112462306a36Sopenharmony_ci		.list = list,
112562306a36Sopenharmony_ci		.data = data,
112662306a36Sopenharmony_ci		.is_delete = is_delete,
112762306a36Sopenharmony_ci	};
112862306a36Sopenharmony_ci	static const struct {
112962306a36Sopenharmony_ci		const char *keyword;
113062306a36Sopenharmony_ci		int (*write)(struct tomoyo_acl_param *param);
113162306a36Sopenharmony_ci	} tomoyo_callback[5] = {
113262306a36Sopenharmony_ci		{ "file ", tomoyo_write_file },
113362306a36Sopenharmony_ci		{ "network inet ", tomoyo_write_inet_network },
113462306a36Sopenharmony_ci		{ "network unix ", tomoyo_write_unix_network },
113562306a36Sopenharmony_ci		{ "misc ", tomoyo_write_misc },
113662306a36Sopenharmony_ci		{ "task ", tomoyo_write_task },
113762306a36Sopenharmony_ci	};
113862306a36Sopenharmony_ci	u8 i;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) {
114162306a36Sopenharmony_ci		if (!tomoyo_str_starts(&param.data,
114262306a36Sopenharmony_ci				       tomoyo_callback[i].keyword))
114362306a36Sopenharmony_ci			continue;
114462306a36Sopenharmony_ci		return tomoyo_callback[i].write(&param);
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci	return -EINVAL;
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/* String table for domain flags. */
115062306a36Sopenharmony_ciconst char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = {
115162306a36Sopenharmony_ci	[TOMOYO_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
115262306a36Sopenharmony_ci	[TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n",
115362306a36Sopenharmony_ci};
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci/**
115662306a36Sopenharmony_ci * tomoyo_write_domain - Write domain policy.
115762306a36Sopenharmony_ci *
115862306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
115962306a36Sopenharmony_ci *
116062306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
116162306a36Sopenharmony_ci *
116262306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
116362306a36Sopenharmony_ci */
116462306a36Sopenharmony_cistatic int tomoyo_write_domain(struct tomoyo_io_buffer *head)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	char *data = head->write_buf;
116762306a36Sopenharmony_ci	struct tomoyo_policy_namespace *ns;
116862306a36Sopenharmony_ci	struct tomoyo_domain_info *domain = head->w.domain;
116962306a36Sopenharmony_ci	const bool is_delete = head->w.is_delete;
117062306a36Sopenharmony_ci	bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
117162306a36Sopenharmony_ci	unsigned int idx;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (*data == '<') {
117462306a36Sopenharmony_ci		int ret = 0;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci		domain = NULL;
117762306a36Sopenharmony_ci		if (is_delete)
117862306a36Sopenharmony_ci			ret = tomoyo_delete_domain(data);
117962306a36Sopenharmony_ci		else if (is_select)
118062306a36Sopenharmony_ci			domain = tomoyo_find_domain(data);
118162306a36Sopenharmony_ci		else
118262306a36Sopenharmony_ci			domain = tomoyo_assign_domain(data, false);
118362306a36Sopenharmony_ci		head->w.domain = domain;
118462306a36Sopenharmony_ci		return ret;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci	if (!domain)
118762306a36Sopenharmony_ci		return -EINVAL;
118862306a36Sopenharmony_ci	ns = domain->ns;
118962306a36Sopenharmony_ci	if (sscanf(data, "use_profile %u", &idx) == 1
119062306a36Sopenharmony_ci	    && idx < TOMOYO_MAX_PROFILES) {
119162306a36Sopenharmony_ci		if (!tomoyo_policy_loaded || ns->profile_ptr[idx])
119262306a36Sopenharmony_ci			if (!is_delete)
119362306a36Sopenharmony_ci				domain->profile = (u8) idx;
119462306a36Sopenharmony_ci		return 0;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci	if (sscanf(data, "use_group %u\n", &idx) == 1
119762306a36Sopenharmony_ci	    && idx < TOMOYO_MAX_ACL_GROUPS) {
119862306a36Sopenharmony_ci		if (!is_delete)
119962306a36Sopenharmony_ci			set_bit(idx, domain->group);
120062306a36Sopenharmony_ci		else
120162306a36Sopenharmony_ci			clear_bit(idx, domain->group);
120262306a36Sopenharmony_ci		return 0;
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_DOMAIN_INFO_FLAGS; idx++) {
120562306a36Sopenharmony_ci		const char *cp = tomoyo_dif[idx];
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci		if (strncmp(data, cp, strlen(cp) - 1))
120862306a36Sopenharmony_ci			continue;
120962306a36Sopenharmony_ci		domain->flags[idx] = !is_delete;
121062306a36Sopenharmony_ci		return 0;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci	return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
121362306a36Sopenharmony_ci				    is_delete);
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci/**
121762306a36Sopenharmony_ci * tomoyo_print_condition - Print condition part.
121862306a36Sopenharmony_ci *
121962306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
122062306a36Sopenharmony_ci * @cond: Pointer to "struct tomoyo_condition".
122162306a36Sopenharmony_ci *
122262306a36Sopenharmony_ci * Returns true on success, false otherwise.
122362306a36Sopenharmony_ci */
122462306a36Sopenharmony_cistatic bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
122562306a36Sopenharmony_ci				   const struct tomoyo_condition *cond)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	switch (head->r.cond_step) {
122862306a36Sopenharmony_ci	case 0:
122962306a36Sopenharmony_ci		head->r.cond_index = 0;
123062306a36Sopenharmony_ci		head->r.cond_step++;
123162306a36Sopenharmony_ci		if (cond->transit) {
123262306a36Sopenharmony_ci			tomoyo_set_space(head);
123362306a36Sopenharmony_ci			tomoyo_set_string(head, cond->transit->name);
123462306a36Sopenharmony_ci		}
123562306a36Sopenharmony_ci		fallthrough;
123662306a36Sopenharmony_ci	case 1:
123762306a36Sopenharmony_ci		{
123862306a36Sopenharmony_ci			const u16 condc = cond->condc;
123962306a36Sopenharmony_ci			const struct tomoyo_condition_element *condp =
124062306a36Sopenharmony_ci				(typeof(condp)) (cond + 1);
124162306a36Sopenharmony_ci			const struct tomoyo_number_union *numbers_p =
124262306a36Sopenharmony_ci				(typeof(numbers_p)) (condp + condc);
124362306a36Sopenharmony_ci			const struct tomoyo_name_union *names_p =
124462306a36Sopenharmony_ci				(typeof(names_p))
124562306a36Sopenharmony_ci				(numbers_p + cond->numbers_count);
124662306a36Sopenharmony_ci			const struct tomoyo_argv *argv =
124762306a36Sopenharmony_ci				(typeof(argv)) (names_p + cond->names_count);
124862306a36Sopenharmony_ci			const struct tomoyo_envp *envp =
124962306a36Sopenharmony_ci				(typeof(envp)) (argv + cond->argc);
125062306a36Sopenharmony_ci			u16 skip;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci			for (skip = 0; skip < head->r.cond_index; skip++) {
125362306a36Sopenharmony_ci				const u8 left = condp->left;
125462306a36Sopenharmony_ci				const u8 right = condp->right;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci				condp++;
125762306a36Sopenharmony_ci				switch (left) {
125862306a36Sopenharmony_ci				case TOMOYO_ARGV_ENTRY:
125962306a36Sopenharmony_ci					argv++;
126062306a36Sopenharmony_ci					continue;
126162306a36Sopenharmony_ci				case TOMOYO_ENVP_ENTRY:
126262306a36Sopenharmony_ci					envp++;
126362306a36Sopenharmony_ci					continue;
126462306a36Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
126562306a36Sopenharmony_ci					numbers_p++;
126662306a36Sopenharmony_ci					break;
126762306a36Sopenharmony_ci				}
126862306a36Sopenharmony_ci				switch (right) {
126962306a36Sopenharmony_ci				case TOMOYO_NAME_UNION:
127062306a36Sopenharmony_ci					names_p++;
127162306a36Sopenharmony_ci					break;
127262306a36Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
127362306a36Sopenharmony_ci					numbers_p++;
127462306a36Sopenharmony_ci					break;
127562306a36Sopenharmony_ci				}
127662306a36Sopenharmony_ci			}
127762306a36Sopenharmony_ci			while (head->r.cond_index < condc) {
127862306a36Sopenharmony_ci				const u8 match = condp->equals;
127962306a36Sopenharmony_ci				const u8 left = condp->left;
128062306a36Sopenharmony_ci				const u8 right = condp->right;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci				if (!tomoyo_flush(head))
128362306a36Sopenharmony_ci					return false;
128462306a36Sopenharmony_ci				condp++;
128562306a36Sopenharmony_ci				head->r.cond_index++;
128662306a36Sopenharmony_ci				tomoyo_set_space(head);
128762306a36Sopenharmony_ci				switch (left) {
128862306a36Sopenharmony_ci				case TOMOYO_ARGV_ENTRY:
128962306a36Sopenharmony_ci					tomoyo_io_printf(head,
129062306a36Sopenharmony_ci							 "exec.argv[%lu]%s=\"",
129162306a36Sopenharmony_ci							 argv->index, argv->is_not ? "!" : "");
129262306a36Sopenharmony_ci					tomoyo_set_string(head,
129362306a36Sopenharmony_ci							  argv->value->name);
129462306a36Sopenharmony_ci					tomoyo_set_string(head, "\"");
129562306a36Sopenharmony_ci					argv++;
129662306a36Sopenharmony_ci					continue;
129762306a36Sopenharmony_ci				case TOMOYO_ENVP_ENTRY:
129862306a36Sopenharmony_ci					tomoyo_set_string(head,
129962306a36Sopenharmony_ci							  "exec.envp[\"");
130062306a36Sopenharmony_ci					tomoyo_set_string(head,
130162306a36Sopenharmony_ci							  envp->name->name);
130262306a36Sopenharmony_ci					tomoyo_io_printf(head, "\"]%s=", envp->is_not ? "!" : "");
130362306a36Sopenharmony_ci					if (envp->value) {
130462306a36Sopenharmony_ci						tomoyo_set_string(head, "\"");
130562306a36Sopenharmony_ci						tomoyo_set_string(head, envp->value->name);
130662306a36Sopenharmony_ci						tomoyo_set_string(head, "\"");
130762306a36Sopenharmony_ci					} else {
130862306a36Sopenharmony_ci						tomoyo_set_string(head,
130962306a36Sopenharmony_ci								  "NULL");
131062306a36Sopenharmony_ci					}
131162306a36Sopenharmony_ci					envp++;
131262306a36Sopenharmony_ci					continue;
131362306a36Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
131462306a36Sopenharmony_ci					tomoyo_print_number_union_nospace
131562306a36Sopenharmony_ci						(head, numbers_p++);
131662306a36Sopenharmony_ci					break;
131762306a36Sopenharmony_ci				default:
131862306a36Sopenharmony_ci					tomoyo_set_string(head,
131962306a36Sopenharmony_ci					       tomoyo_condition_keyword[left]);
132062306a36Sopenharmony_ci					break;
132162306a36Sopenharmony_ci				}
132262306a36Sopenharmony_ci				tomoyo_set_string(head, match ? "=" : "!=");
132362306a36Sopenharmony_ci				switch (right) {
132462306a36Sopenharmony_ci				case TOMOYO_NAME_UNION:
132562306a36Sopenharmony_ci					tomoyo_print_name_union_quoted
132662306a36Sopenharmony_ci						(head, names_p++);
132762306a36Sopenharmony_ci					break;
132862306a36Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
132962306a36Sopenharmony_ci					tomoyo_print_number_union_nospace
133062306a36Sopenharmony_ci						(head, numbers_p++);
133162306a36Sopenharmony_ci					break;
133262306a36Sopenharmony_ci				default:
133362306a36Sopenharmony_ci					tomoyo_set_string(head,
133462306a36Sopenharmony_ci					  tomoyo_condition_keyword[right]);
133562306a36Sopenharmony_ci					break;
133662306a36Sopenharmony_ci				}
133762306a36Sopenharmony_ci			}
133862306a36Sopenharmony_ci		}
133962306a36Sopenharmony_ci		head->r.cond_step++;
134062306a36Sopenharmony_ci		fallthrough;
134162306a36Sopenharmony_ci	case 2:
134262306a36Sopenharmony_ci		if (!tomoyo_flush(head))
134362306a36Sopenharmony_ci			break;
134462306a36Sopenharmony_ci		head->r.cond_step++;
134562306a36Sopenharmony_ci		fallthrough;
134662306a36Sopenharmony_ci	case 3:
134762306a36Sopenharmony_ci		if (cond->grant_log != TOMOYO_GRANTLOG_AUTO)
134862306a36Sopenharmony_ci			tomoyo_io_printf(head, " grant_log=%s",
134962306a36Sopenharmony_ci					 str_yes_no(cond->grant_log ==
135062306a36Sopenharmony_ci						    TOMOYO_GRANTLOG_YES));
135162306a36Sopenharmony_ci		tomoyo_set_lf(head);
135262306a36Sopenharmony_ci		return true;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci	return false;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci/**
135862306a36Sopenharmony_ci * tomoyo_set_group - Print "acl_group " header keyword and category name.
135962306a36Sopenharmony_ci *
136062306a36Sopenharmony_ci * @head:     Pointer to "struct tomoyo_io_buffer".
136162306a36Sopenharmony_ci * @category: Category name.
136262306a36Sopenharmony_ci *
136362306a36Sopenharmony_ci * Returns nothing.
136462306a36Sopenharmony_ci */
136562306a36Sopenharmony_cistatic void tomoyo_set_group(struct tomoyo_io_buffer *head,
136662306a36Sopenharmony_ci			     const char *category)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	if (head->type == TOMOYO_EXCEPTIONPOLICY) {
136962306a36Sopenharmony_ci		tomoyo_print_namespace(head);
137062306a36Sopenharmony_ci		tomoyo_io_printf(head, "acl_group %u ",
137162306a36Sopenharmony_ci				 head->r.acl_group_index);
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci	tomoyo_set_string(head, category);
137462306a36Sopenharmony_ci}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci/**
137762306a36Sopenharmony_ci * tomoyo_print_entry - Print an ACL entry.
137862306a36Sopenharmony_ci *
137962306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
138062306a36Sopenharmony_ci * @acl:  Pointer to an ACL entry.
138162306a36Sopenharmony_ci *
138262306a36Sopenharmony_ci * Returns true on success, false otherwise.
138362306a36Sopenharmony_ci */
138462306a36Sopenharmony_cistatic bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
138562306a36Sopenharmony_ci			       struct tomoyo_acl_info *acl)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	const u8 acl_type = acl->type;
138862306a36Sopenharmony_ci	bool first = true;
138962306a36Sopenharmony_ci	u8 bit;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	if (head->r.print_cond_part)
139262306a36Sopenharmony_ci		goto print_cond_part;
139362306a36Sopenharmony_ci	if (acl->is_deleted)
139462306a36Sopenharmony_ci		return true;
139562306a36Sopenharmony_ci	if (!tomoyo_flush(head))
139662306a36Sopenharmony_ci		return false;
139762306a36Sopenharmony_ci	else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
139862306a36Sopenharmony_ci		struct tomoyo_path_acl *ptr =
139962306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
140062306a36Sopenharmony_ci		const u16 perm = ptr->perm;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
140362306a36Sopenharmony_ci			if (!(perm & (1 << bit)))
140462306a36Sopenharmony_ci				continue;
140562306a36Sopenharmony_ci			if (head->r.print_transition_related_only &&
140662306a36Sopenharmony_ci			    bit != TOMOYO_TYPE_EXECUTE)
140762306a36Sopenharmony_ci				continue;
140862306a36Sopenharmony_ci			if (first) {
140962306a36Sopenharmony_ci				tomoyo_set_group(head, "file ");
141062306a36Sopenharmony_ci				first = false;
141162306a36Sopenharmony_ci			} else {
141262306a36Sopenharmony_ci				tomoyo_set_slash(head);
141362306a36Sopenharmony_ci			}
141462306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_path_keyword[bit]);
141562306a36Sopenharmony_ci		}
141662306a36Sopenharmony_ci		if (first)
141762306a36Sopenharmony_ci			return true;
141862306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
141962306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
142062306a36Sopenharmony_ci		struct tomoyo_task_acl *ptr =
142162306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		tomoyo_set_group(head, "task ");
142462306a36Sopenharmony_ci		tomoyo_set_string(head, "manual_domain_transition ");
142562306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->domainname->name);
142662306a36Sopenharmony_ci	} else if (head->r.print_transition_related_only) {
142762306a36Sopenharmony_ci		return true;
142862306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
142962306a36Sopenharmony_ci		struct tomoyo_path2_acl *ptr =
143062306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
143162306a36Sopenharmony_ci		const u8 perm = ptr->perm;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
143462306a36Sopenharmony_ci			if (!(perm & (1 << bit)))
143562306a36Sopenharmony_ci				continue;
143662306a36Sopenharmony_ci			if (first) {
143762306a36Sopenharmony_ci				tomoyo_set_group(head, "file ");
143862306a36Sopenharmony_ci				first = false;
143962306a36Sopenharmony_ci			} else {
144062306a36Sopenharmony_ci				tomoyo_set_slash(head);
144162306a36Sopenharmony_ci			}
144262306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_mac_keywords
144362306a36Sopenharmony_ci					  [tomoyo_pp2mac[bit]]);
144462306a36Sopenharmony_ci		}
144562306a36Sopenharmony_ci		if (first)
144662306a36Sopenharmony_ci			return true;
144762306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name1);
144862306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name2);
144962306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
145062306a36Sopenharmony_ci		struct tomoyo_path_number_acl *ptr =
145162306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
145262306a36Sopenharmony_ci		const u8 perm = ptr->perm;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) {
145562306a36Sopenharmony_ci			if (!(perm & (1 << bit)))
145662306a36Sopenharmony_ci				continue;
145762306a36Sopenharmony_ci			if (first) {
145862306a36Sopenharmony_ci				tomoyo_set_group(head, "file ");
145962306a36Sopenharmony_ci				first = false;
146062306a36Sopenharmony_ci			} else {
146162306a36Sopenharmony_ci				tomoyo_set_slash(head);
146262306a36Sopenharmony_ci			}
146362306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_mac_keywords
146462306a36Sopenharmony_ci					  [tomoyo_pn2mac[bit]]);
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci		if (first)
146762306a36Sopenharmony_ci			return true;
146862306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
146962306a36Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->number);
147062306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
147162306a36Sopenharmony_ci		struct tomoyo_mkdev_acl *ptr =
147262306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
147362306a36Sopenharmony_ci		const u8 perm = ptr->perm;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) {
147662306a36Sopenharmony_ci			if (!(perm & (1 << bit)))
147762306a36Sopenharmony_ci				continue;
147862306a36Sopenharmony_ci			if (first) {
147962306a36Sopenharmony_ci				tomoyo_set_group(head, "file ");
148062306a36Sopenharmony_ci				first = false;
148162306a36Sopenharmony_ci			} else {
148262306a36Sopenharmony_ci				tomoyo_set_slash(head);
148362306a36Sopenharmony_ci			}
148462306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_mac_keywords
148562306a36Sopenharmony_ci					  [tomoyo_pnnn2mac[bit]]);
148662306a36Sopenharmony_ci		}
148762306a36Sopenharmony_ci		if (first)
148862306a36Sopenharmony_ci			return true;
148962306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
149062306a36Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->mode);
149162306a36Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->major);
149262306a36Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->minor);
149362306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_INET_ACL) {
149462306a36Sopenharmony_ci		struct tomoyo_inet_acl *ptr =
149562306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
149662306a36Sopenharmony_ci		const u8 perm = ptr->perm;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
149962306a36Sopenharmony_ci			if (!(perm & (1 << bit)))
150062306a36Sopenharmony_ci				continue;
150162306a36Sopenharmony_ci			if (first) {
150262306a36Sopenharmony_ci				tomoyo_set_group(head, "network inet ");
150362306a36Sopenharmony_ci				tomoyo_set_string(head, tomoyo_proto_keyword
150462306a36Sopenharmony_ci						  [ptr->protocol]);
150562306a36Sopenharmony_ci				tomoyo_set_space(head);
150662306a36Sopenharmony_ci				first = false;
150762306a36Sopenharmony_ci			} else {
150862306a36Sopenharmony_ci				tomoyo_set_slash(head);
150962306a36Sopenharmony_ci			}
151062306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
151162306a36Sopenharmony_ci		}
151262306a36Sopenharmony_ci		if (first)
151362306a36Sopenharmony_ci			return true;
151462306a36Sopenharmony_ci		tomoyo_set_space(head);
151562306a36Sopenharmony_ci		if (ptr->address.group) {
151662306a36Sopenharmony_ci			tomoyo_set_string(head, "@");
151762306a36Sopenharmony_ci			tomoyo_set_string(head, ptr->address.group->group_name
151862306a36Sopenharmony_ci					  ->name);
151962306a36Sopenharmony_ci		} else {
152062306a36Sopenharmony_ci			char buf[128];
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci			tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
152362306a36Sopenharmony_ci			tomoyo_io_printf(head, "%s", buf);
152462306a36Sopenharmony_ci		}
152562306a36Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->port);
152662306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_UNIX_ACL) {
152762306a36Sopenharmony_ci		struct tomoyo_unix_acl *ptr =
152862306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
152962306a36Sopenharmony_ci		const u8 perm = ptr->perm;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
153262306a36Sopenharmony_ci			if (!(perm & (1 << bit)))
153362306a36Sopenharmony_ci				continue;
153462306a36Sopenharmony_ci			if (first) {
153562306a36Sopenharmony_ci				tomoyo_set_group(head, "network unix ");
153662306a36Sopenharmony_ci				tomoyo_set_string(head, tomoyo_proto_keyword
153762306a36Sopenharmony_ci						  [ptr->protocol]);
153862306a36Sopenharmony_ci				tomoyo_set_space(head);
153962306a36Sopenharmony_ci				first = false;
154062306a36Sopenharmony_ci			} else {
154162306a36Sopenharmony_ci				tomoyo_set_slash(head);
154262306a36Sopenharmony_ci			}
154362306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
154462306a36Sopenharmony_ci		}
154562306a36Sopenharmony_ci		if (first)
154662306a36Sopenharmony_ci			return true;
154762306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
154862306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
154962306a36Sopenharmony_ci		struct tomoyo_mount_acl *ptr =
155062306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci		tomoyo_set_group(head, "file mount");
155362306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->dev_name);
155462306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->dir_name);
155562306a36Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->fs_type);
155662306a36Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->flags);
155762306a36Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_ENV_ACL) {
155862306a36Sopenharmony_ci		struct tomoyo_env_acl *ptr =
155962306a36Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		tomoyo_set_group(head, "misc env ");
156262306a36Sopenharmony_ci		tomoyo_set_string(head, ptr->env->name);
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci	if (acl->cond) {
156562306a36Sopenharmony_ci		head->r.print_cond_part = true;
156662306a36Sopenharmony_ci		head->r.cond_step = 0;
156762306a36Sopenharmony_ci		if (!tomoyo_flush(head))
156862306a36Sopenharmony_ci			return false;
156962306a36Sopenharmony_ciprint_cond_part:
157062306a36Sopenharmony_ci		if (!tomoyo_print_condition(head, acl->cond))
157162306a36Sopenharmony_ci			return false;
157262306a36Sopenharmony_ci		head->r.print_cond_part = false;
157362306a36Sopenharmony_ci	} else {
157462306a36Sopenharmony_ci		tomoyo_set_lf(head);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci	return true;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci/**
158062306a36Sopenharmony_ci * tomoyo_read_domain2 - Read domain policy.
158162306a36Sopenharmony_ci *
158262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
158362306a36Sopenharmony_ci * @list: Pointer to "struct list_head".
158462306a36Sopenharmony_ci *
158562306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
158662306a36Sopenharmony_ci *
158762306a36Sopenharmony_ci * Returns true on success, false otherwise.
158862306a36Sopenharmony_ci */
158962306a36Sopenharmony_cistatic bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
159062306a36Sopenharmony_ci				struct list_head *list)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	list_for_each_cookie(head->r.acl, list) {
159362306a36Sopenharmony_ci		struct tomoyo_acl_info *ptr =
159462306a36Sopenharmony_ci			list_entry(head->r.acl, typeof(*ptr), list);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		if (!tomoyo_print_entry(head, ptr))
159762306a36Sopenharmony_ci			return false;
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci	head->r.acl = NULL;
160062306a36Sopenharmony_ci	return true;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci/**
160462306a36Sopenharmony_ci * tomoyo_read_domain - Read domain policy.
160562306a36Sopenharmony_ci *
160662306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
160762306a36Sopenharmony_ci *
160862306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
160962306a36Sopenharmony_ci */
161062306a36Sopenharmony_cistatic void tomoyo_read_domain(struct tomoyo_io_buffer *head)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	if (head->r.eof)
161362306a36Sopenharmony_ci		return;
161462306a36Sopenharmony_ci	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
161562306a36Sopenharmony_ci		struct tomoyo_domain_info *domain =
161662306a36Sopenharmony_ci			list_entry(head->r.domain, typeof(*domain), list);
161762306a36Sopenharmony_ci		u8 i;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		switch (head->r.step) {
162062306a36Sopenharmony_ci		case 0:
162162306a36Sopenharmony_ci			if (domain->is_deleted &&
162262306a36Sopenharmony_ci			    !head->r.print_this_domain_only)
162362306a36Sopenharmony_ci				continue;
162462306a36Sopenharmony_ci			/* Print domainname and flags. */
162562306a36Sopenharmony_ci			tomoyo_set_string(head, domain->domainname->name);
162662306a36Sopenharmony_ci			tomoyo_set_lf(head);
162762306a36Sopenharmony_ci			tomoyo_io_printf(head, "use_profile %u\n",
162862306a36Sopenharmony_ci					 domain->profile);
162962306a36Sopenharmony_ci			for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
163062306a36Sopenharmony_ci				if (domain->flags[i])
163162306a36Sopenharmony_ci					tomoyo_set_string(head, tomoyo_dif[i]);
163262306a36Sopenharmony_ci			head->r.index = 0;
163362306a36Sopenharmony_ci			head->r.step++;
163462306a36Sopenharmony_ci			fallthrough;
163562306a36Sopenharmony_ci		case 1:
163662306a36Sopenharmony_ci			while (head->r.index < TOMOYO_MAX_ACL_GROUPS) {
163762306a36Sopenharmony_ci				i = head->r.index++;
163862306a36Sopenharmony_ci				if (!test_bit(i, domain->group))
163962306a36Sopenharmony_ci					continue;
164062306a36Sopenharmony_ci				tomoyo_io_printf(head, "use_group %u\n", i);
164162306a36Sopenharmony_ci				if (!tomoyo_flush(head))
164262306a36Sopenharmony_ci					return;
164362306a36Sopenharmony_ci			}
164462306a36Sopenharmony_ci			head->r.index = 0;
164562306a36Sopenharmony_ci			head->r.step++;
164662306a36Sopenharmony_ci			tomoyo_set_lf(head);
164762306a36Sopenharmony_ci			fallthrough;
164862306a36Sopenharmony_ci		case 2:
164962306a36Sopenharmony_ci			if (!tomoyo_read_domain2(head, &domain->acl_info_list))
165062306a36Sopenharmony_ci				return;
165162306a36Sopenharmony_ci			head->r.step++;
165262306a36Sopenharmony_ci			if (!tomoyo_set_lf(head))
165362306a36Sopenharmony_ci				return;
165462306a36Sopenharmony_ci			fallthrough;
165562306a36Sopenharmony_ci		case 3:
165662306a36Sopenharmony_ci			head->r.step = 0;
165762306a36Sopenharmony_ci			if (head->r.print_this_domain_only)
165862306a36Sopenharmony_ci				goto done;
165962306a36Sopenharmony_ci		}
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci done:
166262306a36Sopenharmony_ci	head->r.eof = true;
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci/**
166662306a36Sopenharmony_ci * tomoyo_write_pid: Specify PID to obtain domainname.
166762306a36Sopenharmony_ci *
166862306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
166962306a36Sopenharmony_ci *
167062306a36Sopenharmony_ci * Returns 0.
167162306a36Sopenharmony_ci */
167262306a36Sopenharmony_cistatic int tomoyo_write_pid(struct tomoyo_io_buffer *head)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	head->r.eof = false;
167562306a36Sopenharmony_ci	return 0;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci/**
167962306a36Sopenharmony_ci * tomoyo_read_pid - Get domainname of the specified PID.
168062306a36Sopenharmony_ci *
168162306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
168262306a36Sopenharmony_ci *
168362306a36Sopenharmony_ci * Returns the domainname which the specified PID is in on success,
168462306a36Sopenharmony_ci * empty string otherwise.
168562306a36Sopenharmony_ci * The PID is specified by tomoyo_write_pid() so that the user can obtain
168662306a36Sopenharmony_ci * using read()/write() interface rather than sysctl() interface.
168762306a36Sopenharmony_ci */
168862306a36Sopenharmony_cistatic void tomoyo_read_pid(struct tomoyo_io_buffer *head)
168962306a36Sopenharmony_ci{
169062306a36Sopenharmony_ci	char *buf = head->write_buf;
169162306a36Sopenharmony_ci	bool global_pid = false;
169262306a36Sopenharmony_ci	unsigned int pid;
169362306a36Sopenharmony_ci	struct task_struct *p;
169462306a36Sopenharmony_ci	struct tomoyo_domain_info *domain = NULL;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	/* Accessing write_buf is safe because head->io_sem is held. */
169762306a36Sopenharmony_ci	if (!buf) {
169862306a36Sopenharmony_ci		head->r.eof = true;
169962306a36Sopenharmony_ci		return; /* Do nothing if open(O_RDONLY). */
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci	if (head->r.w_pos || head->r.eof)
170262306a36Sopenharmony_ci		return;
170362306a36Sopenharmony_ci	head->r.eof = true;
170462306a36Sopenharmony_ci	if (tomoyo_str_starts(&buf, "global-pid "))
170562306a36Sopenharmony_ci		global_pid = true;
170662306a36Sopenharmony_ci	if (kstrtouint(buf, 10, &pid))
170762306a36Sopenharmony_ci		return;
170862306a36Sopenharmony_ci	rcu_read_lock();
170962306a36Sopenharmony_ci	if (global_pid)
171062306a36Sopenharmony_ci		p = find_task_by_pid_ns(pid, &init_pid_ns);
171162306a36Sopenharmony_ci	else
171262306a36Sopenharmony_ci		p = find_task_by_vpid(pid);
171362306a36Sopenharmony_ci	if (p)
171462306a36Sopenharmony_ci		domain = tomoyo_task(p)->domain_info;
171562306a36Sopenharmony_ci	rcu_read_unlock();
171662306a36Sopenharmony_ci	if (!domain)
171762306a36Sopenharmony_ci		return;
171862306a36Sopenharmony_ci	tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
171962306a36Sopenharmony_ci	tomoyo_set_string(head, domain->domainname->name);
172062306a36Sopenharmony_ci}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci/* String table for domain transition control keywords. */
172362306a36Sopenharmony_cistatic const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
172462306a36Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
172562306a36Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_RESET]         = "reset_domain ",
172662306a36Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
172762306a36Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
172862306a36Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
172962306a36Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
173062306a36Sopenharmony_ci};
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci/* String table for grouping keywords. */
173362306a36Sopenharmony_cistatic const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
173462306a36Sopenharmony_ci	[TOMOYO_PATH_GROUP]    = "path_group ",
173562306a36Sopenharmony_ci	[TOMOYO_NUMBER_GROUP]  = "number_group ",
173662306a36Sopenharmony_ci	[TOMOYO_ADDRESS_GROUP] = "address_group ",
173762306a36Sopenharmony_ci};
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci/**
174062306a36Sopenharmony_ci * tomoyo_write_exception - Write exception policy.
174162306a36Sopenharmony_ci *
174262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
174362306a36Sopenharmony_ci *
174462306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
174562306a36Sopenharmony_ci *
174662306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
174762306a36Sopenharmony_ci */
174862306a36Sopenharmony_cistatic int tomoyo_write_exception(struct tomoyo_io_buffer *head)
174962306a36Sopenharmony_ci{
175062306a36Sopenharmony_ci	const bool is_delete = head->w.is_delete;
175162306a36Sopenharmony_ci	struct tomoyo_acl_param param = {
175262306a36Sopenharmony_ci		.ns = head->w.ns,
175362306a36Sopenharmony_ci		.is_delete = is_delete,
175462306a36Sopenharmony_ci		.data = head->write_buf,
175562306a36Sopenharmony_ci	};
175662306a36Sopenharmony_ci	u8 i;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	if (tomoyo_str_starts(&param.data, "aggregator "))
175962306a36Sopenharmony_ci		return tomoyo_write_aggregator(&param);
176062306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
176162306a36Sopenharmony_ci		if (tomoyo_str_starts(&param.data, tomoyo_transition_type[i]))
176262306a36Sopenharmony_ci			return tomoyo_write_transition_control(&param, i);
176362306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_GROUP; i++)
176462306a36Sopenharmony_ci		if (tomoyo_str_starts(&param.data, tomoyo_group_name[i]))
176562306a36Sopenharmony_ci			return tomoyo_write_group(&param, i);
176662306a36Sopenharmony_ci	if (tomoyo_str_starts(&param.data, "acl_group ")) {
176762306a36Sopenharmony_ci		unsigned int group;
176862306a36Sopenharmony_ci		char *data;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci		group = simple_strtoul(param.data, &data, 10);
177162306a36Sopenharmony_ci		if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
177262306a36Sopenharmony_ci			return tomoyo_write_domain2
177362306a36Sopenharmony_ci				(head->w.ns, &head->w.ns->acl_group[group],
177462306a36Sopenharmony_ci				 data, is_delete);
177562306a36Sopenharmony_ci	}
177662306a36Sopenharmony_ci	return -EINVAL;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci/**
178062306a36Sopenharmony_ci * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
178162306a36Sopenharmony_ci *
178262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
178362306a36Sopenharmony_ci * @idx:  Index number.
178462306a36Sopenharmony_ci *
178562306a36Sopenharmony_ci * Returns true on success, false otherwise.
178662306a36Sopenharmony_ci *
178762306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
178862306a36Sopenharmony_ci */
178962306a36Sopenharmony_cistatic bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
179262306a36Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
179362306a36Sopenharmony_ci	struct list_head *list = &ns->group_list[idx];
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	list_for_each_cookie(head->r.group, list) {
179662306a36Sopenharmony_ci		struct tomoyo_group *group =
179762306a36Sopenharmony_ci			list_entry(head->r.group, typeof(*group), head.list);
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci		list_for_each_cookie(head->r.acl, &group->member_list) {
180062306a36Sopenharmony_ci			struct tomoyo_acl_head *ptr =
180162306a36Sopenharmony_ci				list_entry(head->r.acl, typeof(*ptr), list);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci			if (ptr->is_deleted)
180462306a36Sopenharmony_ci				continue;
180562306a36Sopenharmony_ci			if (!tomoyo_flush(head))
180662306a36Sopenharmony_ci				return false;
180762306a36Sopenharmony_ci			tomoyo_print_namespace(head);
180862306a36Sopenharmony_ci			tomoyo_set_string(head, tomoyo_group_name[idx]);
180962306a36Sopenharmony_ci			tomoyo_set_string(head, group->group_name->name);
181062306a36Sopenharmony_ci			if (idx == TOMOYO_PATH_GROUP) {
181162306a36Sopenharmony_ci				tomoyo_set_space(head);
181262306a36Sopenharmony_ci				tomoyo_set_string(head, container_of
181362306a36Sopenharmony_ci					       (ptr, struct tomoyo_path_group,
181462306a36Sopenharmony_ci						head)->member_name->name);
181562306a36Sopenharmony_ci			} else if (idx == TOMOYO_NUMBER_GROUP) {
181662306a36Sopenharmony_ci				tomoyo_print_number_union(head, &container_of
181762306a36Sopenharmony_ci							  (ptr,
181862306a36Sopenharmony_ci						   struct tomoyo_number_group,
181962306a36Sopenharmony_ci							   head)->number);
182062306a36Sopenharmony_ci			} else if (idx == TOMOYO_ADDRESS_GROUP) {
182162306a36Sopenharmony_ci				char buffer[128];
182262306a36Sopenharmony_ci				struct tomoyo_address_group *member =
182362306a36Sopenharmony_ci					container_of(ptr, typeof(*member),
182462306a36Sopenharmony_ci						     head);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci				tomoyo_print_ip(buffer, sizeof(buffer),
182762306a36Sopenharmony_ci						&member->address);
182862306a36Sopenharmony_ci				tomoyo_io_printf(head, " %s", buffer);
182962306a36Sopenharmony_ci			}
183062306a36Sopenharmony_ci			tomoyo_set_lf(head);
183162306a36Sopenharmony_ci		}
183262306a36Sopenharmony_ci		head->r.acl = NULL;
183362306a36Sopenharmony_ci	}
183462306a36Sopenharmony_ci	head->r.group = NULL;
183562306a36Sopenharmony_ci	return true;
183662306a36Sopenharmony_ci}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci/**
183962306a36Sopenharmony_ci * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
184062306a36Sopenharmony_ci *
184162306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
184262306a36Sopenharmony_ci * @idx:  Index number.
184362306a36Sopenharmony_ci *
184462306a36Sopenharmony_ci * Returns true on success, false otherwise.
184562306a36Sopenharmony_ci *
184662306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
184762306a36Sopenharmony_ci */
184862306a36Sopenharmony_cistatic bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
184962306a36Sopenharmony_ci{
185062306a36Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
185162306a36Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
185262306a36Sopenharmony_ci	struct list_head *list = &ns->policy_list[idx];
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	list_for_each_cookie(head->r.acl, list) {
185562306a36Sopenharmony_ci		struct tomoyo_acl_head *acl =
185662306a36Sopenharmony_ci			container_of(head->r.acl, typeof(*acl), list);
185762306a36Sopenharmony_ci		if (acl->is_deleted)
185862306a36Sopenharmony_ci			continue;
185962306a36Sopenharmony_ci		if (!tomoyo_flush(head))
186062306a36Sopenharmony_ci			return false;
186162306a36Sopenharmony_ci		switch (idx) {
186262306a36Sopenharmony_ci		case TOMOYO_ID_TRANSITION_CONTROL:
186362306a36Sopenharmony_ci			{
186462306a36Sopenharmony_ci				struct tomoyo_transition_control *ptr =
186562306a36Sopenharmony_ci					container_of(acl, typeof(*ptr), head);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci				tomoyo_print_namespace(head);
186862306a36Sopenharmony_ci				tomoyo_set_string(head, tomoyo_transition_type
186962306a36Sopenharmony_ci						  [ptr->type]);
187062306a36Sopenharmony_ci				tomoyo_set_string(head, ptr->program ?
187162306a36Sopenharmony_ci						  ptr->program->name : "any");
187262306a36Sopenharmony_ci				tomoyo_set_string(head, " from ");
187362306a36Sopenharmony_ci				tomoyo_set_string(head, ptr->domainname ?
187462306a36Sopenharmony_ci						  ptr->domainname->name :
187562306a36Sopenharmony_ci						  "any");
187662306a36Sopenharmony_ci			}
187762306a36Sopenharmony_ci			break;
187862306a36Sopenharmony_ci		case TOMOYO_ID_AGGREGATOR:
187962306a36Sopenharmony_ci			{
188062306a36Sopenharmony_ci				struct tomoyo_aggregator *ptr =
188162306a36Sopenharmony_ci					container_of(acl, typeof(*ptr), head);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci				tomoyo_print_namespace(head);
188462306a36Sopenharmony_ci				tomoyo_set_string(head, "aggregator ");
188562306a36Sopenharmony_ci				tomoyo_set_string(head,
188662306a36Sopenharmony_ci						  ptr->original_name->name);
188762306a36Sopenharmony_ci				tomoyo_set_space(head);
188862306a36Sopenharmony_ci				tomoyo_set_string(head,
188962306a36Sopenharmony_ci					       ptr->aggregated_name->name);
189062306a36Sopenharmony_ci			}
189162306a36Sopenharmony_ci			break;
189262306a36Sopenharmony_ci		default:
189362306a36Sopenharmony_ci			continue;
189462306a36Sopenharmony_ci		}
189562306a36Sopenharmony_ci		tomoyo_set_lf(head);
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci	head->r.acl = NULL;
189862306a36Sopenharmony_ci	return true;
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci/**
190262306a36Sopenharmony_ci * tomoyo_read_exception - Read exception policy.
190362306a36Sopenharmony_ci *
190462306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
190562306a36Sopenharmony_ci *
190662306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
190762306a36Sopenharmony_ci */
190862306a36Sopenharmony_cistatic void tomoyo_read_exception(struct tomoyo_io_buffer *head)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
191162306a36Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (head->r.eof)
191462306a36Sopenharmony_ci		return;
191562306a36Sopenharmony_ci	while (head->r.step < TOMOYO_MAX_POLICY &&
191662306a36Sopenharmony_ci	       tomoyo_read_policy(head, head->r.step))
191762306a36Sopenharmony_ci		head->r.step++;
191862306a36Sopenharmony_ci	if (head->r.step < TOMOYO_MAX_POLICY)
191962306a36Sopenharmony_ci		return;
192062306a36Sopenharmony_ci	while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
192162306a36Sopenharmony_ci	       tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY))
192262306a36Sopenharmony_ci		head->r.step++;
192362306a36Sopenharmony_ci	if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
192462306a36Sopenharmony_ci		return;
192562306a36Sopenharmony_ci	while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP
192662306a36Sopenharmony_ci	       + TOMOYO_MAX_ACL_GROUPS) {
192762306a36Sopenharmony_ci		head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY
192862306a36Sopenharmony_ci			- TOMOYO_MAX_GROUP;
192962306a36Sopenharmony_ci		if (!tomoyo_read_domain2(head, &ns->acl_group
193062306a36Sopenharmony_ci					 [head->r.acl_group_index]))
193162306a36Sopenharmony_ci			return;
193262306a36Sopenharmony_ci		head->r.step++;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci	head->r.eof = true;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci/* Wait queue for kernel -> userspace notification. */
193862306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
193962306a36Sopenharmony_ci/* Wait queue for userspace -> kernel notification. */
194062306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait);
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci/* Structure for query. */
194362306a36Sopenharmony_cistruct tomoyo_query {
194462306a36Sopenharmony_ci	struct list_head list;
194562306a36Sopenharmony_ci	struct tomoyo_domain_info *domain;
194662306a36Sopenharmony_ci	char *query;
194762306a36Sopenharmony_ci	size_t query_len;
194862306a36Sopenharmony_ci	unsigned int serial;
194962306a36Sopenharmony_ci	u8 timer;
195062306a36Sopenharmony_ci	u8 answer;
195162306a36Sopenharmony_ci	u8 retry;
195262306a36Sopenharmony_ci};
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci/* The list for "struct tomoyo_query". */
195562306a36Sopenharmony_cistatic LIST_HEAD(tomoyo_query_list);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci/* Lock for manipulating tomoyo_query_list. */
195862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(tomoyo_query_list_lock);
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci/*
196162306a36Sopenharmony_ci * Number of "struct file" referring /sys/kernel/security/tomoyo/query
196262306a36Sopenharmony_ci * interface.
196362306a36Sopenharmony_ci */
196462306a36Sopenharmony_cistatic atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci/**
196762306a36Sopenharmony_ci * tomoyo_truncate - Truncate a line.
196862306a36Sopenharmony_ci *
196962306a36Sopenharmony_ci * @str: String to truncate.
197062306a36Sopenharmony_ci *
197162306a36Sopenharmony_ci * Returns length of truncated @str.
197262306a36Sopenharmony_ci */
197362306a36Sopenharmony_cistatic int tomoyo_truncate(char *str)
197462306a36Sopenharmony_ci{
197562306a36Sopenharmony_ci	char *start = str;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	while (*(unsigned char *) str > (unsigned char) ' ')
197862306a36Sopenharmony_ci		str++;
197962306a36Sopenharmony_ci	*str = '\0';
198062306a36Sopenharmony_ci	return strlen(start) + 1;
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci/**
198462306a36Sopenharmony_ci * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode.
198562306a36Sopenharmony_ci *
198662306a36Sopenharmony_ci * @domain: Pointer to "struct tomoyo_domain_info".
198762306a36Sopenharmony_ci * @header: Lines containing ACL.
198862306a36Sopenharmony_ci *
198962306a36Sopenharmony_ci * Returns nothing.
199062306a36Sopenharmony_ci */
199162306a36Sopenharmony_cistatic void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
199262306a36Sopenharmony_ci{
199362306a36Sopenharmony_ci	char *buffer;
199462306a36Sopenharmony_ci	char *realpath = NULL;
199562306a36Sopenharmony_ci	char *argv0 = NULL;
199662306a36Sopenharmony_ci	char *symlink = NULL;
199762306a36Sopenharmony_ci	char *cp = strchr(header, '\n');
199862306a36Sopenharmony_ci	int len;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	if (!cp)
200162306a36Sopenharmony_ci		return;
200262306a36Sopenharmony_ci	cp = strchr(cp + 1, '\n');
200362306a36Sopenharmony_ci	if (!cp)
200462306a36Sopenharmony_ci		return;
200562306a36Sopenharmony_ci	*cp++ = '\0';
200662306a36Sopenharmony_ci	len = strlen(cp) + 1;
200762306a36Sopenharmony_ci	/* strstr() will return NULL if ordering is wrong. */
200862306a36Sopenharmony_ci	if (*cp == 'f') {
200962306a36Sopenharmony_ci		argv0 = strstr(header, " argv[]={ \"");
201062306a36Sopenharmony_ci		if (argv0) {
201162306a36Sopenharmony_ci			argv0 += 10;
201262306a36Sopenharmony_ci			len += tomoyo_truncate(argv0) + 14;
201362306a36Sopenharmony_ci		}
201462306a36Sopenharmony_ci		realpath = strstr(header, " exec={ realpath=\"");
201562306a36Sopenharmony_ci		if (realpath) {
201662306a36Sopenharmony_ci			realpath += 8;
201762306a36Sopenharmony_ci			len += tomoyo_truncate(realpath) + 6;
201862306a36Sopenharmony_ci		}
201962306a36Sopenharmony_ci		symlink = strstr(header, " symlink.target=\"");
202062306a36Sopenharmony_ci		if (symlink)
202162306a36Sopenharmony_ci			len += tomoyo_truncate(symlink + 1) + 1;
202262306a36Sopenharmony_ci	}
202362306a36Sopenharmony_ci	buffer = kmalloc(len, GFP_NOFS);
202462306a36Sopenharmony_ci	if (!buffer)
202562306a36Sopenharmony_ci		return;
202662306a36Sopenharmony_ci	snprintf(buffer, len - 1, "%s", cp);
202762306a36Sopenharmony_ci	if (realpath)
202862306a36Sopenharmony_ci		tomoyo_addprintf(buffer, len, " exec.%s", realpath);
202962306a36Sopenharmony_ci	if (argv0)
203062306a36Sopenharmony_ci		tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
203162306a36Sopenharmony_ci	if (symlink)
203262306a36Sopenharmony_ci		tomoyo_addprintf(buffer, len, "%s", symlink);
203362306a36Sopenharmony_ci	tomoyo_normalize_line(buffer);
203462306a36Sopenharmony_ci	if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
203562306a36Sopenharmony_ci				  false))
203662306a36Sopenharmony_ci		tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
203762306a36Sopenharmony_ci	kfree(buffer);
203862306a36Sopenharmony_ci}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci/**
204162306a36Sopenharmony_ci * tomoyo_supervisor - Ask for the supervisor's decision.
204262306a36Sopenharmony_ci *
204362306a36Sopenharmony_ci * @r:   Pointer to "struct tomoyo_request_info".
204462306a36Sopenharmony_ci * @fmt: The printf()'s format string, followed by parameters.
204562306a36Sopenharmony_ci *
204662306a36Sopenharmony_ci * Returns 0 if the supervisor decided to permit the access request which
204762306a36Sopenharmony_ci * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
204862306a36Sopenharmony_ci * supervisor decided to retry the access request which violated the policy in
204962306a36Sopenharmony_ci * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
205062306a36Sopenharmony_ci */
205162306a36Sopenharmony_ciint tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
205262306a36Sopenharmony_ci{
205362306a36Sopenharmony_ci	va_list args;
205462306a36Sopenharmony_ci	int error;
205562306a36Sopenharmony_ci	int len;
205662306a36Sopenharmony_ci	static unsigned int tomoyo_serial;
205762306a36Sopenharmony_ci	struct tomoyo_query entry = { };
205862306a36Sopenharmony_ci	bool quota_exceeded = false;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	va_start(args, fmt);
206162306a36Sopenharmony_ci	len = vsnprintf(NULL, 0, fmt, args) + 1;
206262306a36Sopenharmony_ci	va_end(args);
206362306a36Sopenharmony_ci	/* Write /sys/kernel/security/tomoyo/audit. */
206462306a36Sopenharmony_ci	va_start(args, fmt);
206562306a36Sopenharmony_ci	tomoyo_write_log2(r, len, fmt, args);
206662306a36Sopenharmony_ci	va_end(args);
206762306a36Sopenharmony_ci	/* Nothing more to do if granted. */
206862306a36Sopenharmony_ci	if (r->granted)
206962306a36Sopenharmony_ci		return 0;
207062306a36Sopenharmony_ci	if (r->mode)
207162306a36Sopenharmony_ci		tomoyo_update_stat(r->mode);
207262306a36Sopenharmony_ci	switch (r->mode) {
207362306a36Sopenharmony_ci	case TOMOYO_CONFIG_ENFORCING:
207462306a36Sopenharmony_ci		error = -EPERM;
207562306a36Sopenharmony_ci		if (atomic_read(&tomoyo_query_observers))
207662306a36Sopenharmony_ci			break;
207762306a36Sopenharmony_ci		goto out;
207862306a36Sopenharmony_ci	case TOMOYO_CONFIG_LEARNING:
207962306a36Sopenharmony_ci		error = 0;
208062306a36Sopenharmony_ci		/* Check max_learning_entry parameter. */
208162306a36Sopenharmony_ci		if (tomoyo_domain_quota_is_ok(r))
208262306a36Sopenharmony_ci			break;
208362306a36Sopenharmony_ci		fallthrough;
208462306a36Sopenharmony_ci	default:
208562306a36Sopenharmony_ci		return 0;
208662306a36Sopenharmony_ci	}
208762306a36Sopenharmony_ci	/* Get message. */
208862306a36Sopenharmony_ci	va_start(args, fmt);
208962306a36Sopenharmony_ci	entry.query = tomoyo_init_log(r, len, fmt, args);
209062306a36Sopenharmony_ci	va_end(args);
209162306a36Sopenharmony_ci	if (!entry.query)
209262306a36Sopenharmony_ci		goto out;
209362306a36Sopenharmony_ci	entry.query_len = strlen(entry.query) + 1;
209462306a36Sopenharmony_ci	if (!error) {
209562306a36Sopenharmony_ci		tomoyo_add_entry(r->domain, entry.query);
209662306a36Sopenharmony_ci		goto out;
209762306a36Sopenharmony_ci	}
209862306a36Sopenharmony_ci	len = kmalloc_size_roundup(entry.query_len);
209962306a36Sopenharmony_ci	entry.domain = r->domain;
210062306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
210162306a36Sopenharmony_ci	if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] &&
210262306a36Sopenharmony_ci	    tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len
210362306a36Sopenharmony_ci	    >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) {
210462306a36Sopenharmony_ci		quota_exceeded = true;
210562306a36Sopenharmony_ci	} else {
210662306a36Sopenharmony_ci		entry.serial = tomoyo_serial++;
210762306a36Sopenharmony_ci		entry.retry = r->retry;
210862306a36Sopenharmony_ci		tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len;
210962306a36Sopenharmony_ci		list_add_tail(&entry.list, &tomoyo_query_list);
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
211262306a36Sopenharmony_ci	if (quota_exceeded)
211362306a36Sopenharmony_ci		goto out;
211462306a36Sopenharmony_ci	/* Give 10 seconds for supervisor's opinion. */
211562306a36Sopenharmony_ci	while (entry.timer < 10) {
211662306a36Sopenharmony_ci		wake_up_all(&tomoyo_query_wait);
211762306a36Sopenharmony_ci		if (wait_event_interruptible_timeout
211862306a36Sopenharmony_ci		    (tomoyo_answer_wait, entry.answer ||
211962306a36Sopenharmony_ci		     !atomic_read(&tomoyo_query_observers), HZ))
212062306a36Sopenharmony_ci			break;
212162306a36Sopenharmony_ci		entry.timer++;
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
212462306a36Sopenharmony_ci	list_del(&entry.list);
212562306a36Sopenharmony_ci	tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len;
212662306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
212762306a36Sopenharmony_ci	switch (entry.answer) {
212862306a36Sopenharmony_ci	case 3: /* Asked to retry by administrator. */
212962306a36Sopenharmony_ci		error = TOMOYO_RETRY_REQUEST;
213062306a36Sopenharmony_ci		r->retry++;
213162306a36Sopenharmony_ci		break;
213262306a36Sopenharmony_ci	case 1:
213362306a36Sopenharmony_ci		/* Granted by administrator. */
213462306a36Sopenharmony_ci		error = 0;
213562306a36Sopenharmony_ci		break;
213662306a36Sopenharmony_ci	default:
213762306a36Sopenharmony_ci		/* Timed out or rejected by administrator. */
213862306a36Sopenharmony_ci		break;
213962306a36Sopenharmony_ci	}
214062306a36Sopenharmony_ciout:
214162306a36Sopenharmony_ci	kfree(entry.query);
214262306a36Sopenharmony_ci	return error;
214362306a36Sopenharmony_ci}
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci/**
214662306a36Sopenharmony_ci * tomoyo_find_domain_by_qid - Get domain by query id.
214762306a36Sopenharmony_ci *
214862306a36Sopenharmony_ci * @serial: Query ID assigned by tomoyo_supervisor().
214962306a36Sopenharmony_ci *
215062306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
215162306a36Sopenharmony_ci */
215262306a36Sopenharmony_cistatic struct tomoyo_domain_info *tomoyo_find_domain_by_qid
215362306a36Sopenharmony_ci(unsigned int serial)
215462306a36Sopenharmony_ci{
215562306a36Sopenharmony_ci	struct tomoyo_query *ptr;
215662306a36Sopenharmony_ci	struct tomoyo_domain_info *domain = NULL;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
215962306a36Sopenharmony_ci	list_for_each_entry(ptr, &tomoyo_query_list, list) {
216062306a36Sopenharmony_ci		if (ptr->serial != serial)
216162306a36Sopenharmony_ci			continue;
216262306a36Sopenharmony_ci		domain = ptr->domain;
216362306a36Sopenharmony_ci		break;
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
216662306a36Sopenharmony_ci	return domain;
216762306a36Sopenharmony_ci}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci/**
217062306a36Sopenharmony_ci * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
217162306a36Sopenharmony_ci *
217262306a36Sopenharmony_ci * @file: Pointer to "struct file".
217362306a36Sopenharmony_ci * @wait: Pointer to "poll_table".
217462306a36Sopenharmony_ci *
217562306a36Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM when ready to read, 0 otherwise.
217662306a36Sopenharmony_ci *
217762306a36Sopenharmony_ci * Waits for access requests which violated policy in enforcing mode.
217862306a36Sopenharmony_ci */
217962306a36Sopenharmony_cistatic __poll_t tomoyo_poll_query(struct file *file, poll_table *wait)
218062306a36Sopenharmony_ci{
218162306a36Sopenharmony_ci	if (!list_empty(&tomoyo_query_list))
218262306a36Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
218362306a36Sopenharmony_ci	poll_wait(file, &tomoyo_query_wait, wait);
218462306a36Sopenharmony_ci	if (!list_empty(&tomoyo_query_list))
218562306a36Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
218662306a36Sopenharmony_ci	return 0;
218762306a36Sopenharmony_ci}
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci/**
219062306a36Sopenharmony_ci * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
219162306a36Sopenharmony_ci *
219262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
219362306a36Sopenharmony_ci */
219462306a36Sopenharmony_cistatic void tomoyo_read_query(struct tomoyo_io_buffer *head)
219562306a36Sopenharmony_ci{
219662306a36Sopenharmony_ci	struct list_head *tmp;
219762306a36Sopenharmony_ci	unsigned int pos = 0;
219862306a36Sopenharmony_ci	size_t len = 0;
219962306a36Sopenharmony_ci	char *buf;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	if (head->r.w_pos)
220262306a36Sopenharmony_ci		return;
220362306a36Sopenharmony_ci	kfree(head->read_buf);
220462306a36Sopenharmony_ci	head->read_buf = NULL;
220562306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
220662306a36Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
220762306a36Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci		if (pos++ != head->r.query_index)
221062306a36Sopenharmony_ci			continue;
221162306a36Sopenharmony_ci		len = ptr->query_len;
221262306a36Sopenharmony_ci		break;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
221562306a36Sopenharmony_ci	if (!len) {
221662306a36Sopenharmony_ci		head->r.query_index = 0;
221762306a36Sopenharmony_ci		return;
221862306a36Sopenharmony_ci	}
221962306a36Sopenharmony_ci	buf = kzalloc(len + 32, GFP_NOFS);
222062306a36Sopenharmony_ci	if (!buf)
222162306a36Sopenharmony_ci		return;
222262306a36Sopenharmony_ci	pos = 0;
222362306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
222462306a36Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
222562306a36Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci		if (pos++ != head->r.query_index)
222862306a36Sopenharmony_ci			continue;
222962306a36Sopenharmony_ci		/*
223062306a36Sopenharmony_ci		 * Some query can be skipped because tomoyo_query_list
223162306a36Sopenharmony_ci		 * can change, but I don't care.
223262306a36Sopenharmony_ci		 */
223362306a36Sopenharmony_ci		if (len == ptr->query_len)
223462306a36Sopenharmony_ci			snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
223562306a36Sopenharmony_ci				 ptr->retry, ptr->query);
223662306a36Sopenharmony_ci		break;
223762306a36Sopenharmony_ci	}
223862306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
223962306a36Sopenharmony_ci	if (buf[0]) {
224062306a36Sopenharmony_ci		head->read_buf = buf;
224162306a36Sopenharmony_ci		head->r.w[head->r.w_pos++] = buf;
224262306a36Sopenharmony_ci		head->r.query_index++;
224362306a36Sopenharmony_ci	} else {
224462306a36Sopenharmony_ci		kfree(buf);
224562306a36Sopenharmony_ci	}
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci/**
224962306a36Sopenharmony_ci * tomoyo_write_answer - Write the supervisor's decision.
225062306a36Sopenharmony_ci *
225162306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
225262306a36Sopenharmony_ci *
225362306a36Sopenharmony_ci * Returns 0 on success, -EINVAL otherwise.
225462306a36Sopenharmony_ci */
225562306a36Sopenharmony_cistatic int tomoyo_write_answer(struct tomoyo_io_buffer *head)
225662306a36Sopenharmony_ci{
225762306a36Sopenharmony_ci	char *data = head->write_buf;
225862306a36Sopenharmony_ci	struct list_head *tmp;
225962306a36Sopenharmony_ci	unsigned int serial;
226062306a36Sopenharmony_ci	unsigned int answer;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
226362306a36Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
226462306a36Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci		ptr->timer = 0;
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
226962306a36Sopenharmony_ci	if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
227062306a36Sopenharmony_ci		return -EINVAL;
227162306a36Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
227262306a36Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
227362306a36Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		if (ptr->serial != serial)
227662306a36Sopenharmony_ci			continue;
227762306a36Sopenharmony_ci		ptr->answer = answer;
227862306a36Sopenharmony_ci		/* Remove from tomoyo_query_list. */
227962306a36Sopenharmony_ci		if (ptr->answer)
228062306a36Sopenharmony_ci			list_del_init(&ptr->list);
228162306a36Sopenharmony_ci		break;
228262306a36Sopenharmony_ci	}
228362306a36Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
228462306a36Sopenharmony_ci	return 0;
228562306a36Sopenharmony_ci}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci/**
228862306a36Sopenharmony_ci * tomoyo_read_version: Get version.
228962306a36Sopenharmony_ci *
229062306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
229162306a36Sopenharmony_ci *
229262306a36Sopenharmony_ci * Returns version information.
229362306a36Sopenharmony_ci */
229462306a36Sopenharmony_cistatic void tomoyo_read_version(struct tomoyo_io_buffer *head)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	if (!head->r.eof) {
229762306a36Sopenharmony_ci		tomoyo_io_printf(head, "2.6.0");
229862306a36Sopenharmony_ci		head->r.eof = true;
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci/* String table for /sys/kernel/security/tomoyo/stat interface. */
230362306a36Sopenharmony_cistatic const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = {
230462306a36Sopenharmony_ci	[TOMOYO_STAT_POLICY_UPDATES]    = "update:",
230562306a36Sopenharmony_ci	[TOMOYO_STAT_POLICY_LEARNING]   = "violation in learning mode:",
230662306a36Sopenharmony_ci	[TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
230762306a36Sopenharmony_ci	[TOMOYO_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
230862306a36Sopenharmony_ci};
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci/* String table for /sys/kernel/security/tomoyo/stat interface. */
231162306a36Sopenharmony_cistatic const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
231262306a36Sopenharmony_ci	[TOMOYO_MEMORY_POLICY] = "policy:",
231362306a36Sopenharmony_ci	[TOMOYO_MEMORY_AUDIT]  = "audit log:",
231462306a36Sopenharmony_ci	[TOMOYO_MEMORY_QUERY]  = "query message:",
231562306a36Sopenharmony_ci};
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci/* Counter for number of updates. */
231862306a36Sopenharmony_cistatic atomic_t tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
231962306a36Sopenharmony_ci/* Timestamp counter for last updated. */
232062306a36Sopenharmony_cistatic time64_t tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci/**
232362306a36Sopenharmony_ci * tomoyo_update_stat - Update statistic counters.
232462306a36Sopenharmony_ci *
232562306a36Sopenharmony_ci * @index: Index for policy type.
232662306a36Sopenharmony_ci *
232762306a36Sopenharmony_ci * Returns nothing.
232862306a36Sopenharmony_ci */
232962306a36Sopenharmony_civoid tomoyo_update_stat(const u8 index)
233062306a36Sopenharmony_ci{
233162306a36Sopenharmony_ci	atomic_inc(&tomoyo_stat_updated[index]);
233262306a36Sopenharmony_ci	tomoyo_stat_modified[index] = ktime_get_real_seconds();
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci/**
233662306a36Sopenharmony_ci * tomoyo_read_stat - Read statistic data.
233762306a36Sopenharmony_ci *
233862306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
233962306a36Sopenharmony_ci *
234062306a36Sopenharmony_ci * Returns nothing.
234162306a36Sopenharmony_ci */
234262306a36Sopenharmony_cistatic void tomoyo_read_stat(struct tomoyo_io_buffer *head)
234362306a36Sopenharmony_ci{
234462306a36Sopenharmony_ci	u8 i;
234562306a36Sopenharmony_ci	unsigned int total = 0;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	if (head->r.eof)
234862306a36Sopenharmony_ci		return;
234962306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) {
235062306a36Sopenharmony_ci		tomoyo_io_printf(head, "Policy %-30s %10u",
235162306a36Sopenharmony_ci				 tomoyo_policy_headers[i],
235262306a36Sopenharmony_ci				 atomic_read(&tomoyo_stat_updated[i]));
235362306a36Sopenharmony_ci		if (tomoyo_stat_modified[i]) {
235462306a36Sopenharmony_ci			struct tomoyo_time stamp;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci			tomoyo_convert_time(tomoyo_stat_modified[i], &stamp);
235762306a36Sopenharmony_ci			tomoyo_io_printf(head, " (Last: %04u/%02u/%02u %02u:%02u:%02u)",
235862306a36Sopenharmony_ci					 stamp.year, stamp.month, stamp.day,
235962306a36Sopenharmony_ci					 stamp.hour, stamp.min, stamp.sec);
236062306a36Sopenharmony_ci		}
236162306a36Sopenharmony_ci		tomoyo_set_lf(head);
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) {
236462306a36Sopenharmony_ci		unsigned int used = tomoyo_memory_used[i];
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci		total += used;
236762306a36Sopenharmony_ci		tomoyo_io_printf(head, "Memory used by %-22s %10u",
236862306a36Sopenharmony_ci				 tomoyo_memory_headers[i], used);
236962306a36Sopenharmony_ci		used = tomoyo_memory_quota[i];
237062306a36Sopenharmony_ci		if (used)
237162306a36Sopenharmony_ci			tomoyo_io_printf(head, " (Quota: %10u)", used);
237262306a36Sopenharmony_ci		tomoyo_set_lf(head);
237362306a36Sopenharmony_ci	}
237462306a36Sopenharmony_ci	tomoyo_io_printf(head, "Total memory used:                    %10u\n",
237562306a36Sopenharmony_ci			 total);
237662306a36Sopenharmony_ci	head->r.eof = true;
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci/**
238062306a36Sopenharmony_ci * tomoyo_write_stat - Set memory quota.
238162306a36Sopenharmony_ci *
238262306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
238362306a36Sopenharmony_ci *
238462306a36Sopenharmony_ci * Returns 0.
238562306a36Sopenharmony_ci */
238662306a36Sopenharmony_cistatic int tomoyo_write_stat(struct tomoyo_io_buffer *head)
238762306a36Sopenharmony_ci{
238862306a36Sopenharmony_ci	char *data = head->write_buf;
238962306a36Sopenharmony_ci	u8 i;
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (tomoyo_str_starts(&data, "Memory used by "))
239262306a36Sopenharmony_ci		for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++)
239362306a36Sopenharmony_ci			if (tomoyo_str_starts(&data, tomoyo_memory_headers[i]))
239462306a36Sopenharmony_ci				sscanf(data, "%u", &tomoyo_memory_quota[i]);
239562306a36Sopenharmony_ci	return 0;
239662306a36Sopenharmony_ci}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci/**
239962306a36Sopenharmony_ci * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
240062306a36Sopenharmony_ci *
240162306a36Sopenharmony_ci * @type: Type of interface.
240262306a36Sopenharmony_ci * @file: Pointer to "struct file".
240362306a36Sopenharmony_ci *
240462306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
240562306a36Sopenharmony_ci */
240662306a36Sopenharmony_ciint tomoyo_open_control(const u8 type, struct file *file)
240762306a36Sopenharmony_ci{
240862306a36Sopenharmony_ci	struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	if (!head)
241162306a36Sopenharmony_ci		return -ENOMEM;
241262306a36Sopenharmony_ci	mutex_init(&head->io_sem);
241362306a36Sopenharmony_ci	head->type = type;
241462306a36Sopenharmony_ci	switch (type) {
241562306a36Sopenharmony_ci	case TOMOYO_DOMAINPOLICY:
241662306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/domain_policy */
241762306a36Sopenharmony_ci		head->write = tomoyo_write_domain;
241862306a36Sopenharmony_ci		head->read = tomoyo_read_domain;
241962306a36Sopenharmony_ci		break;
242062306a36Sopenharmony_ci	case TOMOYO_EXCEPTIONPOLICY:
242162306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/exception_policy */
242262306a36Sopenharmony_ci		head->write = tomoyo_write_exception;
242362306a36Sopenharmony_ci		head->read = tomoyo_read_exception;
242462306a36Sopenharmony_ci		break;
242562306a36Sopenharmony_ci	case TOMOYO_AUDIT:
242662306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/audit */
242762306a36Sopenharmony_ci		head->poll = tomoyo_poll_log;
242862306a36Sopenharmony_ci		head->read = tomoyo_read_log;
242962306a36Sopenharmony_ci		break;
243062306a36Sopenharmony_ci	case TOMOYO_PROCESS_STATUS:
243162306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/.process_status */
243262306a36Sopenharmony_ci		head->write = tomoyo_write_pid;
243362306a36Sopenharmony_ci		head->read = tomoyo_read_pid;
243462306a36Sopenharmony_ci		break;
243562306a36Sopenharmony_ci	case TOMOYO_VERSION:
243662306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/version */
243762306a36Sopenharmony_ci		head->read = tomoyo_read_version;
243862306a36Sopenharmony_ci		head->readbuf_size = 128;
243962306a36Sopenharmony_ci		break;
244062306a36Sopenharmony_ci	case TOMOYO_STAT:
244162306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/stat */
244262306a36Sopenharmony_ci		head->write = tomoyo_write_stat;
244362306a36Sopenharmony_ci		head->read = tomoyo_read_stat;
244462306a36Sopenharmony_ci		head->readbuf_size = 1024;
244562306a36Sopenharmony_ci		break;
244662306a36Sopenharmony_ci	case TOMOYO_PROFILE:
244762306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/profile */
244862306a36Sopenharmony_ci		head->write = tomoyo_write_profile;
244962306a36Sopenharmony_ci		head->read = tomoyo_read_profile;
245062306a36Sopenharmony_ci		break;
245162306a36Sopenharmony_ci	case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
245262306a36Sopenharmony_ci		head->poll = tomoyo_poll_query;
245362306a36Sopenharmony_ci		head->write = tomoyo_write_answer;
245462306a36Sopenharmony_ci		head->read = tomoyo_read_query;
245562306a36Sopenharmony_ci		break;
245662306a36Sopenharmony_ci	case TOMOYO_MANAGER:
245762306a36Sopenharmony_ci		/* /sys/kernel/security/tomoyo/manager */
245862306a36Sopenharmony_ci		head->write = tomoyo_write_manager;
245962306a36Sopenharmony_ci		head->read = tomoyo_read_manager;
246062306a36Sopenharmony_ci		break;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_READ)) {
246362306a36Sopenharmony_ci		/*
246462306a36Sopenharmony_ci		 * No need to allocate read_buf since it is not opened
246562306a36Sopenharmony_ci		 * for reading.
246662306a36Sopenharmony_ci		 */
246762306a36Sopenharmony_ci		head->read = NULL;
246862306a36Sopenharmony_ci		head->poll = NULL;
246962306a36Sopenharmony_ci	} else if (!head->poll) {
247062306a36Sopenharmony_ci		/* Don't allocate read_buf for poll() access. */
247162306a36Sopenharmony_ci		if (!head->readbuf_size)
247262306a36Sopenharmony_ci			head->readbuf_size = 4096 * 2;
247362306a36Sopenharmony_ci		head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
247462306a36Sopenharmony_ci		if (!head->read_buf) {
247562306a36Sopenharmony_ci			kfree(head);
247662306a36Sopenharmony_ci			return -ENOMEM;
247762306a36Sopenharmony_ci		}
247862306a36Sopenharmony_ci	}
247962306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE)) {
248062306a36Sopenharmony_ci		/*
248162306a36Sopenharmony_ci		 * No need to allocate write_buf since it is not opened
248262306a36Sopenharmony_ci		 * for writing.
248362306a36Sopenharmony_ci		 */
248462306a36Sopenharmony_ci		head->write = NULL;
248562306a36Sopenharmony_ci	} else if (head->write) {
248662306a36Sopenharmony_ci		head->writebuf_size = 4096 * 2;
248762306a36Sopenharmony_ci		head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS);
248862306a36Sopenharmony_ci		if (!head->write_buf) {
248962306a36Sopenharmony_ci			kfree(head->read_buf);
249062306a36Sopenharmony_ci			kfree(head);
249162306a36Sopenharmony_ci			return -ENOMEM;
249262306a36Sopenharmony_ci		}
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci	/*
249562306a36Sopenharmony_ci	 * If the file is /sys/kernel/security/tomoyo/query , increment the
249662306a36Sopenharmony_ci	 * observer counter.
249762306a36Sopenharmony_ci	 * The obserber counter is used by tomoyo_supervisor() to see if
249862306a36Sopenharmony_ci	 * there is some process monitoring /sys/kernel/security/tomoyo/query.
249962306a36Sopenharmony_ci	 */
250062306a36Sopenharmony_ci	if (type == TOMOYO_QUERY)
250162306a36Sopenharmony_ci		atomic_inc(&tomoyo_query_observers);
250262306a36Sopenharmony_ci	file->private_data = head;
250362306a36Sopenharmony_ci	tomoyo_notify_gc(head, true);
250462306a36Sopenharmony_ci	return 0;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci/**
250862306a36Sopenharmony_ci * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
250962306a36Sopenharmony_ci *
251062306a36Sopenharmony_ci * @file: Pointer to "struct file".
251162306a36Sopenharmony_ci * @wait: Pointer to "poll_table". Maybe NULL.
251262306a36Sopenharmony_ci *
251362306a36Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write,
251462306a36Sopenharmony_ci * EPOLLOUT | EPOLLWRNORM otherwise.
251562306a36Sopenharmony_ci */
251662306a36Sopenharmony_ci__poll_t tomoyo_poll_control(struct file *file, poll_table *wait)
251762306a36Sopenharmony_ci{
251862306a36Sopenharmony_ci	struct tomoyo_io_buffer *head = file->private_data;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	if (head->poll)
252162306a36Sopenharmony_ci		return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM;
252262306a36Sopenharmony_ci	return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
252362306a36Sopenharmony_ci}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci/**
252662306a36Sopenharmony_ci * tomoyo_set_namespace_cursor - Set namespace to read.
252762306a36Sopenharmony_ci *
252862306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
252962306a36Sopenharmony_ci *
253062306a36Sopenharmony_ci * Returns nothing.
253162306a36Sopenharmony_ci */
253262306a36Sopenharmony_cistatic inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
253362306a36Sopenharmony_ci{
253462306a36Sopenharmony_ci	struct list_head *ns;
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	if (head->type != TOMOYO_EXCEPTIONPOLICY &&
253762306a36Sopenharmony_ci	    head->type != TOMOYO_PROFILE)
253862306a36Sopenharmony_ci		return;
253962306a36Sopenharmony_ci	/*
254062306a36Sopenharmony_ci	 * If this is the first read, or reading previous namespace finished
254162306a36Sopenharmony_ci	 * and has more namespaces to read, update the namespace cursor.
254262306a36Sopenharmony_ci	 */
254362306a36Sopenharmony_ci	ns = head->r.ns;
254462306a36Sopenharmony_ci	if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) {
254562306a36Sopenharmony_ci		/* Clearing is OK because tomoyo_flush() returned true. */
254662306a36Sopenharmony_ci		memset(&head->r, 0, sizeof(head->r));
254762306a36Sopenharmony_ci		head->r.ns = ns ? ns->next : tomoyo_namespace_list.next;
254862306a36Sopenharmony_ci	}
254962306a36Sopenharmony_ci}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci/**
255262306a36Sopenharmony_ci * tomoyo_has_more_namespace - Check for unread namespaces.
255362306a36Sopenharmony_ci *
255462306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
255562306a36Sopenharmony_ci *
255662306a36Sopenharmony_ci * Returns true if we have more entries to print, false otherwise.
255762306a36Sopenharmony_ci */
255862306a36Sopenharmony_cistatic inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head)
255962306a36Sopenharmony_ci{
256062306a36Sopenharmony_ci	return (head->type == TOMOYO_EXCEPTIONPOLICY ||
256162306a36Sopenharmony_ci		head->type == TOMOYO_PROFILE) && head->r.eof &&
256262306a36Sopenharmony_ci		head->r.ns->next != &tomoyo_namespace_list;
256362306a36Sopenharmony_ci}
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci/**
256662306a36Sopenharmony_ci * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
256762306a36Sopenharmony_ci *
256862306a36Sopenharmony_ci * @head:       Pointer to "struct tomoyo_io_buffer".
256962306a36Sopenharmony_ci * @buffer:     Pointer to buffer to write to.
257062306a36Sopenharmony_ci * @buffer_len: Size of @buffer.
257162306a36Sopenharmony_ci *
257262306a36Sopenharmony_ci * Returns bytes read on success, negative value otherwise.
257362306a36Sopenharmony_ci */
257462306a36Sopenharmony_cissize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
257562306a36Sopenharmony_ci			    const int buffer_len)
257662306a36Sopenharmony_ci{
257762306a36Sopenharmony_ci	int len;
257862306a36Sopenharmony_ci	int idx;
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	if (!head->read)
258162306a36Sopenharmony_ci		return -EINVAL;
258262306a36Sopenharmony_ci	if (mutex_lock_interruptible(&head->io_sem))
258362306a36Sopenharmony_ci		return -EINTR;
258462306a36Sopenharmony_ci	head->read_user_buf = buffer;
258562306a36Sopenharmony_ci	head->read_user_buf_avail = buffer_len;
258662306a36Sopenharmony_ci	idx = tomoyo_read_lock();
258762306a36Sopenharmony_ci	if (tomoyo_flush(head))
258862306a36Sopenharmony_ci		/* Call the policy handler. */
258962306a36Sopenharmony_ci		do {
259062306a36Sopenharmony_ci			tomoyo_set_namespace_cursor(head);
259162306a36Sopenharmony_ci			head->read(head);
259262306a36Sopenharmony_ci		} while (tomoyo_flush(head) &&
259362306a36Sopenharmony_ci			 tomoyo_has_more_namespace(head));
259462306a36Sopenharmony_ci	tomoyo_read_unlock(idx);
259562306a36Sopenharmony_ci	len = head->read_user_buf - buffer;
259662306a36Sopenharmony_ci	mutex_unlock(&head->io_sem);
259762306a36Sopenharmony_ci	return len;
259862306a36Sopenharmony_ci}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci/**
260162306a36Sopenharmony_ci * tomoyo_parse_policy - Parse a policy line.
260262306a36Sopenharmony_ci *
260362306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
260462306a36Sopenharmony_ci * @line: Line to parse.
260562306a36Sopenharmony_ci *
260662306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise.
260762306a36Sopenharmony_ci *
260862306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
260962306a36Sopenharmony_ci */
261062306a36Sopenharmony_cistatic int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
261162306a36Sopenharmony_ci{
261262306a36Sopenharmony_ci	/* Delete request? */
261362306a36Sopenharmony_ci	head->w.is_delete = !strncmp(line, "delete ", 7);
261462306a36Sopenharmony_ci	if (head->w.is_delete)
261562306a36Sopenharmony_ci		memmove(line, line + 7, strlen(line + 7) + 1);
261662306a36Sopenharmony_ci	/* Selecting namespace to update. */
261762306a36Sopenharmony_ci	if (head->type == TOMOYO_EXCEPTIONPOLICY ||
261862306a36Sopenharmony_ci	    head->type == TOMOYO_PROFILE) {
261962306a36Sopenharmony_ci		if (*line == '<') {
262062306a36Sopenharmony_ci			char *cp = strchr(line, ' ');
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci			if (cp) {
262362306a36Sopenharmony_ci				*cp++ = '\0';
262462306a36Sopenharmony_ci				head->w.ns = tomoyo_assign_namespace(line);
262562306a36Sopenharmony_ci				memmove(line, cp, strlen(cp) + 1);
262662306a36Sopenharmony_ci			} else
262762306a36Sopenharmony_ci				head->w.ns = NULL;
262862306a36Sopenharmony_ci		} else
262962306a36Sopenharmony_ci			head->w.ns = &tomoyo_kernel_namespace;
263062306a36Sopenharmony_ci		/* Don't allow updating if namespace is invalid. */
263162306a36Sopenharmony_ci		if (!head->w.ns)
263262306a36Sopenharmony_ci			return -ENOENT;
263362306a36Sopenharmony_ci	}
263462306a36Sopenharmony_ci	/* Do the update. */
263562306a36Sopenharmony_ci	return head->write(head);
263662306a36Sopenharmony_ci}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci/**
263962306a36Sopenharmony_ci * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
264062306a36Sopenharmony_ci *
264162306a36Sopenharmony_ci * @head:       Pointer to "struct tomoyo_io_buffer".
264262306a36Sopenharmony_ci * @buffer:     Pointer to buffer to read from.
264362306a36Sopenharmony_ci * @buffer_len: Size of @buffer.
264462306a36Sopenharmony_ci *
264562306a36Sopenharmony_ci * Returns @buffer_len on success, negative value otherwise.
264662306a36Sopenharmony_ci */
264762306a36Sopenharmony_cissize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
264862306a36Sopenharmony_ci			     const char __user *buffer, const int buffer_len)
264962306a36Sopenharmony_ci{
265062306a36Sopenharmony_ci	int error = buffer_len;
265162306a36Sopenharmony_ci	size_t avail_len = buffer_len;
265262306a36Sopenharmony_ci	char *cp0;
265362306a36Sopenharmony_ci	int idx;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	if (!head->write)
265662306a36Sopenharmony_ci		return -EINVAL;
265762306a36Sopenharmony_ci	if (mutex_lock_interruptible(&head->io_sem))
265862306a36Sopenharmony_ci		return -EINTR;
265962306a36Sopenharmony_ci	cp0 = head->write_buf;
266062306a36Sopenharmony_ci	head->read_user_buf_avail = 0;
266162306a36Sopenharmony_ci	idx = tomoyo_read_lock();
266262306a36Sopenharmony_ci	/* Read a line and dispatch it to the policy handler. */
266362306a36Sopenharmony_ci	while (avail_len > 0) {
266462306a36Sopenharmony_ci		char c;
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci		if (head->w.avail >= head->writebuf_size - 1) {
266762306a36Sopenharmony_ci			const int len = head->writebuf_size * 2;
266862306a36Sopenharmony_ci			char *cp = kzalloc(len, GFP_NOFS);
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci			if (!cp) {
267162306a36Sopenharmony_ci				error = -ENOMEM;
267262306a36Sopenharmony_ci				break;
267362306a36Sopenharmony_ci			}
267462306a36Sopenharmony_ci			memmove(cp, cp0, head->w.avail);
267562306a36Sopenharmony_ci			kfree(cp0);
267662306a36Sopenharmony_ci			head->write_buf = cp;
267762306a36Sopenharmony_ci			cp0 = cp;
267862306a36Sopenharmony_ci			head->writebuf_size = len;
267962306a36Sopenharmony_ci		}
268062306a36Sopenharmony_ci		if (get_user(c, buffer)) {
268162306a36Sopenharmony_ci			error = -EFAULT;
268262306a36Sopenharmony_ci			break;
268362306a36Sopenharmony_ci		}
268462306a36Sopenharmony_ci		buffer++;
268562306a36Sopenharmony_ci		avail_len--;
268662306a36Sopenharmony_ci		cp0[head->w.avail++] = c;
268762306a36Sopenharmony_ci		if (c != '\n')
268862306a36Sopenharmony_ci			continue;
268962306a36Sopenharmony_ci		cp0[head->w.avail - 1] = '\0';
269062306a36Sopenharmony_ci		head->w.avail = 0;
269162306a36Sopenharmony_ci		tomoyo_normalize_line(cp0);
269262306a36Sopenharmony_ci		if (!strcmp(cp0, "reset")) {
269362306a36Sopenharmony_ci			head->w.ns = &tomoyo_kernel_namespace;
269462306a36Sopenharmony_ci			head->w.domain = NULL;
269562306a36Sopenharmony_ci			memset(&head->r, 0, sizeof(head->r));
269662306a36Sopenharmony_ci			continue;
269762306a36Sopenharmony_ci		}
269862306a36Sopenharmony_ci		/* Don't allow updating policies by non manager programs. */
269962306a36Sopenharmony_ci		switch (head->type) {
270062306a36Sopenharmony_ci		case TOMOYO_PROCESS_STATUS:
270162306a36Sopenharmony_ci			/* This does not write anything. */
270262306a36Sopenharmony_ci			break;
270362306a36Sopenharmony_ci		case TOMOYO_DOMAINPOLICY:
270462306a36Sopenharmony_ci			if (tomoyo_select_domain(head, cp0))
270562306a36Sopenharmony_ci				continue;
270662306a36Sopenharmony_ci			fallthrough;
270762306a36Sopenharmony_ci		case TOMOYO_EXCEPTIONPOLICY:
270862306a36Sopenharmony_ci			if (!strcmp(cp0, "select transition_only")) {
270962306a36Sopenharmony_ci				head->r.print_transition_related_only = true;
271062306a36Sopenharmony_ci				continue;
271162306a36Sopenharmony_ci			}
271262306a36Sopenharmony_ci			fallthrough;
271362306a36Sopenharmony_ci		default:
271462306a36Sopenharmony_ci			if (!tomoyo_manager()) {
271562306a36Sopenharmony_ci				error = -EPERM;
271662306a36Sopenharmony_ci				goto out;
271762306a36Sopenharmony_ci			}
271862306a36Sopenharmony_ci		}
271962306a36Sopenharmony_ci		switch (tomoyo_parse_policy(head, cp0)) {
272062306a36Sopenharmony_ci		case -EPERM:
272162306a36Sopenharmony_ci			error = -EPERM;
272262306a36Sopenharmony_ci			goto out;
272362306a36Sopenharmony_ci		case 0:
272462306a36Sopenharmony_ci			switch (head->type) {
272562306a36Sopenharmony_ci			case TOMOYO_DOMAINPOLICY:
272662306a36Sopenharmony_ci			case TOMOYO_EXCEPTIONPOLICY:
272762306a36Sopenharmony_ci			case TOMOYO_STAT:
272862306a36Sopenharmony_ci			case TOMOYO_PROFILE:
272962306a36Sopenharmony_ci			case TOMOYO_MANAGER:
273062306a36Sopenharmony_ci				tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
273162306a36Sopenharmony_ci				break;
273262306a36Sopenharmony_ci			default:
273362306a36Sopenharmony_ci				break;
273462306a36Sopenharmony_ci			}
273562306a36Sopenharmony_ci			break;
273662306a36Sopenharmony_ci		}
273762306a36Sopenharmony_ci	}
273862306a36Sopenharmony_ciout:
273962306a36Sopenharmony_ci	tomoyo_read_unlock(idx);
274062306a36Sopenharmony_ci	mutex_unlock(&head->io_sem);
274162306a36Sopenharmony_ci	return error;
274262306a36Sopenharmony_ci}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci/**
274562306a36Sopenharmony_ci * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
274662306a36Sopenharmony_ci *
274762306a36Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
274862306a36Sopenharmony_ci */
274962306a36Sopenharmony_civoid tomoyo_close_control(struct tomoyo_io_buffer *head)
275062306a36Sopenharmony_ci{
275162306a36Sopenharmony_ci	/*
275262306a36Sopenharmony_ci	 * If the file is /sys/kernel/security/tomoyo/query , decrement the
275362306a36Sopenharmony_ci	 * observer counter.
275462306a36Sopenharmony_ci	 */
275562306a36Sopenharmony_ci	if (head->type == TOMOYO_QUERY &&
275662306a36Sopenharmony_ci	    atomic_dec_and_test(&tomoyo_query_observers))
275762306a36Sopenharmony_ci		wake_up_all(&tomoyo_answer_wait);
275862306a36Sopenharmony_ci	tomoyo_notify_gc(head, false);
275962306a36Sopenharmony_ci}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci/**
276262306a36Sopenharmony_ci * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
276362306a36Sopenharmony_ci */
276462306a36Sopenharmony_civoid tomoyo_check_profile(void)
276562306a36Sopenharmony_ci{
276662306a36Sopenharmony_ci	struct tomoyo_domain_info *domain;
276762306a36Sopenharmony_ci	const int idx = tomoyo_read_lock();
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	tomoyo_policy_loaded = true;
277062306a36Sopenharmony_ci	pr_info("TOMOYO: 2.6.0\n");
277162306a36Sopenharmony_ci	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
277262306a36Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
277362306a36Sopenharmony_ci		const u8 profile = domain->profile;
277462306a36Sopenharmony_ci		struct tomoyo_policy_namespace *ns = domain->ns;
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci		if (ns->profile_version == 20110903) {
277762306a36Sopenharmony_ci			pr_info_once("Converting profile version from %u to %u.\n",
277862306a36Sopenharmony_ci				     20110903, 20150505);
277962306a36Sopenharmony_ci			ns->profile_version = 20150505;
278062306a36Sopenharmony_ci		}
278162306a36Sopenharmony_ci		if (ns->profile_version != 20150505)
278262306a36Sopenharmony_ci			pr_err("Profile version %u is not supported.\n",
278362306a36Sopenharmony_ci			       ns->profile_version);
278462306a36Sopenharmony_ci		else if (!ns->profile_ptr[profile])
278562306a36Sopenharmony_ci			pr_err("Profile %u (used by '%s') is not defined.\n",
278662306a36Sopenharmony_ci			       profile, domain->domainname->name);
278762306a36Sopenharmony_ci		else
278862306a36Sopenharmony_ci			continue;
278962306a36Sopenharmony_ci		pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n");
279062306a36Sopenharmony_ci		pr_err("Please see https://tomoyo.osdn.jp/2.6/ for more information.\n");
279162306a36Sopenharmony_ci		panic("STOP!");
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci	tomoyo_read_unlock(idx);
279462306a36Sopenharmony_ci	pr_info("Mandatory Access Control activated.\n");
279562306a36Sopenharmony_ci}
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci/**
279862306a36Sopenharmony_ci * tomoyo_load_builtin_policy - Load built-in policy.
279962306a36Sopenharmony_ci *
280062306a36Sopenharmony_ci * Returns nothing.
280162306a36Sopenharmony_ci */
280262306a36Sopenharmony_civoid __init tomoyo_load_builtin_policy(void)
280362306a36Sopenharmony_ci{
280462306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
280562306a36Sopenharmony_ci	static char tomoyo_builtin_profile[] __initdata =
280662306a36Sopenharmony_ci		"PROFILE_VERSION=20150505\n"
280762306a36Sopenharmony_ci		"0-CONFIG={ mode=learning grant_log=no reject_log=yes }\n";
280862306a36Sopenharmony_ci	static char tomoyo_builtin_exception_policy[] __initdata =
280962306a36Sopenharmony_ci		"aggregator proc:/self/exe /proc/self/exe\n";
281062306a36Sopenharmony_ci	static char tomoyo_builtin_domain_policy[] __initdata = "";
281162306a36Sopenharmony_ci	static char tomoyo_builtin_manager[] __initdata = "";
281262306a36Sopenharmony_ci	static char tomoyo_builtin_stat[] __initdata = "";
281362306a36Sopenharmony_ci#else
281462306a36Sopenharmony_ci	/*
281562306a36Sopenharmony_ci	 * This include file is manually created and contains built-in policy
281662306a36Sopenharmony_ci	 * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy",
281762306a36Sopenharmony_ci	 * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager",
281862306a36Sopenharmony_ci	 * "tomoyo_builtin_stat" in the form of "static char [] __initdata".
281962306a36Sopenharmony_ci	 */
282062306a36Sopenharmony_ci#include "builtin-policy.h"
282162306a36Sopenharmony_ci#endif
282262306a36Sopenharmony_ci	u8 i;
282362306a36Sopenharmony_ci	const int idx = tomoyo_read_lock();
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
282662306a36Sopenharmony_ci		struct tomoyo_io_buffer head = { };
282762306a36Sopenharmony_ci		char *start = "";
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci		switch (i) {
283062306a36Sopenharmony_ci		case 0:
283162306a36Sopenharmony_ci			start = tomoyo_builtin_profile;
283262306a36Sopenharmony_ci			head.type = TOMOYO_PROFILE;
283362306a36Sopenharmony_ci			head.write = tomoyo_write_profile;
283462306a36Sopenharmony_ci			break;
283562306a36Sopenharmony_ci		case 1:
283662306a36Sopenharmony_ci			start = tomoyo_builtin_exception_policy;
283762306a36Sopenharmony_ci			head.type = TOMOYO_EXCEPTIONPOLICY;
283862306a36Sopenharmony_ci			head.write = tomoyo_write_exception;
283962306a36Sopenharmony_ci			break;
284062306a36Sopenharmony_ci		case 2:
284162306a36Sopenharmony_ci			start = tomoyo_builtin_domain_policy;
284262306a36Sopenharmony_ci			head.type = TOMOYO_DOMAINPOLICY;
284362306a36Sopenharmony_ci			head.write = tomoyo_write_domain;
284462306a36Sopenharmony_ci			break;
284562306a36Sopenharmony_ci		case 3:
284662306a36Sopenharmony_ci			start = tomoyo_builtin_manager;
284762306a36Sopenharmony_ci			head.type = TOMOYO_MANAGER;
284862306a36Sopenharmony_ci			head.write = tomoyo_write_manager;
284962306a36Sopenharmony_ci			break;
285062306a36Sopenharmony_ci		case 4:
285162306a36Sopenharmony_ci			start = tomoyo_builtin_stat;
285262306a36Sopenharmony_ci			head.type = TOMOYO_STAT;
285362306a36Sopenharmony_ci			head.write = tomoyo_write_stat;
285462306a36Sopenharmony_ci			break;
285562306a36Sopenharmony_ci		}
285662306a36Sopenharmony_ci		while (1) {
285762306a36Sopenharmony_ci			char *end = strchr(start, '\n');
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci			if (!end)
286062306a36Sopenharmony_ci				break;
286162306a36Sopenharmony_ci			*end = '\0';
286262306a36Sopenharmony_ci			tomoyo_normalize_line(start);
286362306a36Sopenharmony_ci			head.write_buf = start;
286462306a36Sopenharmony_ci			tomoyo_parse_policy(&head, start);
286562306a36Sopenharmony_ci			start = end + 1;
286662306a36Sopenharmony_ci		}
286762306a36Sopenharmony_ci	}
286862306a36Sopenharmony_ci	tomoyo_read_unlock(idx);
286962306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
287062306a36Sopenharmony_ci	tomoyo_check_profile();
287162306a36Sopenharmony_ci#endif
287262306a36Sopenharmony_ci}
2873