18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * security/tomoyo/common.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2011  NTT DATA CORPORATION
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/security.h>
118c2ecf20Sopenharmony_ci#include "common.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* String table for operation mode. */
148c2ecf20Sopenharmony_ciconst char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
158c2ecf20Sopenharmony_ci	[TOMOYO_CONFIG_DISABLED]   = "disabled",
168c2ecf20Sopenharmony_ci	[TOMOYO_CONFIG_LEARNING]   = "learning",
178c2ecf20Sopenharmony_ci	[TOMOYO_CONFIG_PERMISSIVE] = "permissive",
188c2ecf20Sopenharmony_ci	[TOMOYO_CONFIG_ENFORCING]  = "enforcing"
198c2ecf20Sopenharmony_ci};
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* String table for /sys/kernel/security/tomoyo/profile */
228c2ecf20Sopenharmony_ciconst char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
238c2ecf20Sopenharmony_ci				       + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
248c2ecf20Sopenharmony_ci	/* CONFIG::file group */
258c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_EXECUTE]    = "execute",
268c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_OPEN]       = "open",
278c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CREATE]     = "create",
288c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_UNLINK]     = "unlink",
298c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_GETATTR]    = "getattr",
308c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKDIR]      = "mkdir",
318c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_RMDIR]      = "rmdir",
328c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKFIFO]     = "mkfifo",
338c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKSOCK]     = "mksock",
348c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_TRUNCATE]   = "truncate",
358c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_SYMLINK]    = "symlink",
368c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKBLOCK]    = "mkblock",
378c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MKCHAR]     = "mkchar",
388c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_LINK]       = "link",
398c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_RENAME]     = "rename",
408c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHMOD]      = "chmod",
418c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHOWN]      = "chown",
428c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHGRP]      = "chgrp",
438c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_IOCTL]      = "ioctl",
448c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_CHROOT]     = "chroot",
458c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_MOUNT]      = "mount",
468c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_UMOUNT]     = "unmount",
478c2ecf20Sopenharmony_ci	[TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
488c2ecf20Sopenharmony_ci	/* CONFIG::network group */
498c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
508c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
518c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
528c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
538c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
548c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
558c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
568c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
578c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
588c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
598c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
608c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
618c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
628c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
638c2ecf20Sopenharmony_ci	[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
648c2ecf20Sopenharmony_ci	/* CONFIG::misc group */
658c2ecf20Sopenharmony_ci	[TOMOYO_MAC_ENVIRON] = "env",
668c2ecf20Sopenharmony_ci	/* CONFIG group */
678c2ecf20Sopenharmony_ci	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
688c2ecf20Sopenharmony_ci	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network",
698c2ecf20Sopenharmony_ci	[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc",
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* String table for conditions. */
738c2ecf20Sopenharmony_ciconst char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
748c2ecf20Sopenharmony_ci	[TOMOYO_TASK_UID]             = "task.uid",
758c2ecf20Sopenharmony_ci	[TOMOYO_TASK_EUID]            = "task.euid",
768c2ecf20Sopenharmony_ci	[TOMOYO_TASK_SUID]            = "task.suid",
778c2ecf20Sopenharmony_ci	[TOMOYO_TASK_FSUID]           = "task.fsuid",
788c2ecf20Sopenharmony_ci	[TOMOYO_TASK_GID]             = "task.gid",
798c2ecf20Sopenharmony_ci	[TOMOYO_TASK_EGID]            = "task.egid",
808c2ecf20Sopenharmony_ci	[TOMOYO_TASK_SGID]            = "task.sgid",
818c2ecf20Sopenharmony_ci	[TOMOYO_TASK_FSGID]           = "task.fsgid",
828c2ecf20Sopenharmony_ci	[TOMOYO_TASK_PID]             = "task.pid",
838c2ecf20Sopenharmony_ci	[TOMOYO_TASK_PPID]            = "task.ppid",
848c2ecf20Sopenharmony_ci	[TOMOYO_EXEC_ARGC]            = "exec.argc",
858c2ecf20Sopenharmony_ci	[TOMOYO_EXEC_ENVC]            = "exec.envc",
868c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_SOCKET]       = "socket",
878c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_SYMLINK]      = "symlink",
888c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_FILE]         = "file",
898c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_BLOCK_DEV]    = "block",
908c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_DIRECTORY]    = "directory",
918c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_CHAR_DEV]     = "char",
928c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_IS_FIFO]         = "fifo",
938c2ecf20Sopenharmony_ci	[TOMOYO_MODE_SETUID]          = "setuid",
948c2ecf20Sopenharmony_ci	[TOMOYO_MODE_SETGID]          = "setgid",
958c2ecf20Sopenharmony_ci	[TOMOYO_MODE_STICKY]          = "sticky",
968c2ecf20Sopenharmony_ci	[TOMOYO_MODE_OWNER_READ]      = "owner_read",
978c2ecf20Sopenharmony_ci	[TOMOYO_MODE_OWNER_WRITE]     = "owner_write",
988c2ecf20Sopenharmony_ci	[TOMOYO_MODE_OWNER_EXECUTE]   = "owner_execute",
998c2ecf20Sopenharmony_ci	[TOMOYO_MODE_GROUP_READ]      = "group_read",
1008c2ecf20Sopenharmony_ci	[TOMOYO_MODE_GROUP_WRITE]     = "group_write",
1018c2ecf20Sopenharmony_ci	[TOMOYO_MODE_GROUP_EXECUTE]   = "group_execute",
1028c2ecf20Sopenharmony_ci	[TOMOYO_MODE_OTHERS_READ]     = "others_read",
1038c2ecf20Sopenharmony_ci	[TOMOYO_MODE_OTHERS_WRITE]    = "others_write",
1048c2ecf20Sopenharmony_ci	[TOMOYO_MODE_OTHERS_EXECUTE]  = "others_execute",
1058c2ecf20Sopenharmony_ci	[TOMOYO_EXEC_REALPATH]        = "exec.realpath",
1068c2ecf20Sopenharmony_ci	[TOMOYO_SYMLINK_TARGET]       = "symlink.target",
1078c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_UID]            = "path1.uid",
1088c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_GID]            = "path1.gid",
1098c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_INO]            = "path1.ino",
1108c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_MAJOR]          = "path1.major",
1118c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_MINOR]          = "path1.minor",
1128c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_PERM]           = "path1.perm",
1138c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_TYPE]           = "path1.type",
1148c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_DEV_MAJOR]      = "path1.dev_major",
1158c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_DEV_MINOR]      = "path1.dev_minor",
1168c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_UID]            = "path2.uid",
1178c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_GID]            = "path2.gid",
1188c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_INO]            = "path2.ino",
1198c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_MAJOR]          = "path2.major",
1208c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_MINOR]          = "path2.minor",
1218c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_PERM]           = "path2.perm",
1228c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_TYPE]           = "path2.type",
1238c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_DEV_MAJOR]      = "path2.dev_major",
1248c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_DEV_MINOR]      = "path2.dev_minor",
1258c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_PARENT_UID]     = "path1.parent.uid",
1268c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_PARENT_GID]     = "path1.parent.gid",
1278c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_PARENT_INO]     = "path1.parent.ino",
1288c2ecf20Sopenharmony_ci	[TOMOYO_PATH1_PARENT_PERM]    = "path1.parent.perm",
1298c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_PARENT_UID]     = "path2.parent.uid",
1308c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_PARENT_GID]     = "path2.parent.gid",
1318c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_PARENT_INO]     = "path2.parent.ino",
1328c2ecf20Sopenharmony_ci	[TOMOYO_PATH2_PARENT_PERM]    = "path2.parent.perm",
1338c2ecf20Sopenharmony_ci};
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/* String table for PREFERENCE keyword. */
1368c2ecf20Sopenharmony_cistatic const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
1378c2ecf20Sopenharmony_ci	[TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
1388c2ecf20Sopenharmony_ci	[TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* String table for path operation. */
1428c2ecf20Sopenharmony_ciconst char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
1438c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_EXECUTE]    = "execute",
1448c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_READ]       = "read",
1458c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_WRITE]      = "write",
1468c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_APPEND]     = "append",
1478c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_UNLINK]     = "unlink",
1488c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_GETATTR]    = "getattr",
1498c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_RMDIR]      = "rmdir",
1508c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_TRUNCATE]   = "truncate",
1518c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_SYMLINK]    = "symlink",
1528c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_CHROOT]     = "chroot",
1538c2ecf20Sopenharmony_ci	[TOMOYO_TYPE_UMOUNT]     = "unmount",
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/* String table for socket's operation. */
1578c2ecf20Sopenharmony_ciconst char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = {
1588c2ecf20Sopenharmony_ci	[TOMOYO_NETWORK_BIND]    = "bind",
1598c2ecf20Sopenharmony_ci	[TOMOYO_NETWORK_LISTEN]  = "listen",
1608c2ecf20Sopenharmony_ci	[TOMOYO_NETWORK_CONNECT] = "connect",
1618c2ecf20Sopenharmony_ci	[TOMOYO_NETWORK_SEND]    = "send",
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* String table for categories. */
1658c2ecf20Sopenharmony_cistatic const char * const tomoyo_category_keywords
1668c2ecf20Sopenharmony_ci[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
1678c2ecf20Sopenharmony_ci	[TOMOYO_MAC_CATEGORY_FILE]    = "file",
1688c2ecf20Sopenharmony_ci	[TOMOYO_MAC_CATEGORY_NETWORK] = "network",
1698c2ecf20Sopenharmony_ci	[TOMOYO_MAC_CATEGORY_MISC]    = "misc",
1708c2ecf20Sopenharmony_ci};
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* Permit policy management by non-root user? */
1738c2ecf20Sopenharmony_cistatic bool tomoyo_manage_by_non_root;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/* Utility functions. */
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/**
1788c2ecf20Sopenharmony_ci * tomoyo_yesno - Return "yes" or "no".
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci * @value: Bool value.
1818c2ecf20Sopenharmony_ci */
1828c2ecf20Sopenharmony_ciconst char *tomoyo_yesno(const unsigned int value)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	return value ? "yes" : "no";
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/**
1888c2ecf20Sopenharmony_ci * tomoyo_addprintf - strncat()-like-snprintf().
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * @buffer: Buffer to write to. Must be '\0'-terminated.
1918c2ecf20Sopenharmony_ci * @len:    Size of @buffer.
1928c2ecf20Sopenharmony_ci * @fmt:    The printf()'s format string, followed by parameters.
1938c2ecf20Sopenharmony_ci *
1948c2ecf20Sopenharmony_ci * Returns nothing.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_cistatic void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	va_list args;
1998c2ecf20Sopenharmony_ci	const int pos = strlen(buffer);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	va_start(args, fmt);
2028c2ecf20Sopenharmony_ci	vsnprintf(buffer + pos, len - pos - 1, fmt, args);
2038c2ecf20Sopenharmony_ci	va_end(args);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/**
2078c2ecf20Sopenharmony_ci * tomoyo_flush - Flush queued string to userspace's buffer.
2088c2ecf20Sopenharmony_ci *
2098c2ecf20Sopenharmony_ci * @head:   Pointer to "struct tomoyo_io_buffer".
2108c2ecf20Sopenharmony_ci *
2118c2ecf20Sopenharmony_ci * Returns true if all data was flushed, false otherwise.
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic bool tomoyo_flush(struct tomoyo_io_buffer *head)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	while (head->r.w_pos) {
2168c2ecf20Sopenharmony_ci		const char *w = head->r.w[0];
2178c2ecf20Sopenharmony_ci		size_t len = strlen(w);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		if (len) {
2208c2ecf20Sopenharmony_ci			if (len > head->read_user_buf_avail)
2218c2ecf20Sopenharmony_ci				len = head->read_user_buf_avail;
2228c2ecf20Sopenharmony_ci			if (!len)
2238c2ecf20Sopenharmony_ci				return false;
2248c2ecf20Sopenharmony_ci			if (copy_to_user(head->read_user_buf, w, len))
2258c2ecf20Sopenharmony_ci				return false;
2268c2ecf20Sopenharmony_ci			head->read_user_buf_avail -= len;
2278c2ecf20Sopenharmony_ci			head->read_user_buf += len;
2288c2ecf20Sopenharmony_ci			w += len;
2298c2ecf20Sopenharmony_ci		}
2308c2ecf20Sopenharmony_ci		head->r.w[0] = w;
2318c2ecf20Sopenharmony_ci		if (*w)
2328c2ecf20Sopenharmony_ci			return false;
2338c2ecf20Sopenharmony_ci		/* Add '\0' for audit logs and query. */
2348c2ecf20Sopenharmony_ci		if (head->poll) {
2358c2ecf20Sopenharmony_ci			if (!head->read_user_buf_avail ||
2368c2ecf20Sopenharmony_ci			    copy_to_user(head->read_user_buf, "", 1))
2378c2ecf20Sopenharmony_ci				return false;
2388c2ecf20Sopenharmony_ci			head->read_user_buf_avail--;
2398c2ecf20Sopenharmony_ci			head->read_user_buf++;
2408c2ecf20Sopenharmony_ci		}
2418c2ecf20Sopenharmony_ci		head->r.w_pos--;
2428c2ecf20Sopenharmony_ci		for (len = 0; len < head->r.w_pos; len++)
2438c2ecf20Sopenharmony_ci			head->r.w[len] = head->r.w[len + 1];
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	head->r.avail = 0;
2468c2ecf20Sopenharmony_ci	return true;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/**
2508c2ecf20Sopenharmony_ci * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure.
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * @head:   Pointer to "struct tomoyo_io_buffer".
2538c2ecf20Sopenharmony_ci * @string: String to print.
2548c2ecf20Sopenharmony_ci *
2558c2ecf20Sopenharmony_ci * Note that @string has to be kept valid until @head is kfree()d.
2568c2ecf20Sopenharmony_ci * This means that char[] allocated on stack memory cannot be passed to
2578c2ecf20Sopenharmony_ci * this function. Use tomoyo_io_printf() for char[] allocated on stack memory.
2588c2ecf20Sopenharmony_ci */
2598c2ecf20Sopenharmony_cistatic void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) {
2628c2ecf20Sopenharmony_ci		head->r.w[head->r.w_pos++] = string;
2638c2ecf20Sopenharmony_ci		tomoyo_flush(head);
2648c2ecf20Sopenharmony_ci	} else
2658c2ecf20Sopenharmony_ci		WARN_ON(1);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
2698c2ecf20Sopenharmony_ci			     ...) __printf(2, 3);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci/**
2728c2ecf20Sopenharmony_ci * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
2738c2ecf20Sopenharmony_ci *
2748c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
2758c2ecf20Sopenharmony_ci * @fmt:  The printf()'s format string, followed by parameters.
2768c2ecf20Sopenharmony_ci */
2778c2ecf20Sopenharmony_cistatic void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
2788c2ecf20Sopenharmony_ci			     ...)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	va_list args;
2818c2ecf20Sopenharmony_ci	size_t len;
2828c2ecf20Sopenharmony_ci	size_t pos = head->r.avail;
2838c2ecf20Sopenharmony_ci	int size = head->readbuf_size - pos;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (size <= 0)
2868c2ecf20Sopenharmony_ci		return;
2878c2ecf20Sopenharmony_ci	va_start(args, fmt);
2888c2ecf20Sopenharmony_ci	len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
2898c2ecf20Sopenharmony_ci	va_end(args);
2908c2ecf20Sopenharmony_ci	if (pos + len >= head->readbuf_size) {
2918c2ecf20Sopenharmony_ci		WARN_ON(1);
2928c2ecf20Sopenharmony_ci		return;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	head->r.avail += len;
2958c2ecf20Sopenharmony_ci	tomoyo_set_string(head, head->read_buf + pos);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/**
2998c2ecf20Sopenharmony_ci * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure.
3008c2ecf20Sopenharmony_ci *
3018c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * Returns nothing.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_cistatic void tomoyo_set_space(struct tomoyo_io_buffer *head)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	tomoyo_set_string(head, " ");
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci/**
3118c2ecf20Sopenharmony_ci * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure.
3128c2ecf20Sopenharmony_ci *
3138c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
3148c2ecf20Sopenharmony_ci *
3158c2ecf20Sopenharmony_ci * Returns nothing.
3168c2ecf20Sopenharmony_ci */
3178c2ecf20Sopenharmony_cistatic bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	tomoyo_set_string(head, "\n");
3208c2ecf20Sopenharmony_ci	return !head->r.w_pos;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci/**
3248c2ecf20Sopenharmony_ci * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure.
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
3278c2ecf20Sopenharmony_ci *
3288c2ecf20Sopenharmony_ci * Returns nothing.
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_cistatic void tomoyo_set_slash(struct tomoyo_io_buffer *head)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	tomoyo_set_string(head, "/");
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/* List of namespaces. */
3368c2ecf20Sopenharmony_ciLIST_HEAD(tomoyo_namespace_list);
3378c2ecf20Sopenharmony_ci/* True if namespace other than tomoyo_kernel_namespace is defined. */
3388c2ecf20Sopenharmony_cistatic bool tomoyo_namespace_enabled;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/**
3418c2ecf20Sopenharmony_ci * tomoyo_init_policy_namespace - Initialize namespace.
3428c2ecf20Sopenharmony_ci *
3438c2ecf20Sopenharmony_ci * @ns: Pointer to "struct tomoyo_policy_namespace".
3448c2ecf20Sopenharmony_ci *
3458c2ecf20Sopenharmony_ci * Returns nothing.
3468c2ecf20Sopenharmony_ci */
3478c2ecf20Sopenharmony_civoid tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	unsigned int idx;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
3528c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ns->acl_group[idx]);
3538c2ecf20Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
3548c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ns->group_list[idx]);
3558c2ecf20Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
3568c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ns->policy_list[idx]);
3578c2ecf20Sopenharmony_ci	ns->profile_version = 20150505;
3588c2ecf20Sopenharmony_ci	tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
3598c2ecf20Sopenharmony_ci	list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci/**
3638c2ecf20Sopenharmony_ci * tomoyo_print_namespace - Print namespace header.
3648c2ecf20Sopenharmony_ci *
3658c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
3668c2ecf20Sopenharmony_ci *
3678c2ecf20Sopenharmony_ci * Returns nothing.
3688c2ecf20Sopenharmony_ci */
3698c2ecf20Sopenharmony_cistatic void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	if (!tomoyo_namespace_enabled)
3728c2ecf20Sopenharmony_ci		return;
3738c2ecf20Sopenharmony_ci	tomoyo_set_string(head,
3748c2ecf20Sopenharmony_ci			  container_of(head->r.ns,
3758c2ecf20Sopenharmony_ci				       struct tomoyo_policy_namespace,
3768c2ecf20Sopenharmony_ci				       namespace_list)->name);
3778c2ecf20Sopenharmony_ci	tomoyo_set_space(head);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/**
3818c2ecf20Sopenharmony_ci * tomoyo_print_name_union - Print a tomoyo_name_union.
3828c2ecf20Sopenharmony_ci *
3838c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
3848c2ecf20Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_name_union".
3858c2ecf20Sopenharmony_ci */
3868c2ecf20Sopenharmony_cistatic void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
3878c2ecf20Sopenharmony_ci				    const struct tomoyo_name_union *ptr)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	tomoyo_set_space(head);
3908c2ecf20Sopenharmony_ci	if (ptr->group) {
3918c2ecf20Sopenharmony_ci		tomoyo_set_string(head, "@");
3928c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->group->group_name->name);
3938c2ecf20Sopenharmony_ci	} else {
3948c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->filename->name);
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci/**
3998c2ecf20Sopenharmony_ci * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote.
4008c2ecf20Sopenharmony_ci *
4018c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
4028c2ecf20Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_name_union".
4038c2ecf20Sopenharmony_ci *
4048c2ecf20Sopenharmony_ci * Returns nothing.
4058c2ecf20Sopenharmony_ci */
4068c2ecf20Sopenharmony_cistatic void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head,
4078c2ecf20Sopenharmony_ci					   const struct tomoyo_name_union *ptr)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	if (ptr->group) {
4108c2ecf20Sopenharmony_ci		tomoyo_set_string(head, "@");
4118c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->group->group_name->name);
4128c2ecf20Sopenharmony_ci	} else {
4138c2ecf20Sopenharmony_ci		tomoyo_set_string(head, "\"");
4148c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->filename->name);
4158c2ecf20Sopenharmony_ci		tomoyo_set_string(head, "\"");
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/**
4208c2ecf20Sopenharmony_ci * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
4238c2ecf20Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_number_union".
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Returns nothing.
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic void tomoyo_print_number_union_nospace
4288c2ecf20Sopenharmony_ci(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	if (ptr->group) {
4318c2ecf20Sopenharmony_ci		tomoyo_set_string(head, "@");
4328c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->group->group_name->name);
4338c2ecf20Sopenharmony_ci	} else {
4348c2ecf20Sopenharmony_ci		int i;
4358c2ecf20Sopenharmony_ci		unsigned long min = ptr->values[0];
4368c2ecf20Sopenharmony_ci		const unsigned long max = ptr->values[1];
4378c2ecf20Sopenharmony_ci		u8 min_type = ptr->value_type[0];
4388c2ecf20Sopenharmony_ci		const u8 max_type = ptr->value_type[1];
4398c2ecf20Sopenharmony_ci		char buffer[128];
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci		buffer[0] = '\0';
4428c2ecf20Sopenharmony_ci		for (i = 0; i < 2; i++) {
4438c2ecf20Sopenharmony_ci			switch (min_type) {
4448c2ecf20Sopenharmony_ci			case TOMOYO_VALUE_TYPE_HEXADECIMAL:
4458c2ecf20Sopenharmony_ci				tomoyo_addprintf(buffer, sizeof(buffer),
4468c2ecf20Sopenharmony_ci						 "0x%lX", min);
4478c2ecf20Sopenharmony_ci				break;
4488c2ecf20Sopenharmony_ci			case TOMOYO_VALUE_TYPE_OCTAL:
4498c2ecf20Sopenharmony_ci				tomoyo_addprintf(buffer, sizeof(buffer),
4508c2ecf20Sopenharmony_ci						 "0%lo", min);
4518c2ecf20Sopenharmony_ci				break;
4528c2ecf20Sopenharmony_ci			default:
4538c2ecf20Sopenharmony_ci				tomoyo_addprintf(buffer, sizeof(buffer), "%lu",
4548c2ecf20Sopenharmony_ci						 min);
4558c2ecf20Sopenharmony_ci				break;
4568c2ecf20Sopenharmony_ci			}
4578c2ecf20Sopenharmony_ci			if (min == max && min_type == max_type)
4588c2ecf20Sopenharmony_ci				break;
4598c2ecf20Sopenharmony_ci			tomoyo_addprintf(buffer, sizeof(buffer), "-");
4608c2ecf20Sopenharmony_ci			min_type = max_type;
4618c2ecf20Sopenharmony_ci			min = max;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "%s", buffer);
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci/**
4688c2ecf20Sopenharmony_ci * tomoyo_print_number_union - Print a tomoyo_number_union.
4698c2ecf20Sopenharmony_ci *
4708c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
4718c2ecf20Sopenharmony_ci * @ptr:  Pointer to "struct tomoyo_number_union".
4728c2ecf20Sopenharmony_ci *
4738c2ecf20Sopenharmony_ci * Returns nothing.
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_cistatic void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
4768c2ecf20Sopenharmony_ci				      const struct tomoyo_number_union *ptr)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	tomoyo_set_space(head);
4798c2ecf20Sopenharmony_ci	tomoyo_print_number_union_nospace(head, ptr);
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci/**
4838c2ecf20Sopenharmony_ci * tomoyo_assign_profile - Create a new profile.
4848c2ecf20Sopenharmony_ci *
4858c2ecf20Sopenharmony_ci * @ns:      Pointer to "struct tomoyo_policy_namespace".
4868c2ecf20Sopenharmony_ci * @profile: Profile number to create.
4878c2ecf20Sopenharmony_ci *
4888c2ecf20Sopenharmony_ci * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
4898c2ecf20Sopenharmony_ci */
4908c2ecf20Sopenharmony_cistatic struct tomoyo_profile *tomoyo_assign_profile
4918c2ecf20Sopenharmony_ci(struct tomoyo_policy_namespace *ns, const unsigned int profile)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct tomoyo_profile *ptr;
4948c2ecf20Sopenharmony_ci	struct tomoyo_profile *entry;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (profile >= TOMOYO_MAX_PROFILES)
4978c2ecf20Sopenharmony_ci		return NULL;
4988c2ecf20Sopenharmony_ci	ptr = ns->profile_ptr[profile];
4998c2ecf20Sopenharmony_ci	if (ptr)
5008c2ecf20Sopenharmony_ci		return ptr;
5018c2ecf20Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_NOFS);
5028c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&tomoyo_policy_lock))
5038c2ecf20Sopenharmony_ci		goto out;
5048c2ecf20Sopenharmony_ci	ptr = ns->profile_ptr[profile];
5058c2ecf20Sopenharmony_ci	if (!ptr && tomoyo_memory_ok(entry)) {
5068c2ecf20Sopenharmony_ci		ptr = entry;
5078c2ecf20Sopenharmony_ci		ptr->default_config = TOMOYO_CONFIG_DISABLED |
5088c2ecf20Sopenharmony_ci			TOMOYO_CONFIG_WANT_GRANT_LOG |
5098c2ecf20Sopenharmony_ci			TOMOYO_CONFIG_WANT_REJECT_LOG;
5108c2ecf20Sopenharmony_ci		memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
5118c2ecf20Sopenharmony_ci		       sizeof(ptr->config));
5128c2ecf20Sopenharmony_ci		ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] =
5138c2ecf20Sopenharmony_ci			CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG;
5148c2ecf20Sopenharmony_ci		ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] =
5158c2ecf20Sopenharmony_ci			CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY;
5168c2ecf20Sopenharmony_ci		mb(); /* Avoid out-of-order execution. */
5178c2ecf20Sopenharmony_ci		ns->profile_ptr[profile] = ptr;
5188c2ecf20Sopenharmony_ci		entry = NULL;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci	mutex_unlock(&tomoyo_policy_lock);
5218c2ecf20Sopenharmony_ci out:
5228c2ecf20Sopenharmony_ci	kfree(entry);
5238c2ecf20Sopenharmony_ci	return ptr;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci/**
5278c2ecf20Sopenharmony_ci * tomoyo_profile - Find a profile.
5288c2ecf20Sopenharmony_ci *
5298c2ecf20Sopenharmony_ci * @ns:      Pointer to "struct tomoyo_policy_namespace".
5308c2ecf20Sopenharmony_ci * @profile: Profile number to find.
5318c2ecf20Sopenharmony_ci *
5328c2ecf20Sopenharmony_ci * Returns pointer to "struct tomoyo_profile".
5338c2ecf20Sopenharmony_ci */
5348c2ecf20Sopenharmony_cistruct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
5358c2ecf20Sopenharmony_ci				      const u8 profile)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	static struct tomoyo_profile tomoyo_null_profile;
5388c2ecf20Sopenharmony_ci	struct tomoyo_profile *ptr = ns->profile_ptr[profile];
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (!ptr)
5418c2ecf20Sopenharmony_ci		ptr = &tomoyo_null_profile;
5428c2ecf20Sopenharmony_ci	return ptr;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci/**
5468c2ecf20Sopenharmony_ci * tomoyo_find_yesno - Find values for specified keyword.
5478c2ecf20Sopenharmony_ci *
5488c2ecf20Sopenharmony_ci * @string: String to check.
5498c2ecf20Sopenharmony_ci * @find:   Name of keyword.
5508c2ecf20Sopenharmony_ci *
5518c2ecf20Sopenharmony_ci * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
5528c2ecf20Sopenharmony_ci */
5538c2ecf20Sopenharmony_cistatic s8 tomoyo_find_yesno(const char *string, const char *find)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	const char *cp = strstr(string, find);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	if (cp) {
5588c2ecf20Sopenharmony_ci		cp += strlen(find);
5598c2ecf20Sopenharmony_ci		if (!strncmp(cp, "=yes", 4))
5608c2ecf20Sopenharmony_ci			return 1;
5618c2ecf20Sopenharmony_ci		else if (!strncmp(cp, "=no", 3))
5628c2ecf20Sopenharmony_ci			return 0;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci	return -1;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci/**
5688c2ecf20Sopenharmony_ci * tomoyo_set_uint - Set value for specified preference.
5698c2ecf20Sopenharmony_ci *
5708c2ecf20Sopenharmony_ci * @i:      Pointer to "unsigned int".
5718c2ecf20Sopenharmony_ci * @string: String to check.
5728c2ecf20Sopenharmony_ci * @find:   Name of keyword.
5738c2ecf20Sopenharmony_ci *
5748c2ecf20Sopenharmony_ci * Returns nothing.
5758c2ecf20Sopenharmony_ci */
5768c2ecf20Sopenharmony_cistatic void tomoyo_set_uint(unsigned int *i, const char *string,
5778c2ecf20Sopenharmony_ci			    const char *find)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	const char *cp = strstr(string, find);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (cp)
5828c2ecf20Sopenharmony_ci		sscanf(cp + strlen(find), "=%u", i);
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci/**
5868c2ecf20Sopenharmony_ci * tomoyo_set_mode - Set mode for specified profile.
5878c2ecf20Sopenharmony_ci *
5888c2ecf20Sopenharmony_ci * @name:    Name of functionality.
5898c2ecf20Sopenharmony_ci * @value:   Mode for @name.
5908c2ecf20Sopenharmony_ci * @profile: Pointer to "struct tomoyo_profile".
5918c2ecf20Sopenharmony_ci *
5928c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
5938c2ecf20Sopenharmony_ci */
5948c2ecf20Sopenharmony_cistatic int tomoyo_set_mode(char *name, const char *value,
5958c2ecf20Sopenharmony_ci			   struct tomoyo_profile *profile)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	u8 i;
5988c2ecf20Sopenharmony_ci	u8 config;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (!strcmp(name, "CONFIG")) {
6018c2ecf20Sopenharmony_ci		i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
6028c2ecf20Sopenharmony_ci		config = profile->default_config;
6038c2ecf20Sopenharmony_ci	} else if (tomoyo_str_starts(&name, "CONFIG::")) {
6048c2ecf20Sopenharmony_ci		config = 0;
6058c2ecf20Sopenharmony_ci		for (i = 0; i < TOMOYO_MAX_MAC_INDEX
6068c2ecf20Sopenharmony_ci			     + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
6078c2ecf20Sopenharmony_ci			int len = 0;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci			if (i < TOMOYO_MAX_MAC_INDEX) {
6108c2ecf20Sopenharmony_ci				const u8 c = tomoyo_index2category[i];
6118c2ecf20Sopenharmony_ci				const char *category =
6128c2ecf20Sopenharmony_ci					tomoyo_category_keywords[c];
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci				len = strlen(category);
6158c2ecf20Sopenharmony_ci				if (strncmp(name, category, len) ||
6168c2ecf20Sopenharmony_ci				    name[len++] != ':' || name[len++] != ':')
6178c2ecf20Sopenharmony_ci					continue;
6188c2ecf20Sopenharmony_ci			}
6198c2ecf20Sopenharmony_ci			if (strcmp(name + len, tomoyo_mac_keywords[i]))
6208c2ecf20Sopenharmony_ci				continue;
6218c2ecf20Sopenharmony_ci			config = profile->config[i];
6228c2ecf20Sopenharmony_ci			break;
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci		if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
6258c2ecf20Sopenharmony_ci			return -EINVAL;
6268c2ecf20Sopenharmony_ci	} else {
6278c2ecf20Sopenharmony_ci		return -EINVAL;
6288c2ecf20Sopenharmony_ci	}
6298c2ecf20Sopenharmony_ci	if (strstr(value, "use_default")) {
6308c2ecf20Sopenharmony_ci		config = TOMOYO_CONFIG_USE_DEFAULT;
6318c2ecf20Sopenharmony_ci	} else {
6328c2ecf20Sopenharmony_ci		u8 mode;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci		for (mode = 0; mode < 4; mode++)
6358c2ecf20Sopenharmony_ci			if (strstr(value, tomoyo_mode[mode]))
6368c2ecf20Sopenharmony_ci				/*
6378c2ecf20Sopenharmony_ci				 * Update lower 3 bits in order to distinguish
6388c2ecf20Sopenharmony_ci				 * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
6398c2ecf20Sopenharmony_ci				 */
6408c2ecf20Sopenharmony_ci				config = (config & ~7) | mode;
6418c2ecf20Sopenharmony_ci		if (config != TOMOYO_CONFIG_USE_DEFAULT) {
6428c2ecf20Sopenharmony_ci			switch (tomoyo_find_yesno(value, "grant_log")) {
6438c2ecf20Sopenharmony_ci			case 1:
6448c2ecf20Sopenharmony_ci				config |= TOMOYO_CONFIG_WANT_GRANT_LOG;
6458c2ecf20Sopenharmony_ci				break;
6468c2ecf20Sopenharmony_ci			case 0:
6478c2ecf20Sopenharmony_ci				config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG;
6488c2ecf20Sopenharmony_ci				break;
6498c2ecf20Sopenharmony_ci			}
6508c2ecf20Sopenharmony_ci			switch (tomoyo_find_yesno(value, "reject_log")) {
6518c2ecf20Sopenharmony_ci			case 1:
6528c2ecf20Sopenharmony_ci				config |= TOMOYO_CONFIG_WANT_REJECT_LOG;
6538c2ecf20Sopenharmony_ci				break;
6548c2ecf20Sopenharmony_ci			case 0:
6558c2ecf20Sopenharmony_ci				config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG;
6568c2ecf20Sopenharmony_ci				break;
6578c2ecf20Sopenharmony_ci			}
6588c2ecf20Sopenharmony_ci		}
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci	if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
6618c2ecf20Sopenharmony_ci		profile->config[i] = config;
6628c2ecf20Sopenharmony_ci	else if (config != TOMOYO_CONFIG_USE_DEFAULT)
6638c2ecf20Sopenharmony_ci		profile->default_config = config;
6648c2ecf20Sopenharmony_ci	return 0;
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci/**
6688c2ecf20Sopenharmony_ci * tomoyo_write_profile - Write profile table.
6698c2ecf20Sopenharmony_ci *
6708c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
6718c2ecf20Sopenharmony_ci *
6728c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
6738c2ecf20Sopenharmony_ci */
6748c2ecf20Sopenharmony_cistatic int tomoyo_write_profile(struct tomoyo_io_buffer *head)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	char *data = head->write_buf;
6778c2ecf20Sopenharmony_ci	unsigned int i;
6788c2ecf20Sopenharmony_ci	char *cp;
6798c2ecf20Sopenharmony_ci	struct tomoyo_profile *profile;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
6828c2ecf20Sopenharmony_ci	    == 1)
6838c2ecf20Sopenharmony_ci		return 0;
6848c2ecf20Sopenharmony_ci	i = simple_strtoul(data, &cp, 10);
6858c2ecf20Sopenharmony_ci	if (*cp != '-')
6868c2ecf20Sopenharmony_ci		return -EINVAL;
6878c2ecf20Sopenharmony_ci	data = cp + 1;
6888c2ecf20Sopenharmony_ci	profile = tomoyo_assign_profile(head->w.ns, i);
6898c2ecf20Sopenharmony_ci	if (!profile)
6908c2ecf20Sopenharmony_ci		return -EINVAL;
6918c2ecf20Sopenharmony_ci	cp = strchr(data, '=');
6928c2ecf20Sopenharmony_ci	if (!cp)
6938c2ecf20Sopenharmony_ci		return -EINVAL;
6948c2ecf20Sopenharmony_ci	*cp++ = '\0';
6958c2ecf20Sopenharmony_ci	if (!strcmp(data, "COMMENT")) {
6968c2ecf20Sopenharmony_ci		static DEFINE_SPINLOCK(lock);
6978c2ecf20Sopenharmony_ci		const struct tomoyo_path_info *new_comment
6988c2ecf20Sopenharmony_ci			= tomoyo_get_name(cp);
6998c2ecf20Sopenharmony_ci		const struct tomoyo_path_info *old_comment;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		if (!new_comment)
7028c2ecf20Sopenharmony_ci			return -ENOMEM;
7038c2ecf20Sopenharmony_ci		spin_lock(&lock);
7048c2ecf20Sopenharmony_ci		old_comment = profile->comment;
7058c2ecf20Sopenharmony_ci		profile->comment = new_comment;
7068c2ecf20Sopenharmony_ci		spin_unlock(&lock);
7078c2ecf20Sopenharmony_ci		tomoyo_put_name(old_comment);
7088c2ecf20Sopenharmony_ci		return 0;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci	if (!strcmp(data, "PREFERENCE")) {
7118c2ecf20Sopenharmony_ci		for (i = 0; i < TOMOYO_MAX_PREF; i++)
7128c2ecf20Sopenharmony_ci			tomoyo_set_uint(&profile->pref[i], cp,
7138c2ecf20Sopenharmony_ci					tomoyo_pref_keywords[i]);
7148c2ecf20Sopenharmony_ci		return 0;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci	return tomoyo_set_mode(data, cp, profile);
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci/**
7208c2ecf20Sopenharmony_ci * tomoyo_print_config - Print mode for specified functionality.
7218c2ecf20Sopenharmony_ci *
7228c2ecf20Sopenharmony_ci * @head:   Pointer to "struct tomoyo_io_buffer".
7238c2ecf20Sopenharmony_ci * @config: Mode for that functionality.
7248c2ecf20Sopenharmony_ci *
7258c2ecf20Sopenharmony_ci * Returns nothing.
7268c2ecf20Sopenharmony_ci *
7278c2ecf20Sopenharmony_ci * Caller prints functionality's name.
7288c2ecf20Sopenharmony_ci */
7298c2ecf20Sopenharmony_cistatic void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
7328c2ecf20Sopenharmony_ci			 tomoyo_mode[config & 3],
7338c2ecf20Sopenharmony_ci			 tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG),
7348c2ecf20Sopenharmony_ci			 tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG));
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci/**
7388c2ecf20Sopenharmony_ci * tomoyo_read_profile - Read profile table.
7398c2ecf20Sopenharmony_ci *
7408c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
7418c2ecf20Sopenharmony_ci *
7428c2ecf20Sopenharmony_ci * Returns nothing.
7438c2ecf20Sopenharmony_ci */
7448c2ecf20Sopenharmony_cistatic void tomoyo_read_profile(struct tomoyo_io_buffer *head)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	u8 index;
7478c2ecf20Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
7488c2ecf20Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
7498c2ecf20Sopenharmony_ci	const struct tomoyo_profile *profile;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	if (head->r.eof)
7528c2ecf20Sopenharmony_ci		return;
7538c2ecf20Sopenharmony_ci next:
7548c2ecf20Sopenharmony_ci	index = head->r.index;
7558c2ecf20Sopenharmony_ci	profile = ns->profile_ptr[index];
7568c2ecf20Sopenharmony_ci	switch (head->r.step) {
7578c2ecf20Sopenharmony_ci	case 0:
7588c2ecf20Sopenharmony_ci		tomoyo_print_namespace(head);
7598c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
7608c2ecf20Sopenharmony_ci				 ns->profile_version);
7618c2ecf20Sopenharmony_ci		head->r.step++;
7628c2ecf20Sopenharmony_ci		break;
7638c2ecf20Sopenharmony_ci	case 1:
7648c2ecf20Sopenharmony_ci		for ( ; head->r.index < TOMOYO_MAX_PROFILES;
7658c2ecf20Sopenharmony_ci		      head->r.index++)
7668c2ecf20Sopenharmony_ci			if (ns->profile_ptr[head->r.index])
7678c2ecf20Sopenharmony_ci				break;
7688c2ecf20Sopenharmony_ci		if (head->r.index == TOMOYO_MAX_PROFILES) {
7698c2ecf20Sopenharmony_ci			head->r.eof = true;
7708c2ecf20Sopenharmony_ci			return;
7718c2ecf20Sopenharmony_ci		}
7728c2ecf20Sopenharmony_ci		head->r.step++;
7738c2ecf20Sopenharmony_ci		break;
7748c2ecf20Sopenharmony_ci	case 2:
7758c2ecf20Sopenharmony_ci		{
7768c2ecf20Sopenharmony_ci			u8 i;
7778c2ecf20Sopenharmony_ci			const struct tomoyo_path_info *comment =
7788c2ecf20Sopenharmony_ci				profile->comment;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci			tomoyo_print_namespace(head);
7818c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, "%u-COMMENT=", index);
7828c2ecf20Sopenharmony_ci			tomoyo_set_string(head, comment ? comment->name : "");
7838c2ecf20Sopenharmony_ci			tomoyo_set_lf(head);
7848c2ecf20Sopenharmony_ci			tomoyo_print_namespace(head);
7858c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
7868c2ecf20Sopenharmony_ci			for (i = 0; i < TOMOYO_MAX_PREF; i++)
7878c2ecf20Sopenharmony_ci				tomoyo_io_printf(head, "%s=%u ",
7888c2ecf20Sopenharmony_ci						 tomoyo_pref_keywords[i],
7898c2ecf20Sopenharmony_ci						 profile->pref[i]);
7908c2ecf20Sopenharmony_ci			tomoyo_set_string(head, "}\n");
7918c2ecf20Sopenharmony_ci			head->r.step++;
7928c2ecf20Sopenharmony_ci		}
7938c2ecf20Sopenharmony_ci		break;
7948c2ecf20Sopenharmony_ci	case 3:
7958c2ecf20Sopenharmony_ci		{
7968c2ecf20Sopenharmony_ci			tomoyo_print_namespace(head);
7978c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
7988c2ecf20Sopenharmony_ci			tomoyo_print_config(head, profile->default_config);
7998c2ecf20Sopenharmony_ci			head->r.bit = 0;
8008c2ecf20Sopenharmony_ci			head->r.step++;
8018c2ecf20Sopenharmony_ci		}
8028c2ecf20Sopenharmony_ci		break;
8038c2ecf20Sopenharmony_ci	case 4:
8048c2ecf20Sopenharmony_ci		for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX
8058c2ecf20Sopenharmony_ci			      + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
8068c2ecf20Sopenharmony_ci			const u8 i = head->r.bit;
8078c2ecf20Sopenharmony_ci			const u8 config = profile->config[i];
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci			if (config == TOMOYO_CONFIG_USE_DEFAULT)
8108c2ecf20Sopenharmony_ci				continue;
8118c2ecf20Sopenharmony_ci			tomoyo_print_namespace(head);
8128c2ecf20Sopenharmony_ci			if (i < TOMOYO_MAX_MAC_INDEX)
8138c2ecf20Sopenharmony_ci				tomoyo_io_printf(head, "%u-CONFIG::%s::%s",
8148c2ecf20Sopenharmony_ci						 index,
8158c2ecf20Sopenharmony_ci						 tomoyo_category_keywords
8168c2ecf20Sopenharmony_ci						 [tomoyo_index2category[i]],
8178c2ecf20Sopenharmony_ci						 tomoyo_mac_keywords[i]);
8188c2ecf20Sopenharmony_ci			else
8198c2ecf20Sopenharmony_ci				tomoyo_io_printf(head, "%u-CONFIG::%s", index,
8208c2ecf20Sopenharmony_ci						 tomoyo_mac_keywords[i]);
8218c2ecf20Sopenharmony_ci			tomoyo_print_config(head, config);
8228c2ecf20Sopenharmony_ci			head->r.bit++;
8238c2ecf20Sopenharmony_ci			break;
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci		if (head->r.bit == TOMOYO_MAX_MAC_INDEX
8268c2ecf20Sopenharmony_ci		    + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
8278c2ecf20Sopenharmony_ci			head->r.index++;
8288c2ecf20Sopenharmony_ci			head->r.step = 1;
8298c2ecf20Sopenharmony_ci		}
8308c2ecf20Sopenharmony_ci		break;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci	if (tomoyo_flush(head))
8338c2ecf20Sopenharmony_ci		goto next;
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci/**
8378c2ecf20Sopenharmony_ci * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry.
8388c2ecf20Sopenharmony_ci *
8398c2ecf20Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_head".
8408c2ecf20Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_head".
8418c2ecf20Sopenharmony_ci *
8428c2ecf20Sopenharmony_ci * Returns true if @a == @b, false otherwise.
8438c2ecf20Sopenharmony_ci */
8448c2ecf20Sopenharmony_cistatic bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
8458c2ecf20Sopenharmony_ci				const struct tomoyo_acl_head *b)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	return container_of(a, struct tomoyo_manager, head)->manager ==
8488c2ecf20Sopenharmony_ci		container_of(b, struct tomoyo_manager, head)->manager;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci/**
8528c2ecf20Sopenharmony_ci * tomoyo_update_manager_entry - Add a manager entry.
8538c2ecf20Sopenharmony_ci *
8548c2ecf20Sopenharmony_ci * @manager:   The path to manager or the domainnamme.
8558c2ecf20Sopenharmony_ci * @is_delete: True if it is a delete request.
8568c2ecf20Sopenharmony_ci *
8578c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
8588c2ecf20Sopenharmony_ci *
8598c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
8608c2ecf20Sopenharmony_ci */
8618c2ecf20Sopenharmony_cistatic int tomoyo_update_manager_entry(const char *manager,
8628c2ecf20Sopenharmony_ci				       const bool is_delete)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	struct tomoyo_manager e = { };
8658c2ecf20Sopenharmony_ci	struct tomoyo_acl_param param = {
8668c2ecf20Sopenharmony_ci		/* .ns = &tomoyo_kernel_namespace, */
8678c2ecf20Sopenharmony_ci		.is_delete = is_delete,
8688c2ecf20Sopenharmony_ci		.list = &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER],
8698c2ecf20Sopenharmony_ci	};
8708c2ecf20Sopenharmony_ci	int error = is_delete ? -ENOENT : -ENOMEM;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (!tomoyo_correct_domain(manager) &&
8738c2ecf20Sopenharmony_ci	    !tomoyo_correct_word(manager))
8748c2ecf20Sopenharmony_ci		return -EINVAL;
8758c2ecf20Sopenharmony_ci	e.manager = tomoyo_get_name(manager);
8768c2ecf20Sopenharmony_ci	if (e.manager) {
8778c2ecf20Sopenharmony_ci		error = tomoyo_update_policy(&e.head, sizeof(e), &param,
8788c2ecf20Sopenharmony_ci					     tomoyo_same_manager);
8798c2ecf20Sopenharmony_ci		tomoyo_put_name(e.manager);
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci	return error;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci/**
8858c2ecf20Sopenharmony_ci * tomoyo_write_manager - Write manager policy.
8868c2ecf20Sopenharmony_ci *
8878c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
8888c2ecf20Sopenharmony_ci *
8898c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
8908c2ecf20Sopenharmony_ci *
8918c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
8928c2ecf20Sopenharmony_ci */
8938c2ecf20Sopenharmony_cistatic int tomoyo_write_manager(struct tomoyo_io_buffer *head)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	char *data = head->write_buf;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if (!strcmp(data, "manage_by_non_root")) {
8988c2ecf20Sopenharmony_ci		tomoyo_manage_by_non_root = !head->w.is_delete;
8998c2ecf20Sopenharmony_ci		return 0;
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci	return tomoyo_update_manager_entry(data, head->w.is_delete);
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci/**
9058c2ecf20Sopenharmony_ci * tomoyo_read_manager - Read manager policy.
9068c2ecf20Sopenharmony_ci *
9078c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
9088c2ecf20Sopenharmony_ci *
9098c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
9108c2ecf20Sopenharmony_ci */
9118c2ecf20Sopenharmony_cistatic void tomoyo_read_manager(struct tomoyo_io_buffer *head)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	if (head->r.eof)
9148c2ecf20Sopenharmony_ci		return;
9158c2ecf20Sopenharmony_ci	list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER]) {
9168c2ecf20Sopenharmony_ci		struct tomoyo_manager *ptr =
9178c2ecf20Sopenharmony_ci			list_entry(head->r.acl, typeof(*ptr), head.list);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		if (ptr->head.is_deleted)
9208c2ecf20Sopenharmony_ci			continue;
9218c2ecf20Sopenharmony_ci		if (!tomoyo_flush(head))
9228c2ecf20Sopenharmony_ci			return;
9238c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->manager->name);
9248c2ecf20Sopenharmony_ci		tomoyo_set_lf(head);
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci	head->r.eof = true;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci/**
9308c2ecf20Sopenharmony_ci * tomoyo_manager - Check whether the current process is a policy manager.
9318c2ecf20Sopenharmony_ci *
9328c2ecf20Sopenharmony_ci * Returns true if the current process is permitted to modify policy
9338c2ecf20Sopenharmony_ci * via /sys/kernel/security/tomoyo/ interface.
9348c2ecf20Sopenharmony_ci *
9358c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
9368c2ecf20Sopenharmony_ci */
9378c2ecf20Sopenharmony_cistatic bool tomoyo_manager(void)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	struct tomoyo_manager *ptr;
9408c2ecf20Sopenharmony_ci	const char *exe;
9418c2ecf20Sopenharmony_ci	const struct task_struct *task = current;
9428c2ecf20Sopenharmony_ci	const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
9438c2ecf20Sopenharmony_ci	bool found = IS_ENABLED(CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	if (!tomoyo_policy_loaded)
9468c2ecf20Sopenharmony_ci		return true;
9478c2ecf20Sopenharmony_ci	if (!tomoyo_manage_by_non_root &&
9488c2ecf20Sopenharmony_ci	    (!uid_eq(task->cred->uid,  GLOBAL_ROOT_UID) ||
9498c2ecf20Sopenharmony_ci	     !uid_eq(task->cred->euid, GLOBAL_ROOT_UID)))
9508c2ecf20Sopenharmony_ci		return false;
9518c2ecf20Sopenharmony_ci	exe = tomoyo_get_exe();
9528c2ecf20Sopenharmony_ci	if (!exe)
9538c2ecf20Sopenharmony_ci		return false;
9548c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], head.list,
9558c2ecf20Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
9568c2ecf20Sopenharmony_ci		if (!ptr->head.is_deleted &&
9578c2ecf20Sopenharmony_ci		    (!tomoyo_pathcmp(domainname, ptr->manager) ||
9588c2ecf20Sopenharmony_ci		     !strcmp(exe, ptr->manager->name))) {
9598c2ecf20Sopenharmony_ci			found = true;
9608c2ecf20Sopenharmony_ci			break;
9618c2ecf20Sopenharmony_ci		}
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci	if (!found) { /* Reduce error messages. */
9648c2ecf20Sopenharmony_ci		static pid_t last_pid;
9658c2ecf20Sopenharmony_ci		const pid_t pid = current->pid;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci		if (last_pid != pid) {
9688c2ecf20Sopenharmony_ci			pr_warn("%s ( %s ) is not permitted to update policies.\n",
9698c2ecf20Sopenharmony_ci				domainname->name, exe);
9708c2ecf20Sopenharmony_ci			last_pid = pid;
9718c2ecf20Sopenharmony_ci		}
9728c2ecf20Sopenharmony_ci	}
9738c2ecf20Sopenharmony_ci	kfree(exe);
9748c2ecf20Sopenharmony_ci	return found;
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic struct tomoyo_domain_info *tomoyo_find_domain_by_qid
9788c2ecf20Sopenharmony_ci(unsigned int serial);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci/**
9818c2ecf20Sopenharmony_ci * tomoyo_select_domain - Parse select command.
9828c2ecf20Sopenharmony_ci *
9838c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
9848c2ecf20Sopenharmony_ci * @data: String to parse.
9858c2ecf20Sopenharmony_ci *
9868c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
9878c2ecf20Sopenharmony_ci *
9888c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_cistatic bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
9918c2ecf20Sopenharmony_ci				 const char *data)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	unsigned int pid;
9948c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain = NULL;
9958c2ecf20Sopenharmony_ci	bool global_pid = false;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	if (strncmp(data, "select ", 7))
9988c2ecf20Sopenharmony_ci		return false;
9998c2ecf20Sopenharmony_ci	data += 7;
10008c2ecf20Sopenharmony_ci	if (sscanf(data, "pid=%u", &pid) == 1 ||
10018c2ecf20Sopenharmony_ci	    (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
10028c2ecf20Sopenharmony_ci		struct task_struct *p;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci		rcu_read_lock();
10058c2ecf20Sopenharmony_ci		if (global_pid)
10068c2ecf20Sopenharmony_ci			p = find_task_by_pid_ns(pid, &init_pid_ns);
10078c2ecf20Sopenharmony_ci		else
10088c2ecf20Sopenharmony_ci			p = find_task_by_vpid(pid);
10098c2ecf20Sopenharmony_ci		if (p)
10108c2ecf20Sopenharmony_ci			domain = tomoyo_task(p)->domain_info;
10118c2ecf20Sopenharmony_ci		rcu_read_unlock();
10128c2ecf20Sopenharmony_ci	} else if (!strncmp(data, "domain=", 7)) {
10138c2ecf20Sopenharmony_ci		if (tomoyo_domain_def(data + 7))
10148c2ecf20Sopenharmony_ci			domain = tomoyo_find_domain(data + 7);
10158c2ecf20Sopenharmony_ci	} else if (sscanf(data, "Q=%u", &pid) == 1) {
10168c2ecf20Sopenharmony_ci		domain = tomoyo_find_domain_by_qid(pid);
10178c2ecf20Sopenharmony_ci	} else
10188c2ecf20Sopenharmony_ci		return false;
10198c2ecf20Sopenharmony_ci	head->w.domain = domain;
10208c2ecf20Sopenharmony_ci	/* Accessing read_buf is safe because head->io_sem is held. */
10218c2ecf20Sopenharmony_ci	if (!head->read_buf)
10228c2ecf20Sopenharmony_ci		return true; /* Do nothing if open(O_WRONLY). */
10238c2ecf20Sopenharmony_ci	memset(&head->r, 0, sizeof(head->r));
10248c2ecf20Sopenharmony_ci	head->r.print_this_domain_only = true;
10258c2ecf20Sopenharmony_ci	if (domain)
10268c2ecf20Sopenharmony_ci		head->r.domain = &domain->list;
10278c2ecf20Sopenharmony_ci	else
10288c2ecf20Sopenharmony_ci		head->r.eof = true;
10298c2ecf20Sopenharmony_ci	tomoyo_io_printf(head, "# select %s\n", data);
10308c2ecf20Sopenharmony_ci	if (domain && domain->is_deleted)
10318c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "# This is a deleted domain.\n");
10328c2ecf20Sopenharmony_ci	return true;
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci/**
10368c2ecf20Sopenharmony_ci * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry.
10378c2ecf20Sopenharmony_ci *
10388c2ecf20Sopenharmony_ci * @a: Pointer to "struct tomoyo_acl_info".
10398c2ecf20Sopenharmony_ci * @b: Pointer to "struct tomoyo_acl_info".
10408c2ecf20Sopenharmony_ci *
10418c2ecf20Sopenharmony_ci * Returns true if @a == @b, false otherwise.
10428c2ecf20Sopenharmony_ci */
10438c2ecf20Sopenharmony_cistatic bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
10448c2ecf20Sopenharmony_ci				 const struct tomoyo_acl_info *b)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
10478c2ecf20Sopenharmony_ci	const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return p1->domainname == p2->domainname;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci/**
10538c2ecf20Sopenharmony_ci * tomoyo_write_task - Update task related list.
10548c2ecf20Sopenharmony_ci *
10558c2ecf20Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
10568c2ecf20Sopenharmony_ci *
10578c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
10588c2ecf20Sopenharmony_ci *
10598c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
10608c2ecf20Sopenharmony_ci */
10618c2ecf20Sopenharmony_cistatic int tomoyo_write_task(struct tomoyo_acl_param *param)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	int error = -EINVAL;
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
10668c2ecf20Sopenharmony_ci		struct tomoyo_task_acl e = {
10678c2ecf20Sopenharmony_ci			.head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
10688c2ecf20Sopenharmony_ci			.domainname = tomoyo_get_domainname(param),
10698c2ecf20Sopenharmony_ci		};
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci		if (e.domainname)
10728c2ecf20Sopenharmony_ci			error = tomoyo_update_domain(&e.head, sizeof(e), param,
10738c2ecf20Sopenharmony_ci						     tomoyo_same_task_acl,
10748c2ecf20Sopenharmony_ci						     NULL);
10758c2ecf20Sopenharmony_ci		tomoyo_put_name(e.domainname);
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci	return error;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci/**
10818c2ecf20Sopenharmony_ci * tomoyo_delete_domain - Delete a domain.
10828c2ecf20Sopenharmony_ci *
10838c2ecf20Sopenharmony_ci * @domainname: The name of domain.
10848c2ecf20Sopenharmony_ci *
10858c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
10868c2ecf20Sopenharmony_ci *
10878c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
10888c2ecf20Sopenharmony_ci */
10898c2ecf20Sopenharmony_cistatic int tomoyo_delete_domain(char *domainname)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain;
10928c2ecf20Sopenharmony_ci	struct tomoyo_path_info name;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	name.name = domainname;
10958c2ecf20Sopenharmony_ci	tomoyo_fill_path_info(&name);
10968c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&tomoyo_policy_lock))
10978c2ecf20Sopenharmony_ci		return -EINTR;
10988c2ecf20Sopenharmony_ci	/* Is there an active domain? */
10998c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
11008c2ecf20Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
11018c2ecf20Sopenharmony_ci		/* Never delete tomoyo_kernel_domain */
11028c2ecf20Sopenharmony_ci		if (domain == &tomoyo_kernel_domain)
11038c2ecf20Sopenharmony_ci			continue;
11048c2ecf20Sopenharmony_ci		if (domain->is_deleted ||
11058c2ecf20Sopenharmony_ci		    tomoyo_pathcmp(domain->domainname, &name))
11068c2ecf20Sopenharmony_ci			continue;
11078c2ecf20Sopenharmony_ci		domain->is_deleted = true;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci	mutex_unlock(&tomoyo_policy_lock);
11118c2ecf20Sopenharmony_ci	return 0;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci/**
11158c2ecf20Sopenharmony_ci * tomoyo_write_domain2 - Write domain policy.
11168c2ecf20Sopenharmony_ci *
11178c2ecf20Sopenharmony_ci * @ns:        Pointer to "struct tomoyo_policy_namespace".
11188c2ecf20Sopenharmony_ci * @list:      Pointer to "struct list_head".
11198c2ecf20Sopenharmony_ci * @data:      Policy to be interpreted.
11208c2ecf20Sopenharmony_ci * @is_delete: True if it is a delete request.
11218c2ecf20Sopenharmony_ci *
11228c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
11238c2ecf20Sopenharmony_ci *
11248c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
11258c2ecf20Sopenharmony_ci */
11268c2ecf20Sopenharmony_cistatic int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
11278c2ecf20Sopenharmony_ci				struct list_head *list, char *data,
11288c2ecf20Sopenharmony_ci				const bool is_delete)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct tomoyo_acl_param param = {
11318c2ecf20Sopenharmony_ci		.ns = ns,
11328c2ecf20Sopenharmony_ci		.list = list,
11338c2ecf20Sopenharmony_ci		.data = data,
11348c2ecf20Sopenharmony_ci		.is_delete = is_delete,
11358c2ecf20Sopenharmony_ci	};
11368c2ecf20Sopenharmony_ci	static const struct {
11378c2ecf20Sopenharmony_ci		const char *keyword;
11388c2ecf20Sopenharmony_ci		int (*write)(struct tomoyo_acl_param *param);
11398c2ecf20Sopenharmony_ci	} tomoyo_callback[5] = {
11408c2ecf20Sopenharmony_ci		{ "file ", tomoyo_write_file },
11418c2ecf20Sopenharmony_ci		{ "network inet ", tomoyo_write_inet_network },
11428c2ecf20Sopenharmony_ci		{ "network unix ", tomoyo_write_unix_network },
11438c2ecf20Sopenharmony_ci		{ "misc ", tomoyo_write_misc },
11448c2ecf20Sopenharmony_ci		{ "task ", tomoyo_write_task },
11458c2ecf20Sopenharmony_ci	};
11468c2ecf20Sopenharmony_ci	u8 i;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) {
11498c2ecf20Sopenharmony_ci		if (!tomoyo_str_starts(&param.data,
11508c2ecf20Sopenharmony_ci				       tomoyo_callback[i].keyword))
11518c2ecf20Sopenharmony_ci			continue;
11528c2ecf20Sopenharmony_ci		return tomoyo_callback[i].write(&param);
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci	return -EINVAL;
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci/* String table for domain flags. */
11588c2ecf20Sopenharmony_ciconst char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = {
11598c2ecf20Sopenharmony_ci	[TOMOYO_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
11608c2ecf20Sopenharmony_ci	[TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n",
11618c2ecf20Sopenharmony_ci};
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci/**
11648c2ecf20Sopenharmony_ci * tomoyo_write_domain - Write domain policy.
11658c2ecf20Sopenharmony_ci *
11668c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
11678c2ecf20Sopenharmony_ci *
11688c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
11698c2ecf20Sopenharmony_ci *
11708c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
11718c2ecf20Sopenharmony_ci */
11728c2ecf20Sopenharmony_cistatic int tomoyo_write_domain(struct tomoyo_io_buffer *head)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	char *data = head->write_buf;
11758c2ecf20Sopenharmony_ci	struct tomoyo_policy_namespace *ns;
11768c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain = head->w.domain;
11778c2ecf20Sopenharmony_ci	const bool is_delete = head->w.is_delete;
11788c2ecf20Sopenharmony_ci	bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
11798c2ecf20Sopenharmony_ci	unsigned int idx;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	if (*data == '<') {
11828c2ecf20Sopenharmony_ci		int ret = 0;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		domain = NULL;
11858c2ecf20Sopenharmony_ci		if (is_delete)
11868c2ecf20Sopenharmony_ci			ret = tomoyo_delete_domain(data);
11878c2ecf20Sopenharmony_ci		else if (is_select)
11888c2ecf20Sopenharmony_ci			domain = tomoyo_find_domain(data);
11898c2ecf20Sopenharmony_ci		else
11908c2ecf20Sopenharmony_ci			domain = tomoyo_assign_domain(data, false);
11918c2ecf20Sopenharmony_ci		head->w.domain = domain;
11928c2ecf20Sopenharmony_ci		return ret;
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci	if (!domain)
11958c2ecf20Sopenharmony_ci		return -EINVAL;
11968c2ecf20Sopenharmony_ci	ns = domain->ns;
11978c2ecf20Sopenharmony_ci	if (sscanf(data, "use_profile %u", &idx) == 1
11988c2ecf20Sopenharmony_ci	    && idx < TOMOYO_MAX_PROFILES) {
11998c2ecf20Sopenharmony_ci		if (!tomoyo_policy_loaded || ns->profile_ptr[idx])
12008c2ecf20Sopenharmony_ci			if (!is_delete)
12018c2ecf20Sopenharmony_ci				domain->profile = (u8) idx;
12028c2ecf20Sopenharmony_ci		return 0;
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci	if (sscanf(data, "use_group %u\n", &idx) == 1
12058c2ecf20Sopenharmony_ci	    && idx < TOMOYO_MAX_ACL_GROUPS) {
12068c2ecf20Sopenharmony_ci		if (!is_delete)
12078c2ecf20Sopenharmony_ci			set_bit(idx, domain->group);
12088c2ecf20Sopenharmony_ci		else
12098c2ecf20Sopenharmony_ci			clear_bit(idx, domain->group);
12108c2ecf20Sopenharmony_ci		return 0;
12118c2ecf20Sopenharmony_ci	}
12128c2ecf20Sopenharmony_ci	for (idx = 0; idx < TOMOYO_MAX_DOMAIN_INFO_FLAGS; idx++) {
12138c2ecf20Sopenharmony_ci		const char *cp = tomoyo_dif[idx];
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci		if (strncmp(data, cp, strlen(cp) - 1))
12168c2ecf20Sopenharmony_ci			continue;
12178c2ecf20Sopenharmony_ci		domain->flags[idx] = !is_delete;
12188c2ecf20Sopenharmony_ci		return 0;
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci	return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
12218c2ecf20Sopenharmony_ci				    is_delete);
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci/**
12258c2ecf20Sopenharmony_ci * tomoyo_print_condition - Print condition part.
12268c2ecf20Sopenharmony_ci *
12278c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
12288c2ecf20Sopenharmony_ci * @cond: Pointer to "struct tomoyo_condition".
12298c2ecf20Sopenharmony_ci *
12308c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
12318c2ecf20Sopenharmony_ci */
12328c2ecf20Sopenharmony_cistatic bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
12338c2ecf20Sopenharmony_ci				   const struct tomoyo_condition *cond)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	switch (head->r.cond_step) {
12368c2ecf20Sopenharmony_ci	case 0:
12378c2ecf20Sopenharmony_ci		head->r.cond_index = 0;
12388c2ecf20Sopenharmony_ci		head->r.cond_step++;
12398c2ecf20Sopenharmony_ci		if (cond->transit) {
12408c2ecf20Sopenharmony_ci			tomoyo_set_space(head);
12418c2ecf20Sopenharmony_ci			tomoyo_set_string(head, cond->transit->name);
12428c2ecf20Sopenharmony_ci		}
12438c2ecf20Sopenharmony_ci		fallthrough;
12448c2ecf20Sopenharmony_ci	case 1:
12458c2ecf20Sopenharmony_ci		{
12468c2ecf20Sopenharmony_ci			const u16 condc = cond->condc;
12478c2ecf20Sopenharmony_ci			const struct tomoyo_condition_element *condp =
12488c2ecf20Sopenharmony_ci				(typeof(condp)) (cond + 1);
12498c2ecf20Sopenharmony_ci			const struct tomoyo_number_union *numbers_p =
12508c2ecf20Sopenharmony_ci				(typeof(numbers_p)) (condp + condc);
12518c2ecf20Sopenharmony_ci			const struct tomoyo_name_union *names_p =
12528c2ecf20Sopenharmony_ci				(typeof(names_p))
12538c2ecf20Sopenharmony_ci				(numbers_p + cond->numbers_count);
12548c2ecf20Sopenharmony_ci			const struct tomoyo_argv *argv =
12558c2ecf20Sopenharmony_ci				(typeof(argv)) (names_p + cond->names_count);
12568c2ecf20Sopenharmony_ci			const struct tomoyo_envp *envp =
12578c2ecf20Sopenharmony_ci				(typeof(envp)) (argv + cond->argc);
12588c2ecf20Sopenharmony_ci			u16 skip;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci			for (skip = 0; skip < head->r.cond_index; skip++) {
12618c2ecf20Sopenharmony_ci				const u8 left = condp->left;
12628c2ecf20Sopenharmony_ci				const u8 right = condp->right;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci				condp++;
12658c2ecf20Sopenharmony_ci				switch (left) {
12668c2ecf20Sopenharmony_ci				case TOMOYO_ARGV_ENTRY:
12678c2ecf20Sopenharmony_ci					argv++;
12688c2ecf20Sopenharmony_ci					continue;
12698c2ecf20Sopenharmony_ci				case TOMOYO_ENVP_ENTRY:
12708c2ecf20Sopenharmony_ci					envp++;
12718c2ecf20Sopenharmony_ci					continue;
12728c2ecf20Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
12738c2ecf20Sopenharmony_ci					numbers_p++;
12748c2ecf20Sopenharmony_ci					break;
12758c2ecf20Sopenharmony_ci				}
12768c2ecf20Sopenharmony_ci				switch (right) {
12778c2ecf20Sopenharmony_ci				case TOMOYO_NAME_UNION:
12788c2ecf20Sopenharmony_ci					names_p++;
12798c2ecf20Sopenharmony_ci					break;
12808c2ecf20Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
12818c2ecf20Sopenharmony_ci					numbers_p++;
12828c2ecf20Sopenharmony_ci					break;
12838c2ecf20Sopenharmony_ci				}
12848c2ecf20Sopenharmony_ci			}
12858c2ecf20Sopenharmony_ci			while (head->r.cond_index < condc) {
12868c2ecf20Sopenharmony_ci				const u8 match = condp->equals;
12878c2ecf20Sopenharmony_ci				const u8 left = condp->left;
12888c2ecf20Sopenharmony_ci				const u8 right = condp->right;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci				if (!tomoyo_flush(head))
12918c2ecf20Sopenharmony_ci					return false;
12928c2ecf20Sopenharmony_ci				condp++;
12938c2ecf20Sopenharmony_ci				head->r.cond_index++;
12948c2ecf20Sopenharmony_ci				tomoyo_set_space(head);
12958c2ecf20Sopenharmony_ci				switch (left) {
12968c2ecf20Sopenharmony_ci				case TOMOYO_ARGV_ENTRY:
12978c2ecf20Sopenharmony_ci					tomoyo_io_printf(head,
12988c2ecf20Sopenharmony_ci							 "exec.argv[%lu]%s=\"",
12998c2ecf20Sopenharmony_ci							 argv->index, argv->is_not ? "!" : "");
13008c2ecf20Sopenharmony_ci					tomoyo_set_string(head,
13018c2ecf20Sopenharmony_ci							  argv->value->name);
13028c2ecf20Sopenharmony_ci					tomoyo_set_string(head, "\"");
13038c2ecf20Sopenharmony_ci					argv++;
13048c2ecf20Sopenharmony_ci					continue;
13058c2ecf20Sopenharmony_ci				case TOMOYO_ENVP_ENTRY:
13068c2ecf20Sopenharmony_ci					tomoyo_set_string(head,
13078c2ecf20Sopenharmony_ci							  "exec.envp[\"");
13088c2ecf20Sopenharmony_ci					tomoyo_set_string(head,
13098c2ecf20Sopenharmony_ci							  envp->name->name);
13108c2ecf20Sopenharmony_ci					tomoyo_io_printf(head, "\"]%s=", envp->is_not ? "!" : "");
13118c2ecf20Sopenharmony_ci					if (envp->value) {
13128c2ecf20Sopenharmony_ci						tomoyo_set_string(head, "\"");
13138c2ecf20Sopenharmony_ci						tomoyo_set_string(head, envp->value->name);
13148c2ecf20Sopenharmony_ci						tomoyo_set_string(head, "\"");
13158c2ecf20Sopenharmony_ci					} else {
13168c2ecf20Sopenharmony_ci						tomoyo_set_string(head,
13178c2ecf20Sopenharmony_ci								  "NULL");
13188c2ecf20Sopenharmony_ci					}
13198c2ecf20Sopenharmony_ci					envp++;
13208c2ecf20Sopenharmony_ci					continue;
13218c2ecf20Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
13228c2ecf20Sopenharmony_ci					tomoyo_print_number_union_nospace
13238c2ecf20Sopenharmony_ci						(head, numbers_p++);
13248c2ecf20Sopenharmony_ci					break;
13258c2ecf20Sopenharmony_ci				default:
13268c2ecf20Sopenharmony_ci					tomoyo_set_string(head,
13278c2ecf20Sopenharmony_ci					       tomoyo_condition_keyword[left]);
13288c2ecf20Sopenharmony_ci					break;
13298c2ecf20Sopenharmony_ci				}
13308c2ecf20Sopenharmony_ci				tomoyo_set_string(head, match ? "=" : "!=");
13318c2ecf20Sopenharmony_ci				switch (right) {
13328c2ecf20Sopenharmony_ci				case TOMOYO_NAME_UNION:
13338c2ecf20Sopenharmony_ci					tomoyo_print_name_union_quoted
13348c2ecf20Sopenharmony_ci						(head, names_p++);
13358c2ecf20Sopenharmony_ci					break;
13368c2ecf20Sopenharmony_ci				case TOMOYO_NUMBER_UNION:
13378c2ecf20Sopenharmony_ci					tomoyo_print_number_union_nospace
13388c2ecf20Sopenharmony_ci						(head, numbers_p++);
13398c2ecf20Sopenharmony_ci					break;
13408c2ecf20Sopenharmony_ci				default:
13418c2ecf20Sopenharmony_ci					tomoyo_set_string(head,
13428c2ecf20Sopenharmony_ci					  tomoyo_condition_keyword[right]);
13438c2ecf20Sopenharmony_ci					break;
13448c2ecf20Sopenharmony_ci				}
13458c2ecf20Sopenharmony_ci			}
13468c2ecf20Sopenharmony_ci		}
13478c2ecf20Sopenharmony_ci		head->r.cond_step++;
13488c2ecf20Sopenharmony_ci		fallthrough;
13498c2ecf20Sopenharmony_ci	case 2:
13508c2ecf20Sopenharmony_ci		if (!tomoyo_flush(head))
13518c2ecf20Sopenharmony_ci			break;
13528c2ecf20Sopenharmony_ci		head->r.cond_step++;
13538c2ecf20Sopenharmony_ci		fallthrough;
13548c2ecf20Sopenharmony_ci	case 3:
13558c2ecf20Sopenharmony_ci		if (cond->grant_log != TOMOYO_GRANTLOG_AUTO)
13568c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, " grant_log=%s",
13578c2ecf20Sopenharmony_ci					 tomoyo_yesno(cond->grant_log ==
13588c2ecf20Sopenharmony_ci						      TOMOYO_GRANTLOG_YES));
13598c2ecf20Sopenharmony_ci		tomoyo_set_lf(head);
13608c2ecf20Sopenharmony_ci		return true;
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci	return false;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci/**
13668c2ecf20Sopenharmony_ci * tomoyo_set_group - Print "acl_group " header keyword and category name.
13678c2ecf20Sopenharmony_ci *
13688c2ecf20Sopenharmony_ci * @head:     Pointer to "struct tomoyo_io_buffer".
13698c2ecf20Sopenharmony_ci * @category: Category name.
13708c2ecf20Sopenharmony_ci *
13718c2ecf20Sopenharmony_ci * Returns nothing.
13728c2ecf20Sopenharmony_ci */
13738c2ecf20Sopenharmony_cistatic void tomoyo_set_group(struct tomoyo_io_buffer *head,
13748c2ecf20Sopenharmony_ci			     const char *category)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	if (head->type == TOMOYO_EXCEPTIONPOLICY) {
13778c2ecf20Sopenharmony_ci		tomoyo_print_namespace(head);
13788c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "acl_group %u ",
13798c2ecf20Sopenharmony_ci				 head->r.acl_group_index);
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci	tomoyo_set_string(head, category);
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci/**
13858c2ecf20Sopenharmony_ci * tomoyo_print_entry - Print an ACL entry.
13868c2ecf20Sopenharmony_ci *
13878c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
13888c2ecf20Sopenharmony_ci * @acl:  Pointer to an ACL entry.
13898c2ecf20Sopenharmony_ci *
13908c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
13918c2ecf20Sopenharmony_ci */
13928c2ecf20Sopenharmony_cistatic bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
13938c2ecf20Sopenharmony_ci			       struct tomoyo_acl_info *acl)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	const u8 acl_type = acl->type;
13968c2ecf20Sopenharmony_ci	bool first = true;
13978c2ecf20Sopenharmony_ci	u8 bit;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	if (head->r.print_cond_part)
14008c2ecf20Sopenharmony_ci		goto print_cond_part;
14018c2ecf20Sopenharmony_ci	if (acl->is_deleted)
14028c2ecf20Sopenharmony_ci		return true;
14038c2ecf20Sopenharmony_ci	if (!tomoyo_flush(head))
14048c2ecf20Sopenharmony_ci		return false;
14058c2ecf20Sopenharmony_ci	else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
14068c2ecf20Sopenharmony_ci		struct tomoyo_path_acl *ptr =
14078c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
14088c2ecf20Sopenharmony_ci		const u16 perm = ptr->perm;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
14118c2ecf20Sopenharmony_ci			if (!(perm & (1 << bit)))
14128c2ecf20Sopenharmony_ci				continue;
14138c2ecf20Sopenharmony_ci			if (head->r.print_transition_related_only &&
14148c2ecf20Sopenharmony_ci			    bit != TOMOYO_TYPE_EXECUTE)
14158c2ecf20Sopenharmony_ci				continue;
14168c2ecf20Sopenharmony_ci			if (first) {
14178c2ecf20Sopenharmony_ci				tomoyo_set_group(head, "file ");
14188c2ecf20Sopenharmony_ci				first = false;
14198c2ecf20Sopenharmony_ci			} else {
14208c2ecf20Sopenharmony_ci				tomoyo_set_slash(head);
14218c2ecf20Sopenharmony_ci			}
14228c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_path_keyword[bit]);
14238c2ecf20Sopenharmony_ci		}
14248c2ecf20Sopenharmony_ci		if (first)
14258c2ecf20Sopenharmony_ci			return true;
14268c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
14278c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
14288c2ecf20Sopenharmony_ci		struct tomoyo_task_acl *ptr =
14298c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci		tomoyo_set_group(head, "task ");
14328c2ecf20Sopenharmony_ci		tomoyo_set_string(head, "manual_domain_transition ");
14338c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->domainname->name);
14348c2ecf20Sopenharmony_ci	} else if (head->r.print_transition_related_only) {
14358c2ecf20Sopenharmony_ci		return true;
14368c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
14378c2ecf20Sopenharmony_ci		struct tomoyo_path2_acl *ptr =
14388c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
14398c2ecf20Sopenharmony_ci		const u8 perm = ptr->perm;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
14428c2ecf20Sopenharmony_ci			if (!(perm & (1 << bit)))
14438c2ecf20Sopenharmony_ci				continue;
14448c2ecf20Sopenharmony_ci			if (first) {
14458c2ecf20Sopenharmony_ci				tomoyo_set_group(head, "file ");
14468c2ecf20Sopenharmony_ci				first = false;
14478c2ecf20Sopenharmony_ci			} else {
14488c2ecf20Sopenharmony_ci				tomoyo_set_slash(head);
14498c2ecf20Sopenharmony_ci			}
14508c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_mac_keywords
14518c2ecf20Sopenharmony_ci					  [tomoyo_pp2mac[bit]]);
14528c2ecf20Sopenharmony_ci		}
14538c2ecf20Sopenharmony_ci		if (first)
14548c2ecf20Sopenharmony_ci			return true;
14558c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name1);
14568c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name2);
14578c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
14588c2ecf20Sopenharmony_ci		struct tomoyo_path_number_acl *ptr =
14598c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
14608c2ecf20Sopenharmony_ci		const u8 perm = ptr->perm;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) {
14638c2ecf20Sopenharmony_ci			if (!(perm & (1 << bit)))
14648c2ecf20Sopenharmony_ci				continue;
14658c2ecf20Sopenharmony_ci			if (first) {
14668c2ecf20Sopenharmony_ci				tomoyo_set_group(head, "file ");
14678c2ecf20Sopenharmony_ci				first = false;
14688c2ecf20Sopenharmony_ci			} else {
14698c2ecf20Sopenharmony_ci				tomoyo_set_slash(head);
14708c2ecf20Sopenharmony_ci			}
14718c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_mac_keywords
14728c2ecf20Sopenharmony_ci					  [tomoyo_pn2mac[bit]]);
14738c2ecf20Sopenharmony_ci		}
14748c2ecf20Sopenharmony_ci		if (first)
14758c2ecf20Sopenharmony_ci			return true;
14768c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
14778c2ecf20Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->number);
14788c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
14798c2ecf20Sopenharmony_ci		struct tomoyo_mkdev_acl *ptr =
14808c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
14818c2ecf20Sopenharmony_ci		const u8 perm = ptr->perm;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) {
14848c2ecf20Sopenharmony_ci			if (!(perm & (1 << bit)))
14858c2ecf20Sopenharmony_ci				continue;
14868c2ecf20Sopenharmony_ci			if (first) {
14878c2ecf20Sopenharmony_ci				tomoyo_set_group(head, "file ");
14888c2ecf20Sopenharmony_ci				first = false;
14898c2ecf20Sopenharmony_ci			} else {
14908c2ecf20Sopenharmony_ci				tomoyo_set_slash(head);
14918c2ecf20Sopenharmony_ci			}
14928c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_mac_keywords
14938c2ecf20Sopenharmony_ci					  [tomoyo_pnnn2mac[bit]]);
14948c2ecf20Sopenharmony_ci		}
14958c2ecf20Sopenharmony_ci		if (first)
14968c2ecf20Sopenharmony_ci			return true;
14978c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
14988c2ecf20Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->mode);
14998c2ecf20Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->major);
15008c2ecf20Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->minor);
15018c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_INET_ACL) {
15028c2ecf20Sopenharmony_ci		struct tomoyo_inet_acl *ptr =
15038c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
15048c2ecf20Sopenharmony_ci		const u8 perm = ptr->perm;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
15078c2ecf20Sopenharmony_ci			if (!(perm & (1 << bit)))
15088c2ecf20Sopenharmony_ci				continue;
15098c2ecf20Sopenharmony_ci			if (first) {
15108c2ecf20Sopenharmony_ci				tomoyo_set_group(head, "network inet ");
15118c2ecf20Sopenharmony_ci				tomoyo_set_string(head, tomoyo_proto_keyword
15128c2ecf20Sopenharmony_ci						  [ptr->protocol]);
15138c2ecf20Sopenharmony_ci				tomoyo_set_space(head);
15148c2ecf20Sopenharmony_ci				first = false;
15158c2ecf20Sopenharmony_ci			} else {
15168c2ecf20Sopenharmony_ci				tomoyo_set_slash(head);
15178c2ecf20Sopenharmony_ci			}
15188c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
15198c2ecf20Sopenharmony_ci		}
15208c2ecf20Sopenharmony_ci		if (first)
15218c2ecf20Sopenharmony_ci			return true;
15228c2ecf20Sopenharmony_ci		tomoyo_set_space(head);
15238c2ecf20Sopenharmony_ci		if (ptr->address.group) {
15248c2ecf20Sopenharmony_ci			tomoyo_set_string(head, "@");
15258c2ecf20Sopenharmony_ci			tomoyo_set_string(head, ptr->address.group->group_name
15268c2ecf20Sopenharmony_ci					  ->name);
15278c2ecf20Sopenharmony_ci		} else {
15288c2ecf20Sopenharmony_ci			char buf[128];
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci			tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
15318c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, "%s", buf);
15328c2ecf20Sopenharmony_ci		}
15338c2ecf20Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->port);
15348c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_UNIX_ACL) {
15358c2ecf20Sopenharmony_ci		struct tomoyo_unix_acl *ptr =
15368c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
15378c2ecf20Sopenharmony_ci		const u8 perm = ptr->perm;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci		for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
15408c2ecf20Sopenharmony_ci			if (!(perm & (1 << bit)))
15418c2ecf20Sopenharmony_ci				continue;
15428c2ecf20Sopenharmony_ci			if (first) {
15438c2ecf20Sopenharmony_ci				tomoyo_set_group(head, "network unix ");
15448c2ecf20Sopenharmony_ci				tomoyo_set_string(head, tomoyo_proto_keyword
15458c2ecf20Sopenharmony_ci						  [ptr->protocol]);
15468c2ecf20Sopenharmony_ci				tomoyo_set_space(head);
15478c2ecf20Sopenharmony_ci				first = false;
15488c2ecf20Sopenharmony_ci			} else {
15498c2ecf20Sopenharmony_ci				tomoyo_set_slash(head);
15508c2ecf20Sopenharmony_ci			}
15518c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
15528c2ecf20Sopenharmony_ci		}
15538c2ecf20Sopenharmony_ci		if (first)
15548c2ecf20Sopenharmony_ci			return true;
15558c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->name);
15568c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
15578c2ecf20Sopenharmony_ci		struct tomoyo_mount_acl *ptr =
15588c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci		tomoyo_set_group(head, "file mount");
15618c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->dev_name);
15628c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->dir_name);
15638c2ecf20Sopenharmony_ci		tomoyo_print_name_union(head, &ptr->fs_type);
15648c2ecf20Sopenharmony_ci		tomoyo_print_number_union(head, &ptr->flags);
15658c2ecf20Sopenharmony_ci	} else if (acl_type == TOMOYO_TYPE_ENV_ACL) {
15668c2ecf20Sopenharmony_ci		struct tomoyo_env_acl *ptr =
15678c2ecf20Sopenharmony_ci			container_of(acl, typeof(*ptr), head);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci		tomoyo_set_group(head, "misc env ");
15708c2ecf20Sopenharmony_ci		tomoyo_set_string(head, ptr->env->name);
15718c2ecf20Sopenharmony_ci	}
15728c2ecf20Sopenharmony_ci	if (acl->cond) {
15738c2ecf20Sopenharmony_ci		head->r.print_cond_part = true;
15748c2ecf20Sopenharmony_ci		head->r.cond_step = 0;
15758c2ecf20Sopenharmony_ci		if (!tomoyo_flush(head))
15768c2ecf20Sopenharmony_ci			return false;
15778c2ecf20Sopenharmony_ciprint_cond_part:
15788c2ecf20Sopenharmony_ci		if (!tomoyo_print_condition(head, acl->cond))
15798c2ecf20Sopenharmony_ci			return false;
15808c2ecf20Sopenharmony_ci		head->r.print_cond_part = false;
15818c2ecf20Sopenharmony_ci	} else {
15828c2ecf20Sopenharmony_ci		tomoyo_set_lf(head);
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci	return true;
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci/**
15888c2ecf20Sopenharmony_ci * tomoyo_read_domain2 - Read domain policy.
15898c2ecf20Sopenharmony_ci *
15908c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
15918c2ecf20Sopenharmony_ci * @list: Pointer to "struct list_head".
15928c2ecf20Sopenharmony_ci *
15938c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
15948c2ecf20Sopenharmony_ci *
15958c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
15968c2ecf20Sopenharmony_ci */
15978c2ecf20Sopenharmony_cistatic bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
15988c2ecf20Sopenharmony_ci				struct list_head *list)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	list_for_each_cookie(head->r.acl, list) {
16018c2ecf20Sopenharmony_ci		struct tomoyo_acl_info *ptr =
16028c2ecf20Sopenharmony_ci			list_entry(head->r.acl, typeof(*ptr), list);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci		if (!tomoyo_print_entry(head, ptr))
16058c2ecf20Sopenharmony_ci			return false;
16068c2ecf20Sopenharmony_ci	}
16078c2ecf20Sopenharmony_ci	head->r.acl = NULL;
16088c2ecf20Sopenharmony_ci	return true;
16098c2ecf20Sopenharmony_ci}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci/**
16128c2ecf20Sopenharmony_ci * tomoyo_read_domain - Read domain policy.
16138c2ecf20Sopenharmony_ci *
16148c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
16158c2ecf20Sopenharmony_ci *
16168c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
16178c2ecf20Sopenharmony_ci */
16188c2ecf20Sopenharmony_cistatic void tomoyo_read_domain(struct tomoyo_io_buffer *head)
16198c2ecf20Sopenharmony_ci{
16208c2ecf20Sopenharmony_ci	if (head->r.eof)
16218c2ecf20Sopenharmony_ci		return;
16228c2ecf20Sopenharmony_ci	list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
16238c2ecf20Sopenharmony_ci		struct tomoyo_domain_info *domain =
16248c2ecf20Sopenharmony_ci			list_entry(head->r.domain, typeof(*domain), list);
16258c2ecf20Sopenharmony_ci		u8 i;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci		switch (head->r.step) {
16288c2ecf20Sopenharmony_ci		case 0:
16298c2ecf20Sopenharmony_ci			if (domain->is_deleted &&
16308c2ecf20Sopenharmony_ci			    !head->r.print_this_domain_only)
16318c2ecf20Sopenharmony_ci				continue;
16328c2ecf20Sopenharmony_ci			/* Print domainname and flags. */
16338c2ecf20Sopenharmony_ci			tomoyo_set_string(head, domain->domainname->name);
16348c2ecf20Sopenharmony_ci			tomoyo_set_lf(head);
16358c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, "use_profile %u\n",
16368c2ecf20Sopenharmony_ci					 domain->profile);
16378c2ecf20Sopenharmony_ci			for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
16388c2ecf20Sopenharmony_ci				if (domain->flags[i])
16398c2ecf20Sopenharmony_ci					tomoyo_set_string(head, tomoyo_dif[i]);
16408c2ecf20Sopenharmony_ci			head->r.index = 0;
16418c2ecf20Sopenharmony_ci			head->r.step++;
16428c2ecf20Sopenharmony_ci			fallthrough;
16438c2ecf20Sopenharmony_ci		case 1:
16448c2ecf20Sopenharmony_ci			while (head->r.index < TOMOYO_MAX_ACL_GROUPS) {
16458c2ecf20Sopenharmony_ci				i = head->r.index++;
16468c2ecf20Sopenharmony_ci				if (!test_bit(i, domain->group))
16478c2ecf20Sopenharmony_ci					continue;
16488c2ecf20Sopenharmony_ci				tomoyo_io_printf(head, "use_group %u\n", i);
16498c2ecf20Sopenharmony_ci				if (!tomoyo_flush(head))
16508c2ecf20Sopenharmony_ci					return;
16518c2ecf20Sopenharmony_ci			}
16528c2ecf20Sopenharmony_ci			head->r.index = 0;
16538c2ecf20Sopenharmony_ci			head->r.step++;
16548c2ecf20Sopenharmony_ci			tomoyo_set_lf(head);
16558c2ecf20Sopenharmony_ci			fallthrough;
16568c2ecf20Sopenharmony_ci		case 2:
16578c2ecf20Sopenharmony_ci			if (!tomoyo_read_domain2(head, &domain->acl_info_list))
16588c2ecf20Sopenharmony_ci				return;
16598c2ecf20Sopenharmony_ci			head->r.step++;
16608c2ecf20Sopenharmony_ci			if (!tomoyo_set_lf(head))
16618c2ecf20Sopenharmony_ci				return;
16628c2ecf20Sopenharmony_ci			fallthrough;
16638c2ecf20Sopenharmony_ci		case 3:
16648c2ecf20Sopenharmony_ci			head->r.step = 0;
16658c2ecf20Sopenharmony_ci			if (head->r.print_this_domain_only)
16668c2ecf20Sopenharmony_ci				goto done;
16678c2ecf20Sopenharmony_ci		}
16688c2ecf20Sopenharmony_ci	}
16698c2ecf20Sopenharmony_ci done:
16708c2ecf20Sopenharmony_ci	head->r.eof = true;
16718c2ecf20Sopenharmony_ci}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci/**
16748c2ecf20Sopenharmony_ci * tomoyo_write_pid: Specify PID to obtain domainname.
16758c2ecf20Sopenharmony_ci *
16768c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
16778c2ecf20Sopenharmony_ci *
16788c2ecf20Sopenharmony_ci * Returns 0.
16798c2ecf20Sopenharmony_ci */
16808c2ecf20Sopenharmony_cistatic int tomoyo_write_pid(struct tomoyo_io_buffer *head)
16818c2ecf20Sopenharmony_ci{
16828c2ecf20Sopenharmony_ci	head->r.eof = false;
16838c2ecf20Sopenharmony_ci	return 0;
16848c2ecf20Sopenharmony_ci}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci/**
16878c2ecf20Sopenharmony_ci * tomoyo_read_pid - Get domainname of the specified PID.
16888c2ecf20Sopenharmony_ci *
16898c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
16908c2ecf20Sopenharmony_ci *
16918c2ecf20Sopenharmony_ci * Returns the domainname which the specified PID is in on success,
16928c2ecf20Sopenharmony_ci * empty string otherwise.
16938c2ecf20Sopenharmony_ci * The PID is specified by tomoyo_write_pid() so that the user can obtain
16948c2ecf20Sopenharmony_ci * using read()/write() interface rather than sysctl() interface.
16958c2ecf20Sopenharmony_ci */
16968c2ecf20Sopenharmony_cistatic void tomoyo_read_pid(struct tomoyo_io_buffer *head)
16978c2ecf20Sopenharmony_ci{
16988c2ecf20Sopenharmony_ci	char *buf = head->write_buf;
16998c2ecf20Sopenharmony_ci	bool global_pid = false;
17008c2ecf20Sopenharmony_ci	unsigned int pid;
17018c2ecf20Sopenharmony_ci	struct task_struct *p;
17028c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain = NULL;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	/* Accessing write_buf is safe because head->io_sem is held. */
17058c2ecf20Sopenharmony_ci	if (!buf) {
17068c2ecf20Sopenharmony_ci		head->r.eof = true;
17078c2ecf20Sopenharmony_ci		return; /* Do nothing if open(O_RDONLY). */
17088c2ecf20Sopenharmony_ci	}
17098c2ecf20Sopenharmony_ci	if (head->r.w_pos || head->r.eof)
17108c2ecf20Sopenharmony_ci		return;
17118c2ecf20Sopenharmony_ci	head->r.eof = true;
17128c2ecf20Sopenharmony_ci	if (tomoyo_str_starts(&buf, "global-pid "))
17138c2ecf20Sopenharmony_ci		global_pid = true;
17148c2ecf20Sopenharmony_ci	if (kstrtouint(buf, 10, &pid))
17158c2ecf20Sopenharmony_ci		return;
17168c2ecf20Sopenharmony_ci	rcu_read_lock();
17178c2ecf20Sopenharmony_ci	if (global_pid)
17188c2ecf20Sopenharmony_ci		p = find_task_by_pid_ns(pid, &init_pid_ns);
17198c2ecf20Sopenharmony_ci	else
17208c2ecf20Sopenharmony_ci		p = find_task_by_vpid(pid);
17218c2ecf20Sopenharmony_ci	if (p)
17228c2ecf20Sopenharmony_ci		domain = tomoyo_task(p)->domain_info;
17238c2ecf20Sopenharmony_ci	rcu_read_unlock();
17248c2ecf20Sopenharmony_ci	if (!domain)
17258c2ecf20Sopenharmony_ci		return;
17268c2ecf20Sopenharmony_ci	tomoyo_io_printf(head, "%u %u ", pid, domain->profile);
17278c2ecf20Sopenharmony_ci	tomoyo_set_string(head, domain->domainname->name);
17288c2ecf20Sopenharmony_ci}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci/* String table for domain transition control keywords. */
17318c2ecf20Sopenharmony_cistatic const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
17328c2ecf20Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
17338c2ecf20Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_RESET]         = "reset_domain ",
17348c2ecf20Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
17358c2ecf20Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
17368c2ecf20Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
17378c2ecf20Sopenharmony_ci	[TOMOYO_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
17388c2ecf20Sopenharmony_ci};
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci/* String table for grouping keywords. */
17418c2ecf20Sopenharmony_cistatic const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
17428c2ecf20Sopenharmony_ci	[TOMOYO_PATH_GROUP]    = "path_group ",
17438c2ecf20Sopenharmony_ci	[TOMOYO_NUMBER_GROUP]  = "number_group ",
17448c2ecf20Sopenharmony_ci	[TOMOYO_ADDRESS_GROUP] = "address_group ",
17458c2ecf20Sopenharmony_ci};
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci/**
17488c2ecf20Sopenharmony_ci * tomoyo_write_exception - Write exception policy.
17498c2ecf20Sopenharmony_ci *
17508c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
17518c2ecf20Sopenharmony_ci *
17528c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
17538c2ecf20Sopenharmony_ci *
17548c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
17558c2ecf20Sopenharmony_ci */
17568c2ecf20Sopenharmony_cistatic int tomoyo_write_exception(struct tomoyo_io_buffer *head)
17578c2ecf20Sopenharmony_ci{
17588c2ecf20Sopenharmony_ci	const bool is_delete = head->w.is_delete;
17598c2ecf20Sopenharmony_ci	struct tomoyo_acl_param param = {
17608c2ecf20Sopenharmony_ci		.ns = head->w.ns,
17618c2ecf20Sopenharmony_ci		.is_delete = is_delete,
17628c2ecf20Sopenharmony_ci		.data = head->write_buf,
17638c2ecf20Sopenharmony_ci	};
17648c2ecf20Sopenharmony_ci	u8 i;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	if (tomoyo_str_starts(&param.data, "aggregator "))
17678c2ecf20Sopenharmony_ci		return tomoyo_write_aggregator(&param);
17688c2ecf20Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
17698c2ecf20Sopenharmony_ci		if (tomoyo_str_starts(&param.data, tomoyo_transition_type[i]))
17708c2ecf20Sopenharmony_ci			return tomoyo_write_transition_control(&param, i);
17718c2ecf20Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_GROUP; i++)
17728c2ecf20Sopenharmony_ci		if (tomoyo_str_starts(&param.data, tomoyo_group_name[i]))
17738c2ecf20Sopenharmony_ci			return tomoyo_write_group(&param, i);
17748c2ecf20Sopenharmony_ci	if (tomoyo_str_starts(&param.data, "acl_group ")) {
17758c2ecf20Sopenharmony_ci		unsigned int group;
17768c2ecf20Sopenharmony_ci		char *data;
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci		group = simple_strtoul(param.data, &data, 10);
17798c2ecf20Sopenharmony_ci		if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
17808c2ecf20Sopenharmony_ci			return tomoyo_write_domain2
17818c2ecf20Sopenharmony_ci				(head->w.ns, &head->w.ns->acl_group[group],
17828c2ecf20Sopenharmony_ci				 data, is_delete);
17838c2ecf20Sopenharmony_ci	}
17848c2ecf20Sopenharmony_ci	return -EINVAL;
17858c2ecf20Sopenharmony_ci}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci/**
17888c2ecf20Sopenharmony_ci * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
17898c2ecf20Sopenharmony_ci *
17908c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
17918c2ecf20Sopenharmony_ci * @idx:  Index number.
17928c2ecf20Sopenharmony_ci *
17938c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
17948c2ecf20Sopenharmony_ci *
17958c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
17968c2ecf20Sopenharmony_ci */
17978c2ecf20Sopenharmony_cistatic bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
17988c2ecf20Sopenharmony_ci{
17998c2ecf20Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
18008c2ecf20Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
18018c2ecf20Sopenharmony_ci	struct list_head *list = &ns->group_list[idx];
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	list_for_each_cookie(head->r.group, list) {
18048c2ecf20Sopenharmony_ci		struct tomoyo_group *group =
18058c2ecf20Sopenharmony_ci			list_entry(head->r.group, typeof(*group), head.list);
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci		list_for_each_cookie(head->r.acl, &group->member_list) {
18088c2ecf20Sopenharmony_ci			struct tomoyo_acl_head *ptr =
18098c2ecf20Sopenharmony_ci				list_entry(head->r.acl, typeof(*ptr), list);
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci			if (ptr->is_deleted)
18128c2ecf20Sopenharmony_ci				continue;
18138c2ecf20Sopenharmony_ci			if (!tomoyo_flush(head))
18148c2ecf20Sopenharmony_ci				return false;
18158c2ecf20Sopenharmony_ci			tomoyo_print_namespace(head);
18168c2ecf20Sopenharmony_ci			tomoyo_set_string(head, tomoyo_group_name[idx]);
18178c2ecf20Sopenharmony_ci			tomoyo_set_string(head, group->group_name->name);
18188c2ecf20Sopenharmony_ci			if (idx == TOMOYO_PATH_GROUP) {
18198c2ecf20Sopenharmony_ci				tomoyo_set_space(head);
18208c2ecf20Sopenharmony_ci				tomoyo_set_string(head, container_of
18218c2ecf20Sopenharmony_ci					       (ptr, struct tomoyo_path_group,
18228c2ecf20Sopenharmony_ci						head)->member_name->name);
18238c2ecf20Sopenharmony_ci			} else if (idx == TOMOYO_NUMBER_GROUP) {
18248c2ecf20Sopenharmony_ci				tomoyo_print_number_union(head, &container_of
18258c2ecf20Sopenharmony_ci							  (ptr,
18268c2ecf20Sopenharmony_ci						   struct tomoyo_number_group,
18278c2ecf20Sopenharmony_ci							   head)->number);
18288c2ecf20Sopenharmony_ci			} else if (idx == TOMOYO_ADDRESS_GROUP) {
18298c2ecf20Sopenharmony_ci				char buffer[128];
18308c2ecf20Sopenharmony_ci				struct tomoyo_address_group *member =
18318c2ecf20Sopenharmony_ci					container_of(ptr, typeof(*member),
18328c2ecf20Sopenharmony_ci						     head);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci				tomoyo_print_ip(buffer, sizeof(buffer),
18358c2ecf20Sopenharmony_ci						&member->address);
18368c2ecf20Sopenharmony_ci				tomoyo_io_printf(head, " %s", buffer);
18378c2ecf20Sopenharmony_ci			}
18388c2ecf20Sopenharmony_ci			tomoyo_set_lf(head);
18398c2ecf20Sopenharmony_ci		}
18408c2ecf20Sopenharmony_ci		head->r.acl = NULL;
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci	head->r.group = NULL;
18438c2ecf20Sopenharmony_ci	return true;
18448c2ecf20Sopenharmony_ci}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci/**
18478c2ecf20Sopenharmony_ci * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
18488c2ecf20Sopenharmony_ci *
18498c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
18508c2ecf20Sopenharmony_ci * @idx:  Index number.
18518c2ecf20Sopenharmony_ci *
18528c2ecf20Sopenharmony_ci * Returns true on success, false otherwise.
18538c2ecf20Sopenharmony_ci *
18548c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
18558c2ecf20Sopenharmony_ci */
18568c2ecf20Sopenharmony_cistatic bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
18578c2ecf20Sopenharmony_ci{
18588c2ecf20Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
18598c2ecf20Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
18608c2ecf20Sopenharmony_ci	struct list_head *list = &ns->policy_list[idx];
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	list_for_each_cookie(head->r.acl, list) {
18638c2ecf20Sopenharmony_ci		struct tomoyo_acl_head *acl =
18648c2ecf20Sopenharmony_ci			container_of(head->r.acl, typeof(*acl), list);
18658c2ecf20Sopenharmony_ci		if (acl->is_deleted)
18668c2ecf20Sopenharmony_ci			continue;
18678c2ecf20Sopenharmony_ci		if (!tomoyo_flush(head))
18688c2ecf20Sopenharmony_ci			return false;
18698c2ecf20Sopenharmony_ci		switch (idx) {
18708c2ecf20Sopenharmony_ci		case TOMOYO_ID_TRANSITION_CONTROL:
18718c2ecf20Sopenharmony_ci			{
18728c2ecf20Sopenharmony_ci				struct tomoyo_transition_control *ptr =
18738c2ecf20Sopenharmony_ci					container_of(acl, typeof(*ptr), head);
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci				tomoyo_print_namespace(head);
18768c2ecf20Sopenharmony_ci				tomoyo_set_string(head, tomoyo_transition_type
18778c2ecf20Sopenharmony_ci						  [ptr->type]);
18788c2ecf20Sopenharmony_ci				tomoyo_set_string(head, ptr->program ?
18798c2ecf20Sopenharmony_ci						  ptr->program->name : "any");
18808c2ecf20Sopenharmony_ci				tomoyo_set_string(head, " from ");
18818c2ecf20Sopenharmony_ci				tomoyo_set_string(head, ptr->domainname ?
18828c2ecf20Sopenharmony_ci						  ptr->domainname->name :
18838c2ecf20Sopenharmony_ci						  "any");
18848c2ecf20Sopenharmony_ci			}
18858c2ecf20Sopenharmony_ci			break;
18868c2ecf20Sopenharmony_ci		case TOMOYO_ID_AGGREGATOR:
18878c2ecf20Sopenharmony_ci			{
18888c2ecf20Sopenharmony_ci				struct tomoyo_aggregator *ptr =
18898c2ecf20Sopenharmony_ci					container_of(acl, typeof(*ptr), head);
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci				tomoyo_print_namespace(head);
18928c2ecf20Sopenharmony_ci				tomoyo_set_string(head, "aggregator ");
18938c2ecf20Sopenharmony_ci				tomoyo_set_string(head,
18948c2ecf20Sopenharmony_ci						  ptr->original_name->name);
18958c2ecf20Sopenharmony_ci				tomoyo_set_space(head);
18968c2ecf20Sopenharmony_ci				tomoyo_set_string(head,
18978c2ecf20Sopenharmony_ci					       ptr->aggregated_name->name);
18988c2ecf20Sopenharmony_ci			}
18998c2ecf20Sopenharmony_ci			break;
19008c2ecf20Sopenharmony_ci		default:
19018c2ecf20Sopenharmony_ci			continue;
19028c2ecf20Sopenharmony_ci		}
19038c2ecf20Sopenharmony_ci		tomoyo_set_lf(head);
19048c2ecf20Sopenharmony_ci	}
19058c2ecf20Sopenharmony_ci	head->r.acl = NULL;
19068c2ecf20Sopenharmony_ci	return true;
19078c2ecf20Sopenharmony_ci}
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci/**
19108c2ecf20Sopenharmony_ci * tomoyo_read_exception - Read exception policy.
19118c2ecf20Sopenharmony_ci *
19128c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
19138c2ecf20Sopenharmony_ci *
19148c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
19158c2ecf20Sopenharmony_ci */
19168c2ecf20Sopenharmony_cistatic void tomoyo_read_exception(struct tomoyo_io_buffer *head)
19178c2ecf20Sopenharmony_ci{
19188c2ecf20Sopenharmony_ci	struct tomoyo_policy_namespace *ns =
19198c2ecf20Sopenharmony_ci		container_of(head->r.ns, typeof(*ns), namespace_list);
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	if (head->r.eof)
19228c2ecf20Sopenharmony_ci		return;
19238c2ecf20Sopenharmony_ci	while (head->r.step < TOMOYO_MAX_POLICY &&
19248c2ecf20Sopenharmony_ci	       tomoyo_read_policy(head, head->r.step))
19258c2ecf20Sopenharmony_ci		head->r.step++;
19268c2ecf20Sopenharmony_ci	if (head->r.step < TOMOYO_MAX_POLICY)
19278c2ecf20Sopenharmony_ci		return;
19288c2ecf20Sopenharmony_ci	while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
19298c2ecf20Sopenharmony_ci	       tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY))
19308c2ecf20Sopenharmony_ci		head->r.step++;
19318c2ecf20Sopenharmony_ci	if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
19328c2ecf20Sopenharmony_ci		return;
19338c2ecf20Sopenharmony_ci	while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP
19348c2ecf20Sopenharmony_ci	       + TOMOYO_MAX_ACL_GROUPS) {
19358c2ecf20Sopenharmony_ci		head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY
19368c2ecf20Sopenharmony_ci			- TOMOYO_MAX_GROUP;
19378c2ecf20Sopenharmony_ci		if (!tomoyo_read_domain2(head, &ns->acl_group
19388c2ecf20Sopenharmony_ci					 [head->r.acl_group_index]))
19398c2ecf20Sopenharmony_ci			return;
19408c2ecf20Sopenharmony_ci		head->r.step++;
19418c2ecf20Sopenharmony_ci	}
19428c2ecf20Sopenharmony_ci	head->r.eof = true;
19438c2ecf20Sopenharmony_ci}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci/* Wait queue for kernel -> userspace notification. */
19468c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
19478c2ecf20Sopenharmony_ci/* Wait queue for userspace -> kernel notification. */
19488c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait);
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci/* Structure for query. */
19518c2ecf20Sopenharmony_cistruct tomoyo_query {
19528c2ecf20Sopenharmony_ci	struct list_head list;
19538c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain;
19548c2ecf20Sopenharmony_ci	char *query;
19558c2ecf20Sopenharmony_ci	size_t query_len;
19568c2ecf20Sopenharmony_ci	unsigned int serial;
19578c2ecf20Sopenharmony_ci	u8 timer;
19588c2ecf20Sopenharmony_ci	u8 answer;
19598c2ecf20Sopenharmony_ci	u8 retry;
19608c2ecf20Sopenharmony_ci};
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci/* The list for "struct tomoyo_query". */
19638c2ecf20Sopenharmony_cistatic LIST_HEAD(tomoyo_query_list);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci/* Lock for manipulating tomoyo_query_list. */
19668c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(tomoyo_query_list_lock);
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci/*
19698c2ecf20Sopenharmony_ci * Number of "struct file" referring /sys/kernel/security/tomoyo/query
19708c2ecf20Sopenharmony_ci * interface.
19718c2ecf20Sopenharmony_ci */
19728c2ecf20Sopenharmony_cistatic atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci/**
19758c2ecf20Sopenharmony_ci * tomoyo_truncate - Truncate a line.
19768c2ecf20Sopenharmony_ci *
19778c2ecf20Sopenharmony_ci * @str: String to truncate.
19788c2ecf20Sopenharmony_ci *
19798c2ecf20Sopenharmony_ci * Returns length of truncated @str.
19808c2ecf20Sopenharmony_ci */
19818c2ecf20Sopenharmony_cistatic int tomoyo_truncate(char *str)
19828c2ecf20Sopenharmony_ci{
19838c2ecf20Sopenharmony_ci	char *start = str;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	while (*(unsigned char *) str > (unsigned char) ' ')
19868c2ecf20Sopenharmony_ci		str++;
19878c2ecf20Sopenharmony_ci	*str = '\0';
19888c2ecf20Sopenharmony_ci	return strlen(start) + 1;
19898c2ecf20Sopenharmony_ci}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci/**
19928c2ecf20Sopenharmony_ci * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode.
19938c2ecf20Sopenharmony_ci *
19948c2ecf20Sopenharmony_ci * @domain: Pointer to "struct tomoyo_domain_info".
19958c2ecf20Sopenharmony_ci * @header: Lines containing ACL.
19968c2ecf20Sopenharmony_ci *
19978c2ecf20Sopenharmony_ci * Returns nothing.
19988c2ecf20Sopenharmony_ci */
19998c2ecf20Sopenharmony_cistatic void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
20008c2ecf20Sopenharmony_ci{
20018c2ecf20Sopenharmony_ci	char *buffer;
20028c2ecf20Sopenharmony_ci	char *realpath = NULL;
20038c2ecf20Sopenharmony_ci	char *argv0 = NULL;
20048c2ecf20Sopenharmony_ci	char *symlink = NULL;
20058c2ecf20Sopenharmony_ci	char *cp = strchr(header, '\n');
20068c2ecf20Sopenharmony_ci	int len;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if (!cp)
20098c2ecf20Sopenharmony_ci		return;
20108c2ecf20Sopenharmony_ci	cp = strchr(cp + 1, '\n');
20118c2ecf20Sopenharmony_ci	if (!cp)
20128c2ecf20Sopenharmony_ci		return;
20138c2ecf20Sopenharmony_ci	*cp++ = '\0';
20148c2ecf20Sopenharmony_ci	len = strlen(cp) + 1;
20158c2ecf20Sopenharmony_ci	/* strstr() will return NULL if ordering is wrong. */
20168c2ecf20Sopenharmony_ci	if (*cp == 'f') {
20178c2ecf20Sopenharmony_ci		argv0 = strstr(header, " argv[]={ \"");
20188c2ecf20Sopenharmony_ci		if (argv0) {
20198c2ecf20Sopenharmony_ci			argv0 += 10;
20208c2ecf20Sopenharmony_ci			len += tomoyo_truncate(argv0) + 14;
20218c2ecf20Sopenharmony_ci		}
20228c2ecf20Sopenharmony_ci		realpath = strstr(header, " exec={ realpath=\"");
20238c2ecf20Sopenharmony_ci		if (realpath) {
20248c2ecf20Sopenharmony_ci			realpath += 8;
20258c2ecf20Sopenharmony_ci			len += tomoyo_truncate(realpath) + 6;
20268c2ecf20Sopenharmony_ci		}
20278c2ecf20Sopenharmony_ci		symlink = strstr(header, " symlink.target=\"");
20288c2ecf20Sopenharmony_ci		if (symlink)
20298c2ecf20Sopenharmony_ci			len += tomoyo_truncate(symlink + 1) + 1;
20308c2ecf20Sopenharmony_ci	}
20318c2ecf20Sopenharmony_ci	buffer = kmalloc(len, GFP_NOFS);
20328c2ecf20Sopenharmony_ci	if (!buffer)
20338c2ecf20Sopenharmony_ci		return;
20348c2ecf20Sopenharmony_ci	snprintf(buffer, len - 1, "%s", cp);
20358c2ecf20Sopenharmony_ci	if (realpath)
20368c2ecf20Sopenharmony_ci		tomoyo_addprintf(buffer, len, " exec.%s", realpath);
20378c2ecf20Sopenharmony_ci	if (argv0)
20388c2ecf20Sopenharmony_ci		tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
20398c2ecf20Sopenharmony_ci	if (symlink)
20408c2ecf20Sopenharmony_ci		tomoyo_addprintf(buffer, len, "%s", symlink);
20418c2ecf20Sopenharmony_ci	tomoyo_normalize_line(buffer);
20428c2ecf20Sopenharmony_ci	if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
20438c2ecf20Sopenharmony_ci				  false))
20448c2ecf20Sopenharmony_ci		tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
20458c2ecf20Sopenharmony_ci	kfree(buffer);
20468c2ecf20Sopenharmony_ci}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci/**
20498c2ecf20Sopenharmony_ci * tomoyo_supervisor - Ask for the supervisor's decision.
20508c2ecf20Sopenharmony_ci *
20518c2ecf20Sopenharmony_ci * @r:   Pointer to "struct tomoyo_request_info".
20528c2ecf20Sopenharmony_ci * @fmt: The printf()'s format string, followed by parameters.
20538c2ecf20Sopenharmony_ci *
20548c2ecf20Sopenharmony_ci * Returns 0 if the supervisor decided to permit the access request which
20558c2ecf20Sopenharmony_ci * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
20568c2ecf20Sopenharmony_ci * supervisor decided to retry the access request which violated the policy in
20578c2ecf20Sopenharmony_ci * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
20588c2ecf20Sopenharmony_ci */
20598c2ecf20Sopenharmony_ciint tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
20608c2ecf20Sopenharmony_ci{
20618c2ecf20Sopenharmony_ci	va_list args;
20628c2ecf20Sopenharmony_ci	int error;
20638c2ecf20Sopenharmony_ci	int len;
20648c2ecf20Sopenharmony_ci	static unsigned int tomoyo_serial;
20658c2ecf20Sopenharmony_ci	struct tomoyo_query entry = { };
20668c2ecf20Sopenharmony_ci	bool quota_exceeded = false;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	va_start(args, fmt);
20698c2ecf20Sopenharmony_ci	len = vsnprintf((char *) &len, 1, fmt, args) + 1;
20708c2ecf20Sopenharmony_ci	va_end(args);
20718c2ecf20Sopenharmony_ci	/* Write /sys/kernel/security/tomoyo/audit. */
20728c2ecf20Sopenharmony_ci	va_start(args, fmt);
20738c2ecf20Sopenharmony_ci	tomoyo_write_log2(r, len, fmt, args);
20748c2ecf20Sopenharmony_ci	va_end(args);
20758c2ecf20Sopenharmony_ci	/* Nothing more to do if granted. */
20768c2ecf20Sopenharmony_ci	if (r->granted)
20778c2ecf20Sopenharmony_ci		return 0;
20788c2ecf20Sopenharmony_ci	if (r->mode)
20798c2ecf20Sopenharmony_ci		tomoyo_update_stat(r->mode);
20808c2ecf20Sopenharmony_ci	switch (r->mode) {
20818c2ecf20Sopenharmony_ci	case TOMOYO_CONFIG_ENFORCING:
20828c2ecf20Sopenharmony_ci		error = -EPERM;
20838c2ecf20Sopenharmony_ci		if (atomic_read(&tomoyo_query_observers))
20848c2ecf20Sopenharmony_ci			break;
20858c2ecf20Sopenharmony_ci		goto out;
20868c2ecf20Sopenharmony_ci	case TOMOYO_CONFIG_LEARNING:
20878c2ecf20Sopenharmony_ci		error = 0;
20888c2ecf20Sopenharmony_ci		/* Check max_learning_entry parameter. */
20898c2ecf20Sopenharmony_ci		if (tomoyo_domain_quota_is_ok(r))
20908c2ecf20Sopenharmony_ci			break;
20918c2ecf20Sopenharmony_ci		fallthrough;
20928c2ecf20Sopenharmony_ci	default:
20938c2ecf20Sopenharmony_ci		return 0;
20948c2ecf20Sopenharmony_ci	}
20958c2ecf20Sopenharmony_ci	/* Get message. */
20968c2ecf20Sopenharmony_ci	va_start(args, fmt);
20978c2ecf20Sopenharmony_ci	entry.query = tomoyo_init_log(r, len, fmt, args);
20988c2ecf20Sopenharmony_ci	va_end(args);
20998c2ecf20Sopenharmony_ci	if (!entry.query)
21008c2ecf20Sopenharmony_ci		goto out;
21018c2ecf20Sopenharmony_ci	entry.query_len = strlen(entry.query) + 1;
21028c2ecf20Sopenharmony_ci	if (!error) {
21038c2ecf20Sopenharmony_ci		tomoyo_add_entry(r->domain, entry.query);
21048c2ecf20Sopenharmony_ci		goto out;
21058c2ecf20Sopenharmony_ci	}
21068c2ecf20Sopenharmony_ci	len = tomoyo_round2(entry.query_len);
21078c2ecf20Sopenharmony_ci	entry.domain = r->domain;
21088c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
21098c2ecf20Sopenharmony_ci	if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] &&
21108c2ecf20Sopenharmony_ci	    tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len
21118c2ecf20Sopenharmony_ci	    >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) {
21128c2ecf20Sopenharmony_ci		quota_exceeded = true;
21138c2ecf20Sopenharmony_ci	} else {
21148c2ecf20Sopenharmony_ci		entry.serial = tomoyo_serial++;
21158c2ecf20Sopenharmony_ci		entry.retry = r->retry;
21168c2ecf20Sopenharmony_ci		tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len;
21178c2ecf20Sopenharmony_ci		list_add_tail(&entry.list, &tomoyo_query_list);
21188c2ecf20Sopenharmony_ci	}
21198c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
21208c2ecf20Sopenharmony_ci	if (quota_exceeded)
21218c2ecf20Sopenharmony_ci		goto out;
21228c2ecf20Sopenharmony_ci	/* Give 10 seconds for supervisor's opinion. */
21238c2ecf20Sopenharmony_ci	while (entry.timer < 10) {
21248c2ecf20Sopenharmony_ci		wake_up_all(&tomoyo_query_wait);
21258c2ecf20Sopenharmony_ci		if (wait_event_interruptible_timeout
21268c2ecf20Sopenharmony_ci		    (tomoyo_answer_wait, entry.answer ||
21278c2ecf20Sopenharmony_ci		     !atomic_read(&tomoyo_query_observers), HZ))
21288c2ecf20Sopenharmony_ci			break;
21298c2ecf20Sopenharmony_ci		entry.timer++;
21308c2ecf20Sopenharmony_ci	}
21318c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
21328c2ecf20Sopenharmony_ci	list_del(&entry.list);
21338c2ecf20Sopenharmony_ci	tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len;
21348c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
21358c2ecf20Sopenharmony_ci	switch (entry.answer) {
21368c2ecf20Sopenharmony_ci	case 3: /* Asked to retry by administrator. */
21378c2ecf20Sopenharmony_ci		error = TOMOYO_RETRY_REQUEST;
21388c2ecf20Sopenharmony_ci		r->retry++;
21398c2ecf20Sopenharmony_ci		break;
21408c2ecf20Sopenharmony_ci	case 1:
21418c2ecf20Sopenharmony_ci		/* Granted by administrator. */
21428c2ecf20Sopenharmony_ci		error = 0;
21438c2ecf20Sopenharmony_ci		break;
21448c2ecf20Sopenharmony_ci	default:
21458c2ecf20Sopenharmony_ci		/* Timed out or rejected by administrator. */
21468c2ecf20Sopenharmony_ci		break;
21478c2ecf20Sopenharmony_ci	}
21488c2ecf20Sopenharmony_ciout:
21498c2ecf20Sopenharmony_ci	kfree(entry.query);
21508c2ecf20Sopenharmony_ci	return error;
21518c2ecf20Sopenharmony_ci}
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci/**
21548c2ecf20Sopenharmony_ci * tomoyo_find_domain_by_qid - Get domain by query id.
21558c2ecf20Sopenharmony_ci *
21568c2ecf20Sopenharmony_ci * @serial: Query ID assigned by tomoyo_supervisor().
21578c2ecf20Sopenharmony_ci *
21588c2ecf20Sopenharmony_ci * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
21598c2ecf20Sopenharmony_ci */
21608c2ecf20Sopenharmony_cistatic struct tomoyo_domain_info *tomoyo_find_domain_by_qid
21618c2ecf20Sopenharmony_ci(unsigned int serial)
21628c2ecf20Sopenharmony_ci{
21638c2ecf20Sopenharmony_ci	struct tomoyo_query *ptr;
21648c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain = NULL;
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
21678c2ecf20Sopenharmony_ci	list_for_each_entry(ptr, &tomoyo_query_list, list) {
21688c2ecf20Sopenharmony_ci		if (ptr->serial != serial)
21698c2ecf20Sopenharmony_ci			continue;
21708c2ecf20Sopenharmony_ci		domain = ptr->domain;
21718c2ecf20Sopenharmony_ci		break;
21728c2ecf20Sopenharmony_ci	}
21738c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
21748c2ecf20Sopenharmony_ci	return domain;
21758c2ecf20Sopenharmony_ci}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci/**
21788c2ecf20Sopenharmony_ci * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
21798c2ecf20Sopenharmony_ci *
21808c2ecf20Sopenharmony_ci * @file: Pointer to "struct file".
21818c2ecf20Sopenharmony_ci * @wait: Pointer to "poll_table".
21828c2ecf20Sopenharmony_ci *
21838c2ecf20Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM when ready to read, 0 otherwise.
21848c2ecf20Sopenharmony_ci *
21858c2ecf20Sopenharmony_ci * Waits for access requests which violated policy in enforcing mode.
21868c2ecf20Sopenharmony_ci */
21878c2ecf20Sopenharmony_cistatic __poll_t tomoyo_poll_query(struct file *file, poll_table *wait)
21888c2ecf20Sopenharmony_ci{
21898c2ecf20Sopenharmony_ci	if (!list_empty(&tomoyo_query_list))
21908c2ecf20Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
21918c2ecf20Sopenharmony_ci	poll_wait(file, &tomoyo_query_wait, wait);
21928c2ecf20Sopenharmony_ci	if (!list_empty(&tomoyo_query_list))
21938c2ecf20Sopenharmony_ci		return EPOLLIN | EPOLLRDNORM;
21948c2ecf20Sopenharmony_ci	return 0;
21958c2ecf20Sopenharmony_ci}
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci/**
21988c2ecf20Sopenharmony_ci * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
21998c2ecf20Sopenharmony_ci *
22008c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
22018c2ecf20Sopenharmony_ci */
22028c2ecf20Sopenharmony_cistatic void tomoyo_read_query(struct tomoyo_io_buffer *head)
22038c2ecf20Sopenharmony_ci{
22048c2ecf20Sopenharmony_ci	struct list_head *tmp;
22058c2ecf20Sopenharmony_ci	unsigned int pos = 0;
22068c2ecf20Sopenharmony_ci	size_t len = 0;
22078c2ecf20Sopenharmony_ci	char *buf;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	if (head->r.w_pos)
22108c2ecf20Sopenharmony_ci		return;
22118c2ecf20Sopenharmony_ci	kfree(head->read_buf);
22128c2ecf20Sopenharmony_ci	head->read_buf = NULL;
22138c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
22148c2ecf20Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
22158c2ecf20Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci		if (pos++ != head->r.query_index)
22188c2ecf20Sopenharmony_ci			continue;
22198c2ecf20Sopenharmony_ci		len = ptr->query_len;
22208c2ecf20Sopenharmony_ci		break;
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
22238c2ecf20Sopenharmony_ci	if (!len) {
22248c2ecf20Sopenharmony_ci		head->r.query_index = 0;
22258c2ecf20Sopenharmony_ci		return;
22268c2ecf20Sopenharmony_ci	}
22278c2ecf20Sopenharmony_ci	buf = kzalloc(len + 32, GFP_NOFS);
22288c2ecf20Sopenharmony_ci	if (!buf)
22298c2ecf20Sopenharmony_ci		return;
22308c2ecf20Sopenharmony_ci	pos = 0;
22318c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
22328c2ecf20Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
22338c2ecf20Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci		if (pos++ != head->r.query_index)
22368c2ecf20Sopenharmony_ci			continue;
22378c2ecf20Sopenharmony_ci		/*
22388c2ecf20Sopenharmony_ci		 * Some query can be skipped because tomoyo_query_list
22398c2ecf20Sopenharmony_ci		 * can change, but I don't care.
22408c2ecf20Sopenharmony_ci		 */
22418c2ecf20Sopenharmony_ci		if (len == ptr->query_len)
22428c2ecf20Sopenharmony_ci			snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
22438c2ecf20Sopenharmony_ci				 ptr->retry, ptr->query);
22448c2ecf20Sopenharmony_ci		break;
22458c2ecf20Sopenharmony_ci	}
22468c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
22478c2ecf20Sopenharmony_ci	if (buf[0]) {
22488c2ecf20Sopenharmony_ci		head->read_buf = buf;
22498c2ecf20Sopenharmony_ci		head->r.w[head->r.w_pos++] = buf;
22508c2ecf20Sopenharmony_ci		head->r.query_index++;
22518c2ecf20Sopenharmony_ci	} else {
22528c2ecf20Sopenharmony_ci		kfree(buf);
22538c2ecf20Sopenharmony_ci	}
22548c2ecf20Sopenharmony_ci}
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci/**
22578c2ecf20Sopenharmony_ci * tomoyo_write_answer - Write the supervisor's decision.
22588c2ecf20Sopenharmony_ci *
22598c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
22608c2ecf20Sopenharmony_ci *
22618c2ecf20Sopenharmony_ci * Returns 0 on success, -EINVAL otherwise.
22628c2ecf20Sopenharmony_ci */
22638c2ecf20Sopenharmony_cistatic int tomoyo_write_answer(struct tomoyo_io_buffer *head)
22648c2ecf20Sopenharmony_ci{
22658c2ecf20Sopenharmony_ci	char *data = head->write_buf;
22668c2ecf20Sopenharmony_ci	struct list_head *tmp;
22678c2ecf20Sopenharmony_ci	unsigned int serial;
22688c2ecf20Sopenharmony_ci	unsigned int answer;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
22718c2ecf20Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
22728c2ecf20Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		ptr->timer = 0;
22758c2ecf20Sopenharmony_ci	}
22768c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
22778c2ecf20Sopenharmony_ci	if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
22788c2ecf20Sopenharmony_ci		return -EINVAL;
22798c2ecf20Sopenharmony_ci	spin_lock(&tomoyo_query_list_lock);
22808c2ecf20Sopenharmony_ci	list_for_each(tmp, &tomoyo_query_list) {
22818c2ecf20Sopenharmony_ci		struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci		if (ptr->serial != serial)
22848c2ecf20Sopenharmony_ci			continue;
22858c2ecf20Sopenharmony_ci		ptr->answer = answer;
22868c2ecf20Sopenharmony_ci		/* Remove from tomoyo_query_list. */
22878c2ecf20Sopenharmony_ci		if (ptr->answer)
22888c2ecf20Sopenharmony_ci			list_del_init(&ptr->list);
22898c2ecf20Sopenharmony_ci		break;
22908c2ecf20Sopenharmony_ci	}
22918c2ecf20Sopenharmony_ci	spin_unlock(&tomoyo_query_list_lock);
22928c2ecf20Sopenharmony_ci	return 0;
22938c2ecf20Sopenharmony_ci}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci/**
22968c2ecf20Sopenharmony_ci * tomoyo_read_version: Get version.
22978c2ecf20Sopenharmony_ci *
22988c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
22998c2ecf20Sopenharmony_ci *
23008c2ecf20Sopenharmony_ci * Returns version information.
23018c2ecf20Sopenharmony_ci */
23028c2ecf20Sopenharmony_cistatic void tomoyo_read_version(struct tomoyo_io_buffer *head)
23038c2ecf20Sopenharmony_ci{
23048c2ecf20Sopenharmony_ci	if (!head->r.eof) {
23058c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "2.6.0");
23068c2ecf20Sopenharmony_ci		head->r.eof = true;
23078c2ecf20Sopenharmony_ci	}
23088c2ecf20Sopenharmony_ci}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci/* String table for /sys/kernel/security/tomoyo/stat interface. */
23118c2ecf20Sopenharmony_cistatic const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = {
23128c2ecf20Sopenharmony_ci	[TOMOYO_STAT_POLICY_UPDATES]    = "update:",
23138c2ecf20Sopenharmony_ci	[TOMOYO_STAT_POLICY_LEARNING]   = "violation in learning mode:",
23148c2ecf20Sopenharmony_ci	[TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
23158c2ecf20Sopenharmony_ci	[TOMOYO_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
23168c2ecf20Sopenharmony_ci};
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci/* String table for /sys/kernel/security/tomoyo/stat interface. */
23198c2ecf20Sopenharmony_cistatic const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
23208c2ecf20Sopenharmony_ci	[TOMOYO_MEMORY_POLICY] = "policy:",
23218c2ecf20Sopenharmony_ci	[TOMOYO_MEMORY_AUDIT]  = "audit log:",
23228c2ecf20Sopenharmony_ci	[TOMOYO_MEMORY_QUERY]  = "query message:",
23238c2ecf20Sopenharmony_ci};
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci/* Counter for number of updates. */
23268c2ecf20Sopenharmony_cistatic atomic_t tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
23278c2ecf20Sopenharmony_ci/* Timestamp counter for last updated. */
23288c2ecf20Sopenharmony_cistatic time64_t tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci/**
23318c2ecf20Sopenharmony_ci * tomoyo_update_stat - Update statistic counters.
23328c2ecf20Sopenharmony_ci *
23338c2ecf20Sopenharmony_ci * @index: Index for policy type.
23348c2ecf20Sopenharmony_ci *
23358c2ecf20Sopenharmony_ci * Returns nothing.
23368c2ecf20Sopenharmony_ci */
23378c2ecf20Sopenharmony_civoid tomoyo_update_stat(const u8 index)
23388c2ecf20Sopenharmony_ci{
23398c2ecf20Sopenharmony_ci	atomic_inc(&tomoyo_stat_updated[index]);
23408c2ecf20Sopenharmony_ci	tomoyo_stat_modified[index] = ktime_get_real_seconds();
23418c2ecf20Sopenharmony_ci}
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci/**
23448c2ecf20Sopenharmony_ci * tomoyo_read_stat - Read statistic data.
23458c2ecf20Sopenharmony_ci *
23468c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
23478c2ecf20Sopenharmony_ci *
23488c2ecf20Sopenharmony_ci * Returns nothing.
23498c2ecf20Sopenharmony_ci */
23508c2ecf20Sopenharmony_cistatic void tomoyo_read_stat(struct tomoyo_io_buffer *head)
23518c2ecf20Sopenharmony_ci{
23528c2ecf20Sopenharmony_ci	u8 i;
23538c2ecf20Sopenharmony_ci	unsigned int total = 0;
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	if (head->r.eof)
23568c2ecf20Sopenharmony_ci		return;
23578c2ecf20Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) {
23588c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "Policy %-30s %10u",
23598c2ecf20Sopenharmony_ci				 tomoyo_policy_headers[i],
23608c2ecf20Sopenharmony_ci				 atomic_read(&tomoyo_stat_updated[i]));
23618c2ecf20Sopenharmony_ci		if (tomoyo_stat_modified[i]) {
23628c2ecf20Sopenharmony_ci			struct tomoyo_time stamp;
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci			tomoyo_convert_time(tomoyo_stat_modified[i], &stamp);
23658c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, " (Last: %04u/%02u/%02u %02u:%02u:%02u)",
23668c2ecf20Sopenharmony_ci					 stamp.year, stamp.month, stamp.day,
23678c2ecf20Sopenharmony_ci					 stamp.hour, stamp.min, stamp.sec);
23688c2ecf20Sopenharmony_ci		}
23698c2ecf20Sopenharmony_ci		tomoyo_set_lf(head);
23708c2ecf20Sopenharmony_ci	}
23718c2ecf20Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) {
23728c2ecf20Sopenharmony_ci		unsigned int used = tomoyo_memory_used[i];
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci		total += used;
23758c2ecf20Sopenharmony_ci		tomoyo_io_printf(head, "Memory used by %-22s %10u",
23768c2ecf20Sopenharmony_ci				 tomoyo_memory_headers[i], used);
23778c2ecf20Sopenharmony_ci		used = tomoyo_memory_quota[i];
23788c2ecf20Sopenharmony_ci		if (used)
23798c2ecf20Sopenharmony_ci			tomoyo_io_printf(head, " (Quota: %10u)", used);
23808c2ecf20Sopenharmony_ci		tomoyo_set_lf(head);
23818c2ecf20Sopenharmony_ci	}
23828c2ecf20Sopenharmony_ci	tomoyo_io_printf(head, "Total memory used:                    %10u\n",
23838c2ecf20Sopenharmony_ci			 total);
23848c2ecf20Sopenharmony_ci	head->r.eof = true;
23858c2ecf20Sopenharmony_ci}
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci/**
23888c2ecf20Sopenharmony_ci * tomoyo_write_stat - Set memory quota.
23898c2ecf20Sopenharmony_ci *
23908c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
23918c2ecf20Sopenharmony_ci *
23928c2ecf20Sopenharmony_ci * Returns 0.
23938c2ecf20Sopenharmony_ci */
23948c2ecf20Sopenharmony_cistatic int tomoyo_write_stat(struct tomoyo_io_buffer *head)
23958c2ecf20Sopenharmony_ci{
23968c2ecf20Sopenharmony_ci	char *data = head->write_buf;
23978c2ecf20Sopenharmony_ci	u8 i;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	if (tomoyo_str_starts(&data, "Memory used by "))
24008c2ecf20Sopenharmony_ci		for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++)
24018c2ecf20Sopenharmony_ci			if (tomoyo_str_starts(&data, tomoyo_memory_headers[i]))
24028c2ecf20Sopenharmony_ci				sscanf(data, "%u", &tomoyo_memory_quota[i]);
24038c2ecf20Sopenharmony_ci	return 0;
24048c2ecf20Sopenharmony_ci}
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci/**
24078c2ecf20Sopenharmony_ci * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
24088c2ecf20Sopenharmony_ci *
24098c2ecf20Sopenharmony_ci * @type: Type of interface.
24108c2ecf20Sopenharmony_ci * @file: Pointer to "struct file".
24118c2ecf20Sopenharmony_ci *
24128c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
24138c2ecf20Sopenharmony_ci */
24148c2ecf20Sopenharmony_ciint tomoyo_open_control(const u8 type, struct file *file)
24158c2ecf20Sopenharmony_ci{
24168c2ecf20Sopenharmony_ci	struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	if (!head)
24198c2ecf20Sopenharmony_ci		return -ENOMEM;
24208c2ecf20Sopenharmony_ci	mutex_init(&head->io_sem);
24218c2ecf20Sopenharmony_ci	head->type = type;
24228c2ecf20Sopenharmony_ci	switch (type) {
24238c2ecf20Sopenharmony_ci	case TOMOYO_DOMAINPOLICY:
24248c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/domain_policy */
24258c2ecf20Sopenharmony_ci		head->write = tomoyo_write_domain;
24268c2ecf20Sopenharmony_ci		head->read = tomoyo_read_domain;
24278c2ecf20Sopenharmony_ci		break;
24288c2ecf20Sopenharmony_ci	case TOMOYO_EXCEPTIONPOLICY:
24298c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/exception_policy */
24308c2ecf20Sopenharmony_ci		head->write = tomoyo_write_exception;
24318c2ecf20Sopenharmony_ci		head->read = tomoyo_read_exception;
24328c2ecf20Sopenharmony_ci		break;
24338c2ecf20Sopenharmony_ci	case TOMOYO_AUDIT:
24348c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/audit */
24358c2ecf20Sopenharmony_ci		head->poll = tomoyo_poll_log;
24368c2ecf20Sopenharmony_ci		head->read = tomoyo_read_log;
24378c2ecf20Sopenharmony_ci		break;
24388c2ecf20Sopenharmony_ci	case TOMOYO_PROCESS_STATUS:
24398c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/.process_status */
24408c2ecf20Sopenharmony_ci		head->write = tomoyo_write_pid;
24418c2ecf20Sopenharmony_ci		head->read = tomoyo_read_pid;
24428c2ecf20Sopenharmony_ci		break;
24438c2ecf20Sopenharmony_ci	case TOMOYO_VERSION:
24448c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/version */
24458c2ecf20Sopenharmony_ci		head->read = tomoyo_read_version;
24468c2ecf20Sopenharmony_ci		head->readbuf_size = 128;
24478c2ecf20Sopenharmony_ci		break;
24488c2ecf20Sopenharmony_ci	case TOMOYO_STAT:
24498c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/stat */
24508c2ecf20Sopenharmony_ci		head->write = tomoyo_write_stat;
24518c2ecf20Sopenharmony_ci		head->read = tomoyo_read_stat;
24528c2ecf20Sopenharmony_ci		head->readbuf_size = 1024;
24538c2ecf20Sopenharmony_ci		break;
24548c2ecf20Sopenharmony_ci	case TOMOYO_PROFILE:
24558c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/profile */
24568c2ecf20Sopenharmony_ci		head->write = tomoyo_write_profile;
24578c2ecf20Sopenharmony_ci		head->read = tomoyo_read_profile;
24588c2ecf20Sopenharmony_ci		break;
24598c2ecf20Sopenharmony_ci	case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
24608c2ecf20Sopenharmony_ci		head->poll = tomoyo_poll_query;
24618c2ecf20Sopenharmony_ci		head->write = tomoyo_write_answer;
24628c2ecf20Sopenharmony_ci		head->read = tomoyo_read_query;
24638c2ecf20Sopenharmony_ci		break;
24648c2ecf20Sopenharmony_ci	case TOMOYO_MANAGER:
24658c2ecf20Sopenharmony_ci		/* /sys/kernel/security/tomoyo/manager */
24668c2ecf20Sopenharmony_ci		head->write = tomoyo_write_manager;
24678c2ecf20Sopenharmony_ci		head->read = tomoyo_read_manager;
24688c2ecf20Sopenharmony_ci		break;
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci	if (!(file->f_mode & FMODE_READ)) {
24718c2ecf20Sopenharmony_ci		/*
24728c2ecf20Sopenharmony_ci		 * No need to allocate read_buf since it is not opened
24738c2ecf20Sopenharmony_ci		 * for reading.
24748c2ecf20Sopenharmony_ci		 */
24758c2ecf20Sopenharmony_ci		head->read = NULL;
24768c2ecf20Sopenharmony_ci		head->poll = NULL;
24778c2ecf20Sopenharmony_ci	} else if (!head->poll) {
24788c2ecf20Sopenharmony_ci		/* Don't allocate read_buf for poll() access. */
24798c2ecf20Sopenharmony_ci		if (!head->readbuf_size)
24808c2ecf20Sopenharmony_ci			head->readbuf_size = 4096 * 2;
24818c2ecf20Sopenharmony_ci		head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
24828c2ecf20Sopenharmony_ci		if (!head->read_buf) {
24838c2ecf20Sopenharmony_ci			kfree(head);
24848c2ecf20Sopenharmony_ci			return -ENOMEM;
24858c2ecf20Sopenharmony_ci		}
24868c2ecf20Sopenharmony_ci	}
24878c2ecf20Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE)) {
24888c2ecf20Sopenharmony_ci		/*
24898c2ecf20Sopenharmony_ci		 * No need to allocate write_buf since it is not opened
24908c2ecf20Sopenharmony_ci		 * for writing.
24918c2ecf20Sopenharmony_ci		 */
24928c2ecf20Sopenharmony_ci		head->write = NULL;
24938c2ecf20Sopenharmony_ci	} else if (head->write) {
24948c2ecf20Sopenharmony_ci		head->writebuf_size = 4096 * 2;
24958c2ecf20Sopenharmony_ci		head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS);
24968c2ecf20Sopenharmony_ci		if (!head->write_buf) {
24978c2ecf20Sopenharmony_ci			kfree(head->read_buf);
24988c2ecf20Sopenharmony_ci			kfree(head);
24998c2ecf20Sopenharmony_ci			return -ENOMEM;
25008c2ecf20Sopenharmony_ci		}
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci	/*
25038c2ecf20Sopenharmony_ci	 * If the file is /sys/kernel/security/tomoyo/query , increment the
25048c2ecf20Sopenharmony_ci	 * observer counter.
25058c2ecf20Sopenharmony_ci	 * The obserber counter is used by tomoyo_supervisor() to see if
25068c2ecf20Sopenharmony_ci	 * there is some process monitoring /sys/kernel/security/tomoyo/query.
25078c2ecf20Sopenharmony_ci	 */
25088c2ecf20Sopenharmony_ci	if (type == TOMOYO_QUERY)
25098c2ecf20Sopenharmony_ci		atomic_inc(&tomoyo_query_observers);
25108c2ecf20Sopenharmony_ci	file->private_data = head;
25118c2ecf20Sopenharmony_ci	tomoyo_notify_gc(head, true);
25128c2ecf20Sopenharmony_ci	return 0;
25138c2ecf20Sopenharmony_ci}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci/**
25168c2ecf20Sopenharmony_ci * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
25178c2ecf20Sopenharmony_ci *
25188c2ecf20Sopenharmony_ci * @file: Pointer to "struct file".
25198c2ecf20Sopenharmony_ci * @wait: Pointer to "poll_table". Maybe NULL.
25208c2ecf20Sopenharmony_ci *
25218c2ecf20Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write,
25228c2ecf20Sopenharmony_ci * EPOLLOUT | EPOLLWRNORM otherwise.
25238c2ecf20Sopenharmony_ci */
25248c2ecf20Sopenharmony_ci__poll_t tomoyo_poll_control(struct file *file, poll_table *wait)
25258c2ecf20Sopenharmony_ci{
25268c2ecf20Sopenharmony_ci	struct tomoyo_io_buffer *head = file->private_data;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	if (head->poll)
25298c2ecf20Sopenharmony_ci		return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM;
25308c2ecf20Sopenharmony_ci	return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
25318c2ecf20Sopenharmony_ci}
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci/**
25348c2ecf20Sopenharmony_ci * tomoyo_set_namespace_cursor - Set namespace to read.
25358c2ecf20Sopenharmony_ci *
25368c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
25378c2ecf20Sopenharmony_ci *
25388c2ecf20Sopenharmony_ci * Returns nothing.
25398c2ecf20Sopenharmony_ci */
25408c2ecf20Sopenharmony_cistatic inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
25418c2ecf20Sopenharmony_ci{
25428c2ecf20Sopenharmony_ci	struct list_head *ns;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	if (head->type != TOMOYO_EXCEPTIONPOLICY &&
25458c2ecf20Sopenharmony_ci	    head->type != TOMOYO_PROFILE)
25468c2ecf20Sopenharmony_ci		return;
25478c2ecf20Sopenharmony_ci	/*
25488c2ecf20Sopenharmony_ci	 * If this is the first read, or reading previous namespace finished
25498c2ecf20Sopenharmony_ci	 * and has more namespaces to read, update the namespace cursor.
25508c2ecf20Sopenharmony_ci	 */
25518c2ecf20Sopenharmony_ci	ns = head->r.ns;
25528c2ecf20Sopenharmony_ci	if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) {
25538c2ecf20Sopenharmony_ci		/* Clearing is OK because tomoyo_flush() returned true. */
25548c2ecf20Sopenharmony_ci		memset(&head->r, 0, sizeof(head->r));
25558c2ecf20Sopenharmony_ci		head->r.ns = ns ? ns->next : tomoyo_namespace_list.next;
25568c2ecf20Sopenharmony_ci	}
25578c2ecf20Sopenharmony_ci}
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci/**
25608c2ecf20Sopenharmony_ci * tomoyo_has_more_namespace - Check for unread namespaces.
25618c2ecf20Sopenharmony_ci *
25628c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
25638c2ecf20Sopenharmony_ci *
25648c2ecf20Sopenharmony_ci * Returns true if we have more entries to print, false otherwise.
25658c2ecf20Sopenharmony_ci */
25668c2ecf20Sopenharmony_cistatic inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head)
25678c2ecf20Sopenharmony_ci{
25688c2ecf20Sopenharmony_ci	return (head->type == TOMOYO_EXCEPTIONPOLICY ||
25698c2ecf20Sopenharmony_ci		head->type == TOMOYO_PROFILE) && head->r.eof &&
25708c2ecf20Sopenharmony_ci		head->r.ns->next != &tomoyo_namespace_list;
25718c2ecf20Sopenharmony_ci}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci/**
25748c2ecf20Sopenharmony_ci * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
25758c2ecf20Sopenharmony_ci *
25768c2ecf20Sopenharmony_ci * @head:       Pointer to "struct tomoyo_io_buffer".
25778c2ecf20Sopenharmony_ci * @buffer:     Poiner to buffer to write to.
25788c2ecf20Sopenharmony_ci * @buffer_len: Size of @buffer.
25798c2ecf20Sopenharmony_ci *
25808c2ecf20Sopenharmony_ci * Returns bytes read on success, negative value otherwise.
25818c2ecf20Sopenharmony_ci */
25828c2ecf20Sopenharmony_cissize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
25838c2ecf20Sopenharmony_ci			    const int buffer_len)
25848c2ecf20Sopenharmony_ci{
25858c2ecf20Sopenharmony_ci	int len;
25868c2ecf20Sopenharmony_ci	int idx;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	if (!head->read)
25898c2ecf20Sopenharmony_ci		return -EINVAL;
25908c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&head->io_sem))
25918c2ecf20Sopenharmony_ci		return -EINTR;
25928c2ecf20Sopenharmony_ci	head->read_user_buf = buffer;
25938c2ecf20Sopenharmony_ci	head->read_user_buf_avail = buffer_len;
25948c2ecf20Sopenharmony_ci	idx = tomoyo_read_lock();
25958c2ecf20Sopenharmony_ci	if (tomoyo_flush(head))
25968c2ecf20Sopenharmony_ci		/* Call the policy handler. */
25978c2ecf20Sopenharmony_ci		do {
25988c2ecf20Sopenharmony_ci			tomoyo_set_namespace_cursor(head);
25998c2ecf20Sopenharmony_ci			head->read(head);
26008c2ecf20Sopenharmony_ci		} while (tomoyo_flush(head) &&
26018c2ecf20Sopenharmony_ci			 tomoyo_has_more_namespace(head));
26028c2ecf20Sopenharmony_ci	tomoyo_read_unlock(idx);
26038c2ecf20Sopenharmony_ci	len = head->read_user_buf - buffer;
26048c2ecf20Sopenharmony_ci	mutex_unlock(&head->io_sem);
26058c2ecf20Sopenharmony_ci	return len;
26068c2ecf20Sopenharmony_ci}
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci/**
26098c2ecf20Sopenharmony_ci * tomoyo_parse_policy - Parse a policy line.
26108c2ecf20Sopenharmony_ci *
26118c2ecf20Sopenharmony_ci * @head: Poiter to "struct tomoyo_io_buffer".
26128c2ecf20Sopenharmony_ci * @line: Line to parse.
26138c2ecf20Sopenharmony_ci *
26148c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise.
26158c2ecf20Sopenharmony_ci *
26168c2ecf20Sopenharmony_ci * Caller holds tomoyo_read_lock().
26178c2ecf20Sopenharmony_ci */
26188c2ecf20Sopenharmony_cistatic int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
26198c2ecf20Sopenharmony_ci{
26208c2ecf20Sopenharmony_ci	/* Delete request? */
26218c2ecf20Sopenharmony_ci	head->w.is_delete = !strncmp(line, "delete ", 7);
26228c2ecf20Sopenharmony_ci	if (head->w.is_delete)
26238c2ecf20Sopenharmony_ci		memmove(line, line + 7, strlen(line + 7) + 1);
26248c2ecf20Sopenharmony_ci	/* Selecting namespace to update. */
26258c2ecf20Sopenharmony_ci	if (head->type == TOMOYO_EXCEPTIONPOLICY ||
26268c2ecf20Sopenharmony_ci	    head->type == TOMOYO_PROFILE) {
26278c2ecf20Sopenharmony_ci		if (*line == '<') {
26288c2ecf20Sopenharmony_ci			char *cp = strchr(line, ' ');
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci			if (cp) {
26318c2ecf20Sopenharmony_ci				*cp++ = '\0';
26328c2ecf20Sopenharmony_ci				head->w.ns = tomoyo_assign_namespace(line);
26338c2ecf20Sopenharmony_ci				memmove(line, cp, strlen(cp) + 1);
26348c2ecf20Sopenharmony_ci			} else
26358c2ecf20Sopenharmony_ci				head->w.ns = NULL;
26368c2ecf20Sopenharmony_ci		} else
26378c2ecf20Sopenharmony_ci			head->w.ns = &tomoyo_kernel_namespace;
26388c2ecf20Sopenharmony_ci		/* Don't allow updating if namespace is invalid. */
26398c2ecf20Sopenharmony_ci		if (!head->w.ns)
26408c2ecf20Sopenharmony_ci			return -ENOENT;
26418c2ecf20Sopenharmony_ci	}
26428c2ecf20Sopenharmony_ci	/* Do the update. */
26438c2ecf20Sopenharmony_ci	return head->write(head);
26448c2ecf20Sopenharmony_ci}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci/**
26478c2ecf20Sopenharmony_ci * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
26488c2ecf20Sopenharmony_ci *
26498c2ecf20Sopenharmony_ci * @head:       Pointer to "struct tomoyo_io_buffer".
26508c2ecf20Sopenharmony_ci * @buffer:     Pointer to buffer to read from.
26518c2ecf20Sopenharmony_ci * @buffer_len: Size of @buffer.
26528c2ecf20Sopenharmony_ci *
26538c2ecf20Sopenharmony_ci * Returns @buffer_len on success, negative value otherwise.
26548c2ecf20Sopenharmony_ci */
26558c2ecf20Sopenharmony_cissize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
26568c2ecf20Sopenharmony_ci			     const char __user *buffer, const int buffer_len)
26578c2ecf20Sopenharmony_ci{
26588c2ecf20Sopenharmony_ci	int error = buffer_len;
26598c2ecf20Sopenharmony_ci	size_t avail_len = buffer_len;
26608c2ecf20Sopenharmony_ci	char *cp0 = head->write_buf;
26618c2ecf20Sopenharmony_ci	int idx;
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	if (!head->write)
26648c2ecf20Sopenharmony_ci		return -EINVAL;
26658c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&head->io_sem))
26668c2ecf20Sopenharmony_ci		return -EINTR;
26678c2ecf20Sopenharmony_ci	head->read_user_buf_avail = 0;
26688c2ecf20Sopenharmony_ci	idx = tomoyo_read_lock();
26698c2ecf20Sopenharmony_ci	/* Read a line and dispatch it to the policy handler. */
26708c2ecf20Sopenharmony_ci	while (avail_len > 0) {
26718c2ecf20Sopenharmony_ci		char c;
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci		if (head->w.avail >= head->writebuf_size - 1) {
26748c2ecf20Sopenharmony_ci			const int len = head->writebuf_size * 2;
26758c2ecf20Sopenharmony_ci			char *cp = kzalloc(len, GFP_NOFS);
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci			if (!cp) {
26788c2ecf20Sopenharmony_ci				error = -ENOMEM;
26798c2ecf20Sopenharmony_ci				break;
26808c2ecf20Sopenharmony_ci			}
26818c2ecf20Sopenharmony_ci			memmove(cp, cp0, head->w.avail);
26828c2ecf20Sopenharmony_ci			kfree(cp0);
26838c2ecf20Sopenharmony_ci			head->write_buf = cp;
26848c2ecf20Sopenharmony_ci			cp0 = cp;
26858c2ecf20Sopenharmony_ci			head->writebuf_size = len;
26868c2ecf20Sopenharmony_ci		}
26878c2ecf20Sopenharmony_ci		if (get_user(c, buffer)) {
26888c2ecf20Sopenharmony_ci			error = -EFAULT;
26898c2ecf20Sopenharmony_ci			break;
26908c2ecf20Sopenharmony_ci		}
26918c2ecf20Sopenharmony_ci		buffer++;
26928c2ecf20Sopenharmony_ci		avail_len--;
26938c2ecf20Sopenharmony_ci		cp0[head->w.avail++] = c;
26948c2ecf20Sopenharmony_ci		if (c != '\n')
26958c2ecf20Sopenharmony_ci			continue;
26968c2ecf20Sopenharmony_ci		cp0[head->w.avail - 1] = '\0';
26978c2ecf20Sopenharmony_ci		head->w.avail = 0;
26988c2ecf20Sopenharmony_ci		tomoyo_normalize_line(cp0);
26998c2ecf20Sopenharmony_ci		if (!strcmp(cp0, "reset")) {
27008c2ecf20Sopenharmony_ci			head->w.ns = &tomoyo_kernel_namespace;
27018c2ecf20Sopenharmony_ci			head->w.domain = NULL;
27028c2ecf20Sopenharmony_ci			memset(&head->r, 0, sizeof(head->r));
27038c2ecf20Sopenharmony_ci			continue;
27048c2ecf20Sopenharmony_ci		}
27058c2ecf20Sopenharmony_ci		/* Don't allow updating policies by non manager programs. */
27068c2ecf20Sopenharmony_ci		switch (head->type) {
27078c2ecf20Sopenharmony_ci		case TOMOYO_PROCESS_STATUS:
27088c2ecf20Sopenharmony_ci			/* This does not write anything. */
27098c2ecf20Sopenharmony_ci			break;
27108c2ecf20Sopenharmony_ci		case TOMOYO_DOMAINPOLICY:
27118c2ecf20Sopenharmony_ci			if (tomoyo_select_domain(head, cp0))
27128c2ecf20Sopenharmony_ci				continue;
27138c2ecf20Sopenharmony_ci			fallthrough;
27148c2ecf20Sopenharmony_ci		case TOMOYO_EXCEPTIONPOLICY:
27158c2ecf20Sopenharmony_ci			if (!strcmp(cp0, "select transition_only")) {
27168c2ecf20Sopenharmony_ci				head->r.print_transition_related_only = true;
27178c2ecf20Sopenharmony_ci				continue;
27188c2ecf20Sopenharmony_ci			}
27198c2ecf20Sopenharmony_ci			fallthrough;
27208c2ecf20Sopenharmony_ci		default:
27218c2ecf20Sopenharmony_ci			if (!tomoyo_manager()) {
27228c2ecf20Sopenharmony_ci				error = -EPERM;
27238c2ecf20Sopenharmony_ci				goto out;
27248c2ecf20Sopenharmony_ci			}
27258c2ecf20Sopenharmony_ci		}
27268c2ecf20Sopenharmony_ci		switch (tomoyo_parse_policy(head, cp0)) {
27278c2ecf20Sopenharmony_ci		case -EPERM:
27288c2ecf20Sopenharmony_ci			error = -EPERM;
27298c2ecf20Sopenharmony_ci			goto out;
27308c2ecf20Sopenharmony_ci		case 0:
27318c2ecf20Sopenharmony_ci			switch (head->type) {
27328c2ecf20Sopenharmony_ci			case TOMOYO_DOMAINPOLICY:
27338c2ecf20Sopenharmony_ci			case TOMOYO_EXCEPTIONPOLICY:
27348c2ecf20Sopenharmony_ci			case TOMOYO_STAT:
27358c2ecf20Sopenharmony_ci			case TOMOYO_PROFILE:
27368c2ecf20Sopenharmony_ci			case TOMOYO_MANAGER:
27378c2ecf20Sopenharmony_ci				tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
27388c2ecf20Sopenharmony_ci				break;
27398c2ecf20Sopenharmony_ci			default:
27408c2ecf20Sopenharmony_ci				break;
27418c2ecf20Sopenharmony_ci			}
27428c2ecf20Sopenharmony_ci			break;
27438c2ecf20Sopenharmony_ci		}
27448c2ecf20Sopenharmony_ci	}
27458c2ecf20Sopenharmony_ciout:
27468c2ecf20Sopenharmony_ci	tomoyo_read_unlock(idx);
27478c2ecf20Sopenharmony_ci	mutex_unlock(&head->io_sem);
27488c2ecf20Sopenharmony_ci	return error;
27498c2ecf20Sopenharmony_ci}
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci/**
27528c2ecf20Sopenharmony_ci * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
27538c2ecf20Sopenharmony_ci *
27548c2ecf20Sopenharmony_ci * @head: Pointer to "struct tomoyo_io_buffer".
27558c2ecf20Sopenharmony_ci */
27568c2ecf20Sopenharmony_civoid tomoyo_close_control(struct tomoyo_io_buffer *head)
27578c2ecf20Sopenharmony_ci{
27588c2ecf20Sopenharmony_ci	/*
27598c2ecf20Sopenharmony_ci	 * If the file is /sys/kernel/security/tomoyo/query , decrement the
27608c2ecf20Sopenharmony_ci	 * observer counter.
27618c2ecf20Sopenharmony_ci	 */
27628c2ecf20Sopenharmony_ci	if (head->type == TOMOYO_QUERY &&
27638c2ecf20Sopenharmony_ci	    atomic_dec_and_test(&tomoyo_query_observers))
27648c2ecf20Sopenharmony_ci		wake_up_all(&tomoyo_answer_wait);
27658c2ecf20Sopenharmony_ci	tomoyo_notify_gc(head, false);
27668c2ecf20Sopenharmony_ci}
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci/**
27698c2ecf20Sopenharmony_ci * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
27708c2ecf20Sopenharmony_ci */
27718c2ecf20Sopenharmony_civoid tomoyo_check_profile(void)
27728c2ecf20Sopenharmony_ci{
27738c2ecf20Sopenharmony_ci	struct tomoyo_domain_info *domain;
27748c2ecf20Sopenharmony_ci	const int idx = tomoyo_read_lock();
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	tomoyo_policy_loaded = true;
27778c2ecf20Sopenharmony_ci	pr_info("TOMOYO: 2.6.0\n");
27788c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
27798c2ecf20Sopenharmony_ci				srcu_read_lock_held(&tomoyo_ss)) {
27808c2ecf20Sopenharmony_ci		const u8 profile = domain->profile;
27818c2ecf20Sopenharmony_ci		struct tomoyo_policy_namespace *ns = domain->ns;
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci		if (ns->profile_version == 20110903) {
27848c2ecf20Sopenharmony_ci			pr_info_once("Converting profile version from %u to %u.\n",
27858c2ecf20Sopenharmony_ci				     20110903, 20150505);
27868c2ecf20Sopenharmony_ci			ns->profile_version = 20150505;
27878c2ecf20Sopenharmony_ci		}
27888c2ecf20Sopenharmony_ci		if (ns->profile_version != 20150505)
27898c2ecf20Sopenharmony_ci			pr_err("Profile version %u is not supported.\n",
27908c2ecf20Sopenharmony_ci			       ns->profile_version);
27918c2ecf20Sopenharmony_ci		else if (!ns->profile_ptr[profile])
27928c2ecf20Sopenharmony_ci			pr_err("Profile %u (used by '%s') is not defined.\n",
27938c2ecf20Sopenharmony_ci			       profile, domain->domainname->name);
27948c2ecf20Sopenharmony_ci		else
27958c2ecf20Sopenharmony_ci			continue;
27968c2ecf20Sopenharmony_ci		pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n");
27978c2ecf20Sopenharmony_ci		pr_err("Please see https://tomoyo.osdn.jp/2.6/ for more information.\n");
27988c2ecf20Sopenharmony_ci		panic("STOP!");
27998c2ecf20Sopenharmony_ci	}
28008c2ecf20Sopenharmony_ci	tomoyo_read_unlock(idx);
28018c2ecf20Sopenharmony_ci	pr_info("Mandatory Access Control activated.\n");
28028c2ecf20Sopenharmony_ci}
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci/**
28058c2ecf20Sopenharmony_ci * tomoyo_load_builtin_policy - Load built-in policy.
28068c2ecf20Sopenharmony_ci *
28078c2ecf20Sopenharmony_ci * Returns nothing.
28088c2ecf20Sopenharmony_ci */
28098c2ecf20Sopenharmony_civoid __init tomoyo_load_builtin_policy(void)
28108c2ecf20Sopenharmony_ci{
28118c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
28128c2ecf20Sopenharmony_ci	static char tomoyo_builtin_profile[] __initdata =
28138c2ecf20Sopenharmony_ci		"PROFILE_VERSION=20150505\n"
28148c2ecf20Sopenharmony_ci		"0-CONFIG={ mode=learning grant_log=no reject_log=yes }\n";
28158c2ecf20Sopenharmony_ci	static char tomoyo_builtin_exception_policy[] __initdata =
28168c2ecf20Sopenharmony_ci		"aggregator proc:/self/exe /proc/self/exe\n";
28178c2ecf20Sopenharmony_ci	static char tomoyo_builtin_domain_policy[] __initdata = "";
28188c2ecf20Sopenharmony_ci	static char tomoyo_builtin_manager[] __initdata = "";
28198c2ecf20Sopenharmony_ci	static char tomoyo_builtin_stat[] __initdata = "";
28208c2ecf20Sopenharmony_ci#else
28218c2ecf20Sopenharmony_ci	/*
28228c2ecf20Sopenharmony_ci	 * This include file is manually created and contains built-in policy
28238c2ecf20Sopenharmony_ci	 * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy",
28248c2ecf20Sopenharmony_ci	 * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager",
28258c2ecf20Sopenharmony_ci	 * "tomoyo_builtin_stat" in the form of "static char [] __initdata".
28268c2ecf20Sopenharmony_ci	 */
28278c2ecf20Sopenharmony_ci#include "builtin-policy.h"
28288c2ecf20Sopenharmony_ci#endif
28298c2ecf20Sopenharmony_ci	u8 i;
28308c2ecf20Sopenharmony_ci	const int idx = tomoyo_read_lock();
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++) {
28338c2ecf20Sopenharmony_ci		struct tomoyo_io_buffer head = { };
28348c2ecf20Sopenharmony_ci		char *start = "";
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci		switch (i) {
28378c2ecf20Sopenharmony_ci		case 0:
28388c2ecf20Sopenharmony_ci			start = tomoyo_builtin_profile;
28398c2ecf20Sopenharmony_ci			head.type = TOMOYO_PROFILE;
28408c2ecf20Sopenharmony_ci			head.write = tomoyo_write_profile;
28418c2ecf20Sopenharmony_ci			break;
28428c2ecf20Sopenharmony_ci		case 1:
28438c2ecf20Sopenharmony_ci			start = tomoyo_builtin_exception_policy;
28448c2ecf20Sopenharmony_ci			head.type = TOMOYO_EXCEPTIONPOLICY;
28458c2ecf20Sopenharmony_ci			head.write = tomoyo_write_exception;
28468c2ecf20Sopenharmony_ci			break;
28478c2ecf20Sopenharmony_ci		case 2:
28488c2ecf20Sopenharmony_ci			start = tomoyo_builtin_domain_policy;
28498c2ecf20Sopenharmony_ci			head.type = TOMOYO_DOMAINPOLICY;
28508c2ecf20Sopenharmony_ci			head.write = tomoyo_write_domain;
28518c2ecf20Sopenharmony_ci			break;
28528c2ecf20Sopenharmony_ci		case 3:
28538c2ecf20Sopenharmony_ci			start = tomoyo_builtin_manager;
28548c2ecf20Sopenharmony_ci			head.type = TOMOYO_MANAGER;
28558c2ecf20Sopenharmony_ci			head.write = tomoyo_write_manager;
28568c2ecf20Sopenharmony_ci			break;
28578c2ecf20Sopenharmony_ci		case 4:
28588c2ecf20Sopenharmony_ci			start = tomoyo_builtin_stat;
28598c2ecf20Sopenharmony_ci			head.type = TOMOYO_STAT;
28608c2ecf20Sopenharmony_ci			head.write = tomoyo_write_stat;
28618c2ecf20Sopenharmony_ci			break;
28628c2ecf20Sopenharmony_ci		}
28638c2ecf20Sopenharmony_ci		while (1) {
28648c2ecf20Sopenharmony_ci			char *end = strchr(start, '\n');
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci			if (!end)
28678c2ecf20Sopenharmony_ci				break;
28688c2ecf20Sopenharmony_ci			*end = '\0';
28698c2ecf20Sopenharmony_ci			tomoyo_normalize_line(start);
28708c2ecf20Sopenharmony_ci			head.write_buf = start;
28718c2ecf20Sopenharmony_ci			tomoyo_parse_policy(&head, start);
28728c2ecf20Sopenharmony_ci			start = end + 1;
28738c2ecf20Sopenharmony_ci		}
28748c2ecf20Sopenharmony_ci	}
28758c2ecf20Sopenharmony_ci	tomoyo_read_unlock(idx);
28768c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
28778c2ecf20Sopenharmony_ci	tomoyo_check_profile();
28788c2ecf20Sopenharmony_ci#endif
28798c2ecf20Sopenharmony_ci}
2880