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