1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 29590837bSKentaro Takeda /* 39590837bSKentaro Takeda * security/tomoyo/common.c 49590837bSKentaro Takeda * 50f2a55d5STetsuo Handa * Copyright (C) 2005-2011 NTT DATA CORPORATION 69590837bSKentaro Takeda */ 79590837bSKentaro Takeda 89590837bSKentaro Takeda #include <linux/uaccess.h> 95a0e3ad6STejun Heo #include <linux/slab.h> 109590837bSKentaro Takeda #include <linux/security.h> 11ea181a34SLucas De Marchi #include <linux/string_helpers.h> 129590837bSKentaro Takeda #include "common.h" 139590837bSKentaro Takeda 14eadd99ccSTetsuo Handa /* String table for operation mode. */ 15eadd99ccSTetsuo Handa const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = { 16eadd99ccSTetsuo Handa [TOMOYO_CONFIG_DISABLED] = "disabled", 17eadd99ccSTetsuo Handa [TOMOYO_CONFIG_LEARNING] = "learning", 18eadd99ccSTetsuo Handa [TOMOYO_CONFIG_PERMISSIVE] = "permissive", 19eadd99ccSTetsuo Handa [TOMOYO_CONFIG_ENFORCING] = "enforcing" 209590837bSKentaro Takeda }; 219590837bSKentaro Takeda 2257c2590fSTetsuo Handa /* String table for /sys/kernel/security/tomoyo/profile */ 232c47ab93STetsuo Handa const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX 2457c2590fSTetsuo Handa + TOMOYO_MAX_MAC_CATEGORY_INDEX] = { 25d58e0da8STetsuo Handa /* CONFIG::file group */ 262c47ab93STetsuo Handa [TOMOYO_MAC_FILE_EXECUTE] = "execute", 272c47ab93STetsuo Handa [TOMOYO_MAC_FILE_OPEN] = "open", 282c47ab93STetsuo Handa [TOMOYO_MAC_FILE_CREATE] = "create", 292c47ab93STetsuo Handa [TOMOYO_MAC_FILE_UNLINK] = "unlink", 302c47ab93STetsuo Handa [TOMOYO_MAC_FILE_GETATTR] = "getattr", 312c47ab93STetsuo Handa [TOMOYO_MAC_FILE_MKDIR] = "mkdir", 322c47ab93STetsuo Handa [TOMOYO_MAC_FILE_RMDIR] = "rmdir", 332c47ab93STetsuo Handa [TOMOYO_MAC_FILE_MKFIFO] = "mkfifo", 342c47ab93STetsuo Handa [TOMOYO_MAC_FILE_MKSOCK] = "mksock", 352c47ab93STetsuo Handa [TOMOYO_MAC_FILE_TRUNCATE] = "truncate", 362c47ab93STetsuo Handa [TOMOYO_MAC_FILE_SYMLINK] = "symlink", 372c47ab93STetsuo Handa [TOMOYO_MAC_FILE_MKBLOCK] = "mkblock", 382c47ab93STetsuo Handa [TOMOYO_MAC_FILE_MKCHAR] = "mkchar", 392c47ab93STetsuo Handa [TOMOYO_MAC_FILE_LINK] = "link", 402c47ab93STetsuo Handa [TOMOYO_MAC_FILE_RENAME] = "rename", 412c47ab93STetsuo Handa [TOMOYO_MAC_FILE_CHMOD] = "chmod", 422c47ab93STetsuo Handa [TOMOYO_MAC_FILE_CHOWN] = "chown", 432c47ab93STetsuo Handa [TOMOYO_MAC_FILE_CHGRP] = "chgrp", 442c47ab93STetsuo Handa [TOMOYO_MAC_FILE_IOCTL] = "ioctl", 452c47ab93STetsuo Handa [TOMOYO_MAC_FILE_CHROOT] = "chroot", 462c47ab93STetsuo Handa [TOMOYO_MAC_FILE_MOUNT] = "mount", 472c47ab93STetsuo Handa [TOMOYO_MAC_FILE_UMOUNT] = "unmount", 482c47ab93STetsuo Handa [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root", 49059d84dbSTetsuo Handa /* CONFIG::network group */ 50059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind", 51059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen", 52059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect", 53059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind", 54059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send", 55059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind", 56059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send", 57059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind", 58059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen", 59059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect", 60059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind", 61059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send", 62059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind", 63059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen", 64059d84dbSTetsuo Handa [TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect", 65d58e0da8STetsuo Handa /* CONFIG::misc group */ 66d58e0da8STetsuo Handa [TOMOYO_MAC_ENVIRON] = "env", 67d58e0da8STetsuo Handa /* CONFIG group */ 6857c2590fSTetsuo Handa [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file", 69059d84dbSTetsuo Handa [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network", 70d58e0da8STetsuo Handa [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc", 719590837bSKentaro Takeda }; 729590837bSKentaro Takeda 732066a361STetsuo Handa /* String table for conditions. */ 742066a361STetsuo Handa const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = { 752066a361STetsuo Handa [TOMOYO_TASK_UID] = "task.uid", 762066a361STetsuo Handa [TOMOYO_TASK_EUID] = "task.euid", 772066a361STetsuo Handa [TOMOYO_TASK_SUID] = "task.suid", 782066a361STetsuo Handa [TOMOYO_TASK_FSUID] = "task.fsuid", 792066a361STetsuo Handa [TOMOYO_TASK_GID] = "task.gid", 802066a361STetsuo Handa [TOMOYO_TASK_EGID] = "task.egid", 812066a361STetsuo Handa [TOMOYO_TASK_SGID] = "task.sgid", 822066a361STetsuo Handa [TOMOYO_TASK_FSGID] = "task.fsgid", 832066a361STetsuo Handa [TOMOYO_TASK_PID] = "task.pid", 842066a361STetsuo Handa [TOMOYO_TASK_PPID] = "task.ppid", 855b636857STetsuo Handa [TOMOYO_EXEC_ARGC] = "exec.argc", 865b636857STetsuo Handa [TOMOYO_EXEC_ENVC] = "exec.envc", 878761afd4STetsuo Handa [TOMOYO_TYPE_IS_SOCKET] = "socket", 888761afd4STetsuo Handa [TOMOYO_TYPE_IS_SYMLINK] = "symlink", 898761afd4STetsuo Handa [TOMOYO_TYPE_IS_FILE] = "file", 908761afd4STetsuo Handa [TOMOYO_TYPE_IS_BLOCK_DEV] = "block", 918761afd4STetsuo Handa [TOMOYO_TYPE_IS_DIRECTORY] = "directory", 928761afd4STetsuo Handa [TOMOYO_TYPE_IS_CHAR_DEV] = "char", 938761afd4STetsuo Handa [TOMOYO_TYPE_IS_FIFO] = "fifo", 948761afd4STetsuo Handa [TOMOYO_MODE_SETUID] = "setuid", 958761afd4STetsuo Handa [TOMOYO_MODE_SETGID] = "setgid", 968761afd4STetsuo Handa [TOMOYO_MODE_STICKY] = "sticky", 978761afd4STetsuo Handa [TOMOYO_MODE_OWNER_READ] = "owner_read", 988761afd4STetsuo Handa [TOMOYO_MODE_OWNER_WRITE] = "owner_write", 998761afd4STetsuo Handa [TOMOYO_MODE_OWNER_EXECUTE] = "owner_execute", 1008761afd4STetsuo Handa [TOMOYO_MODE_GROUP_READ] = "group_read", 1018761afd4STetsuo Handa [TOMOYO_MODE_GROUP_WRITE] = "group_write", 1028761afd4STetsuo Handa [TOMOYO_MODE_GROUP_EXECUTE] = "group_execute", 1038761afd4STetsuo Handa [TOMOYO_MODE_OTHERS_READ] = "others_read", 1048761afd4STetsuo Handa [TOMOYO_MODE_OTHERS_WRITE] = "others_write", 1058761afd4STetsuo Handa [TOMOYO_MODE_OTHERS_EXECUTE] = "others_execute", 1062ca9bf45STetsuo Handa [TOMOYO_EXEC_REALPATH] = "exec.realpath", 1072ca9bf45STetsuo Handa [TOMOYO_SYMLINK_TARGET] = "symlink.target", 1088761afd4STetsuo Handa [TOMOYO_PATH1_UID] = "path1.uid", 1098761afd4STetsuo Handa [TOMOYO_PATH1_GID] = "path1.gid", 1108761afd4STetsuo Handa [TOMOYO_PATH1_INO] = "path1.ino", 1118761afd4STetsuo Handa [TOMOYO_PATH1_MAJOR] = "path1.major", 1128761afd4STetsuo Handa [TOMOYO_PATH1_MINOR] = "path1.minor", 1138761afd4STetsuo Handa [TOMOYO_PATH1_PERM] = "path1.perm", 1148761afd4STetsuo Handa [TOMOYO_PATH1_TYPE] = "path1.type", 1158761afd4STetsuo Handa [TOMOYO_PATH1_DEV_MAJOR] = "path1.dev_major", 1168761afd4STetsuo Handa [TOMOYO_PATH1_DEV_MINOR] = "path1.dev_minor", 1178761afd4STetsuo Handa [TOMOYO_PATH2_UID] = "path2.uid", 1188761afd4STetsuo Handa [TOMOYO_PATH2_GID] = "path2.gid", 1198761afd4STetsuo Handa [TOMOYO_PATH2_INO] = "path2.ino", 1208761afd4STetsuo Handa [TOMOYO_PATH2_MAJOR] = "path2.major", 1218761afd4STetsuo Handa [TOMOYO_PATH2_MINOR] = "path2.minor", 1228761afd4STetsuo Handa [TOMOYO_PATH2_PERM] = "path2.perm", 1238761afd4STetsuo Handa [TOMOYO_PATH2_TYPE] = "path2.type", 1248761afd4STetsuo Handa [TOMOYO_PATH2_DEV_MAJOR] = "path2.dev_major", 1258761afd4STetsuo Handa [TOMOYO_PATH2_DEV_MINOR] = "path2.dev_minor", 1268761afd4STetsuo Handa [TOMOYO_PATH1_PARENT_UID] = "path1.parent.uid", 1278761afd4STetsuo Handa [TOMOYO_PATH1_PARENT_GID] = "path1.parent.gid", 1288761afd4STetsuo Handa [TOMOYO_PATH1_PARENT_INO] = "path1.parent.ino", 1298761afd4STetsuo Handa [TOMOYO_PATH1_PARENT_PERM] = "path1.parent.perm", 1308761afd4STetsuo Handa [TOMOYO_PATH2_PARENT_UID] = "path2.parent.uid", 1318761afd4STetsuo Handa [TOMOYO_PATH2_PARENT_GID] = "path2.parent.gid", 1328761afd4STetsuo Handa [TOMOYO_PATH2_PARENT_INO] = "path2.parent.ino", 1338761afd4STetsuo Handa [TOMOYO_PATH2_PARENT_PERM] = "path2.parent.perm", 1342066a361STetsuo Handa }; 1352066a361STetsuo Handa 136d5ca1725STetsuo Handa /* String table for PREFERENCE keyword. */ 137d5ca1725STetsuo Handa static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = { 138eadd99ccSTetsuo Handa [TOMOYO_PREF_MAX_AUDIT_LOG] = "max_audit_log", 139d5ca1725STetsuo Handa [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry", 140d5ca1725STetsuo Handa }; 141d5ca1725STetsuo Handa 1422c47ab93STetsuo Handa /* String table for path operation. */ 1432c47ab93STetsuo Handa const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { 1442c47ab93STetsuo Handa [TOMOYO_TYPE_EXECUTE] = "execute", 1452c47ab93STetsuo Handa [TOMOYO_TYPE_READ] = "read", 1462c47ab93STetsuo Handa [TOMOYO_TYPE_WRITE] = "write", 1472c47ab93STetsuo Handa [TOMOYO_TYPE_APPEND] = "append", 1482c47ab93STetsuo Handa [TOMOYO_TYPE_UNLINK] = "unlink", 1492c47ab93STetsuo Handa [TOMOYO_TYPE_GETATTR] = "getattr", 1502c47ab93STetsuo Handa [TOMOYO_TYPE_RMDIR] = "rmdir", 1512c47ab93STetsuo Handa [TOMOYO_TYPE_TRUNCATE] = "truncate", 1522c47ab93STetsuo Handa [TOMOYO_TYPE_SYMLINK] = "symlink", 1532c47ab93STetsuo Handa [TOMOYO_TYPE_CHROOT] = "chroot", 1542c47ab93STetsuo Handa [TOMOYO_TYPE_UMOUNT] = "unmount", 1552c47ab93STetsuo Handa }; 1562c47ab93STetsuo Handa 157059d84dbSTetsuo Handa /* String table for socket's operation. */ 158059d84dbSTetsuo Handa const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = { 159059d84dbSTetsuo Handa [TOMOYO_NETWORK_BIND] = "bind", 160059d84dbSTetsuo Handa [TOMOYO_NETWORK_LISTEN] = "listen", 161059d84dbSTetsuo Handa [TOMOYO_NETWORK_CONNECT] = "connect", 162059d84dbSTetsuo Handa [TOMOYO_NETWORK_SEND] = "send", 163059d84dbSTetsuo Handa }; 164059d84dbSTetsuo Handa 1652c47ab93STetsuo Handa /* String table for categories. */ 1662c47ab93STetsuo Handa static const char * const tomoyo_category_keywords 1672c47ab93STetsuo Handa [TOMOYO_MAX_MAC_CATEGORY_INDEX] = { 1682c47ab93STetsuo Handa [TOMOYO_MAC_CATEGORY_FILE] = "file", 169059d84dbSTetsuo Handa [TOMOYO_MAC_CATEGORY_NETWORK] = "network", 170d58e0da8STetsuo Handa [TOMOYO_MAC_CATEGORY_MISC] = "misc", 1712c47ab93STetsuo Handa }; 1722c47ab93STetsuo Handa 1739590837bSKentaro Takeda /* Permit policy management by non-root user? */ 1749590837bSKentaro Takeda static bool tomoyo_manage_by_non_root; 1759590837bSKentaro Takeda 1769590837bSKentaro Takeda /* Utility functions. */ 1779590837bSKentaro Takeda 1787762fbffSTetsuo Handa /** 179d5ca1725STetsuo Handa * tomoyo_addprintf - strncat()-like-snprintf(). 180d5ca1725STetsuo Handa * 181d5ca1725STetsuo Handa * @buffer: Buffer to write to. Must be '\0'-terminated. 182d5ca1725STetsuo Handa * @len: Size of @buffer. 183d5ca1725STetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 184d5ca1725STetsuo Handa * 185d5ca1725STetsuo Handa * Returns nothing. 186d5ca1725STetsuo Handa */ 187a959dbd9SChristian Göttsche __printf(3, 4) 188f23571e8STetsuo Handa static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) 189f23571e8STetsuo Handa { 190f23571e8STetsuo Handa va_list args; 191f23571e8STetsuo Handa const int pos = strlen(buffer); 192cdcf6723STetsuo Handa 193f23571e8STetsuo Handa va_start(args, fmt); 194f23571e8STetsuo Handa vsnprintf(buffer + pos, len - pos - 1, fmt, args); 195f23571e8STetsuo Handa va_end(args); 196f23571e8STetsuo Handa } 197f23571e8STetsuo Handa 198f23571e8STetsuo Handa /** 199f23571e8STetsuo Handa * tomoyo_flush - Flush queued string to userspace's buffer. 200f23571e8STetsuo Handa * 201f23571e8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 202f23571e8STetsuo Handa * 203f23571e8STetsuo Handa * Returns true if all data was flushed, false otherwise. 204f23571e8STetsuo Handa */ 205f23571e8STetsuo Handa static bool tomoyo_flush(struct tomoyo_io_buffer *head) 206f23571e8STetsuo Handa { 207f23571e8STetsuo Handa while (head->r.w_pos) { 208f23571e8STetsuo Handa const char *w = head->r.w[0]; 2092c47ab93STetsuo Handa size_t len = strlen(w); 210cdcf6723STetsuo Handa 211f23571e8STetsuo Handa if (len) { 212f23571e8STetsuo Handa if (len > head->read_user_buf_avail) 213f23571e8STetsuo Handa len = head->read_user_buf_avail; 214f23571e8STetsuo Handa if (!len) 215f23571e8STetsuo Handa return false; 216f23571e8STetsuo Handa if (copy_to_user(head->read_user_buf, w, len)) 217f23571e8STetsuo Handa return false; 218f23571e8STetsuo Handa head->read_user_buf_avail -= len; 219f23571e8STetsuo Handa head->read_user_buf += len; 220f23571e8STetsuo Handa w += len; 221f23571e8STetsuo Handa } 222f23571e8STetsuo Handa head->r.w[0] = w; 223c0fa797aSTetsuo Handa if (*w) 224f23571e8STetsuo Handa return false; 225eadd99ccSTetsuo Handa /* Add '\0' for audit logs and query. */ 226f23571e8STetsuo Handa if (head->poll) { 227f23571e8STetsuo Handa if (!head->read_user_buf_avail || 228f23571e8STetsuo Handa copy_to_user(head->read_user_buf, "", 1)) 229f23571e8STetsuo Handa return false; 230f23571e8STetsuo Handa head->read_user_buf_avail--; 231f23571e8STetsuo Handa head->read_user_buf++; 232f23571e8STetsuo Handa } 233f23571e8STetsuo Handa head->r.w_pos--; 234f23571e8STetsuo Handa for (len = 0; len < head->r.w_pos; len++) 235f23571e8STetsuo Handa head->r.w[len] = head->r.w[len + 1]; 236f23571e8STetsuo Handa } 237f23571e8STetsuo Handa head->r.avail = 0; 238f23571e8STetsuo Handa return true; 239f23571e8STetsuo Handa } 240f23571e8STetsuo Handa 241f23571e8STetsuo Handa /** 242f23571e8STetsuo Handa * tomoyo_set_string - Queue string to "struct tomoyo_io_buffer" structure. 243f23571e8STetsuo Handa * 244f23571e8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 245f23571e8STetsuo Handa * @string: String to print. 246f23571e8STetsuo Handa * 247f23571e8STetsuo Handa * Note that @string has to be kept valid until @head is kfree()d. 248f23571e8STetsuo Handa * This means that char[] allocated on stack memory cannot be passed to 249f23571e8STetsuo Handa * this function. Use tomoyo_io_printf() for char[] allocated on stack memory. 250f23571e8STetsuo Handa */ 251f23571e8STetsuo Handa static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string) 252f23571e8STetsuo Handa { 253f23571e8STetsuo Handa if (head->r.w_pos < TOMOYO_MAX_IO_READ_QUEUE) { 254f23571e8STetsuo Handa head->r.w[head->r.w_pos++] = string; 255f23571e8STetsuo Handa tomoyo_flush(head); 256f23571e8STetsuo Handa } else 257f23571e8STetsuo Handa WARN_ON(1); 258f23571e8STetsuo Handa } 259f23571e8STetsuo Handa 260778c4a4dSTetsuo Handa static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, 261778c4a4dSTetsuo Handa ...) __printf(2, 3); 262778c4a4dSTetsuo Handa 263f23571e8STetsuo Handa /** 264f23571e8STetsuo Handa * tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure. 265f23571e8STetsuo Handa * 266f23571e8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 267f23571e8STetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 268f23571e8STetsuo Handa */ 269778c4a4dSTetsuo Handa static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, 270778c4a4dSTetsuo Handa ...) 271f23571e8STetsuo Handa { 272f23571e8STetsuo Handa va_list args; 2732c47ab93STetsuo Handa size_t len; 2742c47ab93STetsuo Handa size_t pos = head->r.avail; 275f23571e8STetsuo Handa int size = head->readbuf_size - pos; 276cdcf6723STetsuo Handa 277f23571e8STetsuo Handa if (size <= 0) 278f23571e8STetsuo Handa return; 279f23571e8STetsuo Handa va_start(args, fmt); 280f23571e8STetsuo Handa len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1; 281f23571e8STetsuo Handa va_end(args); 282f23571e8STetsuo Handa if (pos + len >= head->readbuf_size) { 283f23571e8STetsuo Handa WARN_ON(1); 284f23571e8STetsuo Handa return; 285f23571e8STetsuo Handa } 286f23571e8STetsuo Handa head->r.avail += len; 287f23571e8STetsuo Handa tomoyo_set_string(head, head->read_buf + pos); 288f23571e8STetsuo Handa } 289f23571e8STetsuo Handa 2900d2171d7STetsuo Handa /** 2910d2171d7STetsuo Handa * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure. 2920d2171d7STetsuo Handa * 2930d2171d7STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 2940d2171d7STetsuo Handa * 2950d2171d7STetsuo Handa * Returns nothing. 2960d2171d7STetsuo Handa */ 297f23571e8STetsuo Handa static void tomoyo_set_space(struct tomoyo_io_buffer *head) 298f23571e8STetsuo Handa { 299f23571e8STetsuo Handa tomoyo_set_string(head, " "); 300f23571e8STetsuo Handa } 301f23571e8STetsuo Handa 3020d2171d7STetsuo Handa /** 3030d2171d7STetsuo Handa * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure. 3040d2171d7STetsuo Handa * 3050d2171d7STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 3060d2171d7STetsuo Handa * 3070d2171d7STetsuo Handa * Returns nothing. 3080d2171d7STetsuo Handa */ 309f23571e8STetsuo Handa static bool tomoyo_set_lf(struct tomoyo_io_buffer *head) 310f23571e8STetsuo Handa { 311f23571e8STetsuo Handa tomoyo_set_string(head, "\n"); 312f23571e8STetsuo Handa return !head->r.w_pos; 313f23571e8STetsuo Handa } 314f23571e8STetsuo Handa 31557c2590fSTetsuo Handa /** 3160d2171d7STetsuo Handa * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure. 3170d2171d7STetsuo Handa * 3180d2171d7STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 3190d2171d7STetsuo Handa * 3200d2171d7STetsuo Handa * Returns nothing. 3210d2171d7STetsuo Handa */ 3220d2171d7STetsuo Handa static void tomoyo_set_slash(struct tomoyo_io_buffer *head) 3230d2171d7STetsuo Handa { 3240d2171d7STetsuo Handa tomoyo_set_string(head, "/"); 3250d2171d7STetsuo Handa } 3260d2171d7STetsuo Handa 327bd03a3e4STetsuo Handa /* List of namespaces. */ 328bd03a3e4STetsuo Handa LIST_HEAD(tomoyo_namespace_list); 329bd03a3e4STetsuo Handa /* True if namespace other than tomoyo_kernel_namespace is defined. */ 330bd03a3e4STetsuo Handa static bool tomoyo_namespace_enabled; 331bd03a3e4STetsuo Handa 332bd03a3e4STetsuo Handa /** 333bd03a3e4STetsuo Handa * tomoyo_init_policy_namespace - Initialize namespace. 334bd03a3e4STetsuo Handa * 335bd03a3e4STetsuo Handa * @ns: Pointer to "struct tomoyo_policy_namespace". 336bd03a3e4STetsuo Handa * 337bd03a3e4STetsuo Handa * Returns nothing. 338bd03a3e4STetsuo Handa */ 339bd03a3e4STetsuo Handa void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) 340bd03a3e4STetsuo Handa { 341bd03a3e4STetsuo Handa unsigned int idx; 342cdcf6723STetsuo Handa 343bd03a3e4STetsuo Handa for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++) 344bd03a3e4STetsuo Handa INIT_LIST_HEAD(&ns->acl_group[idx]); 345bd03a3e4STetsuo Handa for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++) 346bd03a3e4STetsuo Handa INIT_LIST_HEAD(&ns->group_list[idx]); 347bd03a3e4STetsuo Handa for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) 348bd03a3e4STetsuo Handa INIT_LIST_HEAD(&ns->policy_list[idx]); 349861f4bcfSTetsuo Handa ns->profile_version = 20150505; 350bd03a3e4STetsuo Handa tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); 351bd03a3e4STetsuo Handa list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); 352bd03a3e4STetsuo Handa } 353bd03a3e4STetsuo Handa 354bd03a3e4STetsuo Handa /** 355bd03a3e4STetsuo Handa * tomoyo_print_namespace - Print namespace header. 356bd03a3e4STetsuo Handa * 357bd03a3e4STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 358bd03a3e4STetsuo Handa * 359bd03a3e4STetsuo Handa * Returns nothing. 360bd03a3e4STetsuo Handa */ 361bd03a3e4STetsuo Handa static void tomoyo_print_namespace(struct tomoyo_io_buffer *head) 362bd03a3e4STetsuo Handa { 363bd03a3e4STetsuo Handa if (!tomoyo_namespace_enabled) 364bd03a3e4STetsuo Handa return; 365bd03a3e4STetsuo Handa tomoyo_set_string(head, 366bd03a3e4STetsuo Handa container_of(head->r.ns, 367bd03a3e4STetsuo Handa struct tomoyo_policy_namespace, 368bd03a3e4STetsuo Handa namespace_list)->name); 369bd03a3e4STetsuo Handa tomoyo_set_space(head); 370bd03a3e4STetsuo Handa } 371bd03a3e4STetsuo Handa 3720d2171d7STetsuo Handa /** 3737762fbffSTetsuo Handa * tomoyo_print_name_union - Print a tomoyo_name_union. 3747762fbffSTetsuo Handa * 3757762fbffSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 3767762fbffSTetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union". 3777762fbffSTetsuo Handa */ 378f23571e8STetsuo Handa static void tomoyo_print_name_union(struct tomoyo_io_buffer *head, 3797762fbffSTetsuo Handa const struct tomoyo_name_union *ptr) 3807762fbffSTetsuo Handa { 381f23571e8STetsuo Handa tomoyo_set_space(head); 3820df7e8b8STetsuo Handa if (ptr->group) { 383f23571e8STetsuo Handa tomoyo_set_string(head, "@"); 384f23571e8STetsuo Handa tomoyo_set_string(head, ptr->group->group_name->name); 385f23571e8STetsuo Handa } else { 386f23571e8STetsuo Handa tomoyo_set_string(head, ptr->filename->name); 387f23571e8STetsuo Handa } 3887762fbffSTetsuo Handa } 3897762fbffSTetsuo Handa 3907762fbffSTetsuo Handa /** 3912ca9bf45STetsuo Handa * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote. 3922ca9bf45STetsuo Handa * 3932ca9bf45STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 3942ca9bf45STetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union". 3952ca9bf45STetsuo Handa * 3962ca9bf45STetsuo Handa * Returns nothing. 3972ca9bf45STetsuo Handa */ 3982ca9bf45STetsuo Handa static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head, 3992ca9bf45STetsuo Handa const struct tomoyo_name_union *ptr) 4002ca9bf45STetsuo Handa { 4012ca9bf45STetsuo Handa if (ptr->group) { 4022ca9bf45STetsuo Handa tomoyo_set_string(head, "@"); 4032ca9bf45STetsuo Handa tomoyo_set_string(head, ptr->group->group_name->name); 4042ca9bf45STetsuo Handa } else { 4052ca9bf45STetsuo Handa tomoyo_set_string(head, "\""); 4062ca9bf45STetsuo Handa tomoyo_set_string(head, ptr->filename->name); 4072ca9bf45STetsuo Handa tomoyo_set_string(head, "\""); 4082ca9bf45STetsuo Handa } 4092ca9bf45STetsuo Handa } 4102ca9bf45STetsuo Handa 4112ca9bf45STetsuo Handa /** 4122066a361STetsuo Handa * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space. 4134c3e9e2dSTetsuo Handa * 4144c3e9e2dSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 4154c3e9e2dSTetsuo Handa * @ptr: Pointer to "struct tomoyo_number_union". 4162066a361STetsuo Handa * 4172066a361STetsuo Handa * Returns nothing. 4184c3e9e2dSTetsuo Handa */ 4192066a361STetsuo Handa static void tomoyo_print_number_union_nospace 4202066a361STetsuo Handa (struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) 4214c3e9e2dSTetsuo Handa { 4220df7e8b8STetsuo Handa if (ptr->group) { 423f23571e8STetsuo Handa tomoyo_set_string(head, "@"); 424f23571e8STetsuo Handa tomoyo_set_string(head, ptr->group->group_name->name); 425f23571e8STetsuo Handa } else { 426f23571e8STetsuo Handa int i; 427f23571e8STetsuo Handa unsigned long min = ptr->values[0]; 428f23571e8STetsuo Handa const unsigned long max = ptr->values[1]; 4290df7e8b8STetsuo Handa u8 min_type = ptr->value_type[0]; 4300df7e8b8STetsuo Handa const u8 max_type = ptr->value_type[1]; 431f23571e8STetsuo Handa char buffer[128]; 432cdcf6723STetsuo Handa 433f23571e8STetsuo Handa buffer[0] = '\0'; 434f23571e8STetsuo Handa for (i = 0; i < 2; i++) { 4354c3e9e2dSTetsuo Handa switch (min_type) { 4364c3e9e2dSTetsuo Handa case TOMOYO_VALUE_TYPE_HEXADECIMAL: 437f23571e8STetsuo Handa tomoyo_addprintf(buffer, sizeof(buffer), 438f23571e8STetsuo Handa "0x%lX", min); 4394c3e9e2dSTetsuo Handa break; 4404c3e9e2dSTetsuo Handa case TOMOYO_VALUE_TYPE_OCTAL: 441f23571e8STetsuo Handa tomoyo_addprintf(buffer, sizeof(buffer), 442f23571e8STetsuo Handa "0%lo", min); 4434c3e9e2dSTetsuo Handa break; 4444c3e9e2dSTetsuo Handa default: 4452066a361STetsuo Handa tomoyo_addprintf(buffer, sizeof(buffer), "%lu", 4462066a361STetsuo Handa min); 4474c3e9e2dSTetsuo Handa break; 4484c3e9e2dSTetsuo Handa } 4494c3e9e2dSTetsuo Handa if (min == max && min_type == max_type) 450f23571e8STetsuo Handa break; 451f23571e8STetsuo Handa tomoyo_addprintf(buffer, sizeof(buffer), "-"); 452f23571e8STetsuo Handa min_type = max_type; 453f23571e8STetsuo Handa min = max; 4544c3e9e2dSTetsuo Handa } 455f23571e8STetsuo Handa tomoyo_io_printf(head, "%s", buffer); 4564c3e9e2dSTetsuo Handa } 4579590837bSKentaro Takeda } 4589590837bSKentaro Takeda 4599590837bSKentaro Takeda /** 4602066a361STetsuo Handa * tomoyo_print_number_union - Print a tomoyo_number_union. 4612066a361STetsuo Handa * 4622066a361STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 4632066a361STetsuo Handa * @ptr: Pointer to "struct tomoyo_number_union". 4642066a361STetsuo Handa * 4652066a361STetsuo Handa * Returns nothing. 4662066a361STetsuo Handa */ 4672066a361STetsuo Handa static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, 4682066a361STetsuo Handa const struct tomoyo_number_union *ptr) 4692066a361STetsuo Handa { 4702066a361STetsuo Handa tomoyo_set_space(head); 4712066a361STetsuo Handa tomoyo_print_number_union_nospace(head, ptr); 4722066a361STetsuo Handa } 4732066a361STetsuo Handa 4742066a361STetsuo Handa /** 475e2bf6907STetsuo Handa * tomoyo_assign_profile - Create a new profile. 4769590837bSKentaro Takeda * 477bd03a3e4STetsuo Handa * @ns: Pointer to "struct tomoyo_policy_namespace". 4789590837bSKentaro Takeda * @profile: Profile number to create. 4799590837bSKentaro Takeda * 4809590837bSKentaro Takeda * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise. 4819590837bSKentaro Takeda */ 482bd03a3e4STetsuo Handa static struct tomoyo_profile *tomoyo_assign_profile 483bd03a3e4STetsuo Handa (struct tomoyo_policy_namespace *ns, const unsigned int profile) 4849590837bSKentaro Takeda { 48557c2590fSTetsuo Handa struct tomoyo_profile *ptr; 48657c2590fSTetsuo Handa struct tomoyo_profile *entry; 487cdcf6723STetsuo Handa 4889590837bSKentaro Takeda if (profile >= TOMOYO_MAX_PROFILES) 4899590837bSKentaro Takeda return NULL; 490bd03a3e4STetsuo Handa ptr = ns->profile_ptr[profile]; 4919590837bSKentaro Takeda if (ptr) 49257c2590fSTetsuo Handa return ptr; 4931b6b924eSZheng Zengkai entry = kzalloc(sizeof(*entry), GFP_NOFS | __GFP_NOWARN); 49457c2590fSTetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 49557c2590fSTetsuo Handa goto out; 496bd03a3e4STetsuo Handa ptr = ns->profile_ptr[profile]; 49757c2590fSTetsuo Handa if (!ptr && tomoyo_memory_ok(entry)) { 49857c2590fSTetsuo Handa ptr = entry; 499eadd99ccSTetsuo Handa ptr->default_config = TOMOYO_CONFIG_DISABLED | 500eadd99ccSTetsuo Handa TOMOYO_CONFIG_WANT_GRANT_LOG | 501eadd99ccSTetsuo Handa TOMOYO_CONFIG_WANT_REJECT_LOG; 50257c2590fSTetsuo Handa memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT, 50357c2590fSTetsuo Handa sizeof(ptr->config)); 5046afcb3b7STetsuo Handa ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 5056afcb3b7STetsuo Handa CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG; 5066afcb3b7STetsuo Handa ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 5076afcb3b7STetsuo Handa CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY; 5089590837bSKentaro Takeda mb(); /* Avoid out-of-order execution. */ 509bd03a3e4STetsuo Handa ns->profile_ptr[profile] = ptr; 51057c2590fSTetsuo Handa entry = NULL; 51157c2590fSTetsuo Handa } 51229282381STetsuo Handa mutex_unlock(&tomoyo_policy_lock); 51357c2590fSTetsuo Handa out: 51457c2590fSTetsuo Handa kfree(entry); 5159590837bSKentaro Takeda return ptr; 5169590837bSKentaro Takeda } 5179590837bSKentaro Takeda 5189590837bSKentaro Takeda /** 51957c2590fSTetsuo Handa * tomoyo_profile - Find a profile. 52057c2590fSTetsuo Handa * 521bd03a3e4STetsuo Handa * @ns: Pointer to "struct tomoyo_policy_namespace". 52257c2590fSTetsuo Handa * @profile: Profile number to find. 52357c2590fSTetsuo Handa * 52457c2590fSTetsuo Handa * Returns pointer to "struct tomoyo_profile". 52557c2590fSTetsuo Handa */ 526bd03a3e4STetsuo Handa struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, 527bd03a3e4STetsuo Handa const u8 profile) 52857c2590fSTetsuo Handa { 529d5ca1725STetsuo Handa static struct tomoyo_profile tomoyo_null_profile; 530bd03a3e4STetsuo Handa struct tomoyo_profile *ptr = ns->profile_ptr[profile]; 531cdcf6723STetsuo Handa 532d5ca1725STetsuo Handa if (!ptr) 533d5ca1725STetsuo Handa ptr = &tomoyo_null_profile; 53457c2590fSTetsuo Handa return ptr; 53557c2590fSTetsuo Handa } 53657c2590fSTetsuo Handa 537d5ca1725STetsuo Handa /** 538d5ca1725STetsuo Handa * tomoyo_find_yesno - Find values for specified keyword. 539d5ca1725STetsuo Handa * 540d5ca1725STetsuo Handa * @string: String to check. 541d5ca1725STetsuo Handa * @find: Name of keyword. 542d5ca1725STetsuo Handa * 543d5ca1725STetsuo Handa * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise. 544d5ca1725STetsuo Handa */ 5458e568687STetsuo Handa static s8 tomoyo_find_yesno(const char *string, const char *find) 5468e568687STetsuo Handa { 5478e568687STetsuo Handa const char *cp = strstr(string, find); 548cdcf6723STetsuo Handa 5498e568687STetsuo Handa if (cp) { 5508e568687STetsuo Handa cp += strlen(find); 5518e568687STetsuo Handa if (!strncmp(cp, "=yes", 4)) 5528e568687STetsuo Handa return 1; 5538e568687STetsuo Handa else if (!strncmp(cp, "=no", 3)) 5548e568687STetsuo Handa return 0; 5558e568687STetsuo Handa } 5568e568687STetsuo Handa return -1; 5578e568687STetsuo Handa } 5588e568687STetsuo Handa 559d5ca1725STetsuo Handa /** 560d5ca1725STetsuo Handa * tomoyo_set_uint - Set value for specified preference. 561d5ca1725STetsuo Handa * 562d5ca1725STetsuo Handa * @i: Pointer to "unsigned int". 563d5ca1725STetsuo Handa * @string: String to check. 564d5ca1725STetsuo Handa * @find: Name of keyword. 565d5ca1725STetsuo Handa * 566d5ca1725STetsuo Handa * Returns nothing. 567d5ca1725STetsuo Handa */ 5688e568687STetsuo Handa static void tomoyo_set_uint(unsigned int *i, const char *string, 5698e568687STetsuo Handa const char *find) 5708e568687STetsuo Handa { 5718e568687STetsuo Handa const char *cp = strstr(string, find); 572cdcf6723STetsuo Handa 5738e568687STetsuo Handa if (cp) 5748e568687STetsuo Handa sscanf(cp + strlen(find), "=%u", i); 5758e568687STetsuo Handa } 5768e568687STetsuo Handa 577d5ca1725STetsuo Handa /** 578d5ca1725STetsuo Handa * tomoyo_set_mode - Set mode for specified profile. 579d5ca1725STetsuo Handa * 580d5ca1725STetsuo Handa * @name: Name of functionality. 581d5ca1725STetsuo Handa * @value: Mode for @name. 582d5ca1725STetsuo Handa * @profile: Pointer to "struct tomoyo_profile". 583d5ca1725STetsuo Handa * 584d5ca1725STetsuo Handa * Returns 0 on success, negative value otherwise. 585d5ca1725STetsuo Handa */ 5868e568687STetsuo Handa static int tomoyo_set_mode(char *name, const char *value, 5878e568687STetsuo Handa struct tomoyo_profile *profile) 5888e568687STetsuo Handa { 5898e568687STetsuo Handa u8 i; 5908e568687STetsuo Handa u8 config; 591cdcf6723STetsuo Handa 5928e568687STetsuo Handa if (!strcmp(name, "CONFIG")) { 5938e568687STetsuo Handa i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; 5948e568687STetsuo Handa config = profile->default_config; 5958e568687STetsuo Handa } else if (tomoyo_str_starts(&name, "CONFIG::")) { 5968e568687STetsuo Handa config = 0; 5978e568687STetsuo Handa for (i = 0; i < TOMOYO_MAX_MAC_INDEX 5988e568687STetsuo Handa + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) { 5992c47ab93STetsuo Handa int len = 0; 600cdcf6723STetsuo Handa 6012c47ab93STetsuo Handa if (i < TOMOYO_MAX_MAC_INDEX) { 6022c47ab93STetsuo Handa const u8 c = tomoyo_index2category[i]; 6032c47ab93STetsuo Handa const char *category = 6042c47ab93STetsuo Handa tomoyo_category_keywords[c]; 605cdcf6723STetsuo Handa 6062c47ab93STetsuo Handa len = strlen(category); 6072c47ab93STetsuo Handa if (strncmp(name, category, len) || 6082c47ab93STetsuo Handa name[len++] != ':' || name[len++] != ':') 6092c47ab93STetsuo Handa continue; 6102c47ab93STetsuo Handa } 6112c47ab93STetsuo Handa if (strcmp(name + len, tomoyo_mac_keywords[i])) 6128e568687STetsuo Handa continue; 6138e568687STetsuo Handa config = profile->config[i]; 6148e568687STetsuo Handa break; 6158e568687STetsuo Handa } 6168e568687STetsuo Handa if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) 6178e568687STetsuo Handa return -EINVAL; 6188e568687STetsuo Handa } else { 6198e568687STetsuo Handa return -EINVAL; 6208e568687STetsuo Handa } 621d5ca1725STetsuo Handa if (strstr(value, "use_default")) { 6228e568687STetsuo Handa config = TOMOYO_CONFIG_USE_DEFAULT; 6238e568687STetsuo Handa } else { 6248e568687STetsuo Handa u8 mode; 625cdcf6723STetsuo Handa 6268e568687STetsuo Handa for (mode = 0; mode < 4; mode++) 6278e568687STetsuo Handa if (strstr(value, tomoyo_mode[mode])) 6288e568687STetsuo Handa /* 6298e568687STetsuo Handa * Update lower 3 bits in order to distinguish 63015269fb1STetsuo Handa * 'config' from 'TOMOYO_CONFIG_USE_DEFAULT'. 6318e568687STetsuo Handa */ 6328e568687STetsuo Handa config = (config & ~7) | mode; 633eadd99ccSTetsuo Handa if (config != TOMOYO_CONFIG_USE_DEFAULT) { 634eadd99ccSTetsuo Handa switch (tomoyo_find_yesno(value, "grant_log")) { 635eadd99ccSTetsuo Handa case 1: 636eadd99ccSTetsuo Handa config |= TOMOYO_CONFIG_WANT_GRANT_LOG; 637eadd99ccSTetsuo Handa break; 638eadd99ccSTetsuo Handa case 0: 639eadd99ccSTetsuo Handa config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG; 640eadd99ccSTetsuo Handa break; 641eadd99ccSTetsuo Handa } 642eadd99ccSTetsuo Handa switch (tomoyo_find_yesno(value, "reject_log")) { 643eadd99ccSTetsuo Handa case 1: 644eadd99ccSTetsuo Handa config |= TOMOYO_CONFIG_WANT_REJECT_LOG; 645eadd99ccSTetsuo Handa break; 646eadd99ccSTetsuo Handa case 0: 647eadd99ccSTetsuo Handa config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG; 648eadd99ccSTetsuo Handa break; 649eadd99ccSTetsuo Handa } 650eadd99ccSTetsuo Handa } 6518e568687STetsuo Handa } 6528e568687STetsuo Handa if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX) 6538e568687STetsuo Handa profile->config[i] = config; 6548e568687STetsuo Handa else if (config != TOMOYO_CONFIG_USE_DEFAULT) 6558e568687STetsuo Handa profile->default_config = config; 6568e568687STetsuo Handa return 0; 6578e568687STetsuo Handa } 6588e568687STetsuo Handa 65957c2590fSTetsuo Handa /** 66057c2590fSTetsuo Handa * tomoyo_write_profile - Write profile table. 6619590837bSKentaro Takeda * 6629590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 6639590837bSKentaro Takeda * 6649590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 6659590837bSKentaro Takeda */ 6669590837bSKentaro Takeda static int tomoyo_write_profile(struct tomoyo_io_buffer *head) 6679590837bSKentaro Takeda { 6689590837bSKentaro Takeda char *data = head->write_buf; 6699590837bSKentaro Takeda unsigned int i; 6709590837bSKentaro Takeda char *cp; 6719590837bSKentaro Takeda struct tomoyo_profile *profile; 672cdcf6723STetsuo Handa 673bd03a3e4STetsuo Handa if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version) 674bd03a3e4STetsuo Handa == 1) 67557c2590fSTetsuo Handa return 0; 67657c2590fSTetsuo Handa i = simple_strtoul(data, &cp, 10); 67757c2590fSTetsuo Handa if (*cp != '-') 6789590837bSKentaro Takeda return -EINVAL; 6799590837bSKentaro Takeda data = cp + 1; 680bd03a3e4STetsuo Handa profile = tomoyo_assign_profile(head->w.ns, i); 6819590837bSKentaro Takeda if (!profile) 6829590837bSKentaro Takeda return -EINVAL; 6839590837bSKentaro Takeda cp = strchr(data, '='); 6849590837bSKentaro Takeda if (!cp) 6859590837bSKentaro Takeda return -EINVAL; 68657c2590fSTetsuo Handa *cp++ = '\0'; 6879590837bSKentaro Takeda if (!strcmp(data, "COMMENT")) { 6882a086e5dSTetsuo Handa static DEFINE_SPINLOCK(lock); 6892a086e5dSTetsuo Handa const struct tomoyo_path_info *new_comment 6902a086e5dSTetsuo Handa = tomoyo_get_name(cp); 6912a086e5dSTetsuo Handa const struct tomoyo_path_info *old_comment; 692cdcf6723STetsuo Handa 6932a086e5dSTetsuo Handa if (!new_comment) 6942a086e5dSTetsuo Handa return -ENOMEM; 6952a086e5dSTetsuo Handa spin_lock(&lock); 6962a086e5dSTetsuo Handa old_comment = profile->comment; 6972a086e5dSTetsuo Handa profile->comment = new_comment; 6982a086e5dSTetsuo Handa spin_unlock(&lock); 699bf24fb01STetsuo Handa tomoyo_put_name(old_comment); 7009590837bSKentaro Takeda return 0; 7019590837bSKentaro Takeda } 702d5ca1725STetsuo Handa if (!strcmp(data, "PREFERENCE")) { 703d5ca1725STetsuo Handa for (i = 0; i < TOMOYO_MAX_PREF; i++) 704d5ca1725STetsuo Handa tomoyo_set_uint(&profile->pref[i], cp, 705d5ca1725STetsuo Handa tomoyo_pref_keywords[i]); 706d5ca1725STetsuo Handa return 0; 7079590837bSKentaro Takeda } 708d5ca1725STetsuo Handa return tomoyo_set_mode(data, cp, profile); 709f23571e8STetsuo Handa } 710f23571e8STetsuo Handa 711eadd99ccSTetsuo Handa /** 712eadd99ccSTetsuo Handa * tomoyo_print_config - Print mode for specified functionality. 713eadd99ccSTetsuo Handa * 714eadd99ccSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 715eadd99ccSTetsuo Handa * @config: Mode for that functionality. 716eadd99ccSTetsuo Handa * 717eadd99ccSTetsuo Handa * Returns nothing. 718eadd99ccSTetsuo Handa * 719eadd99ccSTetsuo Handa * Caller prints functionality's name. 720eadd99ccSTetsuo Handa */ 721f23571e8STetsuo Handa static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config) 722f23571e8STetsuo Handa { 723eadd99ccSTetsuo Handa tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n", 724eadd99ccSTetsuo Handa tomoyo_mode[config & 3], 725ea181a34SLucas De Marchi str_yes_no(config & TOMOYO_CONFIG_WANT_GRANT_LOG), 726ea181a34SLucas De Marchi str_yes_no(config & TOMOYO_CONFIG_WANT_REJECT_LOG)); 727f23571e8STetsuo Handa } 728f23571e8STetsuo Handa 7299590837bSKentaro Takeda /** 73057c2590fSTetsuo Handa * tomoyo_read_profile - Read profile table. 7319590837bSKentaro Takeda * 7329590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 733eadd99ccSTetsuo Handa * 734eadd99ccSTetsuo Handa * Returns nothing. 7359590837bSKentaro Takeda */ 7368fbe71f0STetsuo Handa static void tomoyo_read_profile(struct tomoyo_io_buffer *head) 7379590837bSKentaro Takeda { 738f23571e8STetsuo Handa u8 index; 739bd03a3e4STetsuo Handa struct tomoyo_policy_namespace *ns = 740bd03a3e4STetsuo Handa container_of(head->r.ns, typeof(*ns), namespace_list); 741f23571e8STetsuo Handa const struct tomoyo_profile *profile; 742cdcf6723STetsuo Handa 743bd03a3e4STetsuo Handa if (head->r.eof) 744bd03a3e4STetsuo Handa return; 745f23571e8STetsuo Handa next: 746f23571e8STetsuo Handa index = head->r.index; 747bd03a3e4STetsuo Handa profile = ns->profile_ptr[index]; 748f23571e8STetsuo Handa switch (head->r.step) { 749f23571e8STetsuo Handa case 0: 750bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 751bd03a3e4STetsuo Handa tomoyo_io_printf(head, "PROFILE_VERSION=%u\n", 752bd03a3e4STetsuo Handa ns->profile_version); 753f23571e8STetsuo Handa head->r.step++; 754f23571e8STetsuo Handa break; 755f23571e8STetsuo Handa case 1: 756f23571e8STetsuo Handa for ( ; head->r.index < TOMOYO_MAX_PROFILES; 757f23571e8STetsuo Handa head->r.index++) 758bd03a3e4STetsuo Handa if (ns->profile_ptr[head->r.index]) 759f23571e8STetsuo Handa break; 7604d818971STetsuo Handa if (head->r.index == TOMOYO_MAX_PROFILES) { 7614d818971STetsuo Handa head->r.eof = true; 762f23571e8STetsuo Handa return; 7634d818971STetsuo Handa } 764f23571e8STetsuo Handa head->r.step++; 765f23571e8STetsuo Handa break; 766f23571e8STetsuo Handa case 2: 767f23571e8STetsuo Handa { 768d5ca1725STetsuo Handa u8 i; 769f23571e8STetsuo Handa const struct tomoyo_path_info *comment = 770f23571e8STetsuo Handa profile->comment; 771cdcf6723STetsuo Handa 772bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 773f23571e8STetsuo Handa tomoyo_io_printf(head, "%u-COMMENT=", index); 774f23571e8STetsuo Handa tomoyo_set_string(head, comment ? comment->name : ""); 775f23571e8STetsuo Handa tomoyo_set_lf(head); 7764d818971STetsuo Handa tomoyo_print_namespace(head); 777d5ca1725STetsuo Handa tomoyo_io_printf(head, "%u-PREFERENCE={ ", index); 778d5ca1725STetsuo Handa for (i = 0; i < TOMOYO_MAX_PREF; i++) 779d5ca1725STetsuo Handa tomoyo_io_printf(head, "%s=%u ", 780d5ca1725STetsuo Handa tomoyo_pref_keywords[i], 781d5ca1725STetsuo Handa profile->pref[i]); 782d5ca1725STetsuo Handa tomoyo_set_string(head, "}\n"); 783f23571e8STetsuo Handa head->r.step++; 784f23571e8STetsuo Handa } 785f23571e8STetsuo Handa break; 786f23571e8STetsuo Handa case 3: 787f23571e8STetsuo Handa { 788bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 789f23571e8STetsuo Handa tomoyo_io_printf(head, "%u-%s", index, "CONFIG"); 790f23571e8STetsuo Handa tomoyo_print_config(head, profile->default_config); 791f23571e8STetsuo Handa head->r.bit = 0; 792f23571e8STetsuo Handa head->r.step++; 793f23571e8STetsuo Handa } 794f23571e8STetsuo Handa break; 795f23571e8STetsuo Handa case 4: 796f23571e8STetsuo Handa for ( ; head->r.bit < TOMOYO_MAX_MAC_INDEX 797f23571e8STetsuo Handa + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) { 798f23571e8STetsuo Handa const u8 i = head->r.bit; 799f23571e8STetsuo Handa const u8 config = profile->config[i]; 800cdcf6723STetsuo Handa 80157c2590fSTetsuo Handa if (config == TOMOYO_CONFIG_USE_DEFAULT) 8029590837bSKentaro Takeda continue; 803bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 8042c47ab93STetsuo Handa if (i < TOMOYO_MAX_MAC_INDEX) 8052c47ab93STetsuo Handa tomoyo_io_printf(head, "%u-CONFIG::%s::%s", 8062c47ab93STetsuo Handa index, 8072c47ab93STetsuo Handa tomoyo_category_keywords 8082c47ab93STetsuo Handa [tomoyo_index2category[i]], 8092c47ab93STetsuo Handa tomoyo_mac_keywords[i]); 8102c47ab93STetsuo Handa else 8112c47ab93STetsuo Handa tomoyo_io_printf(head, "%u-CONFIG::%s", index, 812f23571e8STetsuo Handa tomoyo_mac_keywords[i]); 813f23571e8STetsuo Handa tomoyo_print_config(head, config); 814f23571e8STetsuo Handa head->r.bit++; 8159590837bSKentaro Takeda break; 8169590837bSKentaro Takeda } 817f23571e8STetsuo Handa if (head->r.bit == TOMOYO_MAX_MAC_INDEX 818f23571e8STetsuo Handa + TOMOYO_MAX_MAC_CATEGORY_INDEX) { 819f23571e8STetsuo Handa head->r.index++; 820f23571e8STetsuo Handa head->r.step = 1; 821f23571e8STetsuo Handa } 822f23571e8STetsuo Handa break; 823f23571e8STetsuo Handa } 824f23571e8STetsuo Handa if (tomoyo_flush(head)) 825f23571e8STetsuo Handa goto next; 8269590837bSKentaro Takeda } 8279590837bSKentaro Takeda 8280f2a55d5STetsuo Handa /** 8290f2a55d5STetsuo Handa * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry. 8300f2a55d5STetsuo Handa * 8310f2a55d5STetsuo Handa * @a: Pointer to "struct tomoyo_acl_head". 8320f2a55d5STetsuo Handa * @b: Pointer to "struct tomoyo_acl_head". 8330f2a55d5STetsuo Handa * 8340f2a55d5STetsuo Handa * Returns true if @a == @b, false otherwise. 8350f2a55d5STetsuo Handa */ 836e2bf6907STetsuo Handa static bool tomoyo_same_manager(const struct tomoyo_acl_head *a, 83736f5e1ffSTetsuo Handa const struct tomoyo_acl_head *b) 83836f5e1ffSTetsuo Handa { 839e2bf6907STetsuo Handa return container_of(a, struct tomoyo_manager, head)->manager == 840e2bf6907STetsuo Handa container_of(b, struct tomoyo_manager, head)->manager; 84136f5e1ffSTetsuo Handa } 84236f5e1ffSTetsuo Handa 8439590837bSKentaro Takeda /** 8449590837bSKentaro Takeda * tomoyo_update_manager_entry - Add a manager entry. 8459590837bSKentaro Takeda * 8469590837bSKentaro Takeda * @manager: The path to manager or the domainnamme. 8479590837bSKentaro Takeda * @is_delete: True if it is a delete request. 8489590837bSKentaro Takeda * 8499590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 850fdb8ebb7STetsuo Handa * 851fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 8529590837bSKentaro Takeda */ 8539590837bSKentaro Takeda static int tomoyo_update_manager_entry(const char *manager, 8549590837bSKentaro Takeda const bool is_delete) 8559590837bSKentaro Takeda { 856e2bf6907STetsuo Handa struct tomoyo_manager e = { }; 857a238cf5bSTetsuo Handa struct tomoyo_acl_param param = { 858bd03a3e4STetsuo Handa /* .ns = &tomoyo_kernel_namespace, */ 859a238cf5bSTetsuo Handa .is_delete = is_delete, 860cdcf6723STetsuo Handa .list = &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], 861a238cf5bSTetsuo Handa }; 862a238cf5bSTetsuo Handa int error = is_delete ? -ENOENT : -ENOMEM; 863cdcf6723STetsuo Handa 86477b513ddSTetsuo Handa if (!tomoyo_correct_domain(manager) && 86577b513ddSTetsuo Handa !tomoyo_correct_word(manager)) 8669590837bSKentaro Takeda return -EINVAL; 8679e4b50e9STetsuo Handa e.manager = tomoyo_get_name(manager); 868a238cf5bSTetsuo Handa if (e.manager) { 869a238cf5bSTetsuo Handa error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, 870e2bf6907STetsuo Handa tomoyo_same_manager); 8719e4b50e9STetsuo Handa tomoyo_put_name(e.manager); 872a238cf5bSTetsuo Handa } 8739590837bSKentaro Takeda return error; 8749590837bSKentaro Takeda } 8759590837bSKentaro Takeda 8769590837bSKentaro Takeda /** 877e2bf6907STetsuo Handa * tomoyo_write_manager - Write manager policy. 8789590837bSKentaro Takeda * 8799590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 8809590837bSKentaro Takeda * 8819590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 882fdb8ebb7STetsuo Handa * 883fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 8849590837bSKentaro Takeda */ 885e2bf6907STetsuo Handa static int tomoyo_write_manager(struct tomoyo_io_buffer *head) 8869590837bSKentaro Takeda { 8879590837bSKentaro Takeda char *data = head->write_buf; 8889590837bSKentaro Takeda 8899590837bSKentaro Takeda if (!strcmp(data, "manage_by_non_root")) { 890bd03a3e4STetsuo Handa tomoyo_manage_by_non_root = !head->w.is_delete; 8919590837bSKentaro Takeda return 0; 8929590837bSKentaro Takeda } 893bd03a3e4STetsuo Handa return tomoyo_update_manager_entry(data, head->w.is_delete); 8949590837bSKentaro Takeda } 8959590837bSKentaro Takeda 8969590837bSKentaro Takeda /** 897e2bf6907STetsuo Handa * tomoyo_read_manager - Read manager policy. 8989590837bSKentaro Takeda * 8999590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 9009590837bSKentaro Takeda * 901fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 9029590837bSKentaro Takeda */ 903e2bf6907STetsuo Handa static void tomoyo_read_manager(struct tomoyo_io_buffer *head) 9049590837bSKentaro Takeda { 905f23571e8STetsuo Handa if (head->r.eof) 9068fbe71f0STetsuo Handa return; 907cdcf6723STetsuo Handa list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER]) { 908e2bf6907STetsuo Handa struct tomoyo_manager *ptr = 909f23571e8STetsuo Handa list_entry(head->r.acl, typeof(*ptr), head.list); 910cdcf6723STetsuo Handa 91182e0f001STetsuo Handa if (ptr->head.is_deleted) 9129590837bSKentaro Takeda continue; 913f23571e8STetsuo Handa if (!tomoyo_flush(head)) 914f23571e8STetsuo Handa return; 915f23571e8STetsuo Handa tomoyo_set_string(head, ptr->manager->name); 916f23571e8STetsuo Handa tomoyo_set_lf(head); 9179590837bSKentaro Takeda } 918f23571e8STetsuo Handa head->r.eof = true; 9199590837bSKentaro Takeda } 9209590837bSKentaro Takeda 9219590837bSKentaro Takeda /** 922e2bf6907STetsuo Handa * tomoyo_manager - Check whether the current process is a policy manager. 9239590837bSKentaro Takeda * 9249590837bSKentaro Takeda * Returns true if the current process is permitted to modify policy 9259590837bSKentaro Takeda * via /sys/kernel/security/tomoyo/ interface. 926fdb8ebb7STetsuo Handa * 927fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 9289590837bSKentaro Takeda */ 929e2bf6907STetsuo Handa static bool tomoyo_manager(void) 9309590837bSKentaro Takeda { 931e2bf6907STetsuo Handa struct tomoyo_manager *ptr; 9329590837bSKentaro Takeda const char *exe; 9339590837bSKentaro Takeda const struct task_struct *task = current; 9349590837bSKentaro Takeda const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; 935e80b1859STetsuo Handa bool found = IS_ENABLED(CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING); 9369590837bSKentaro Takeda 9379590837bSKentaro Takeda if (!tomoyo_policy_loaded) 9389590837bSKentaro Takeda return true; 939609fcd1bSEric W. Biederman if (!tomoyo_manage_by_non_root && 940609fcd1bSEric W. Biederman (!uid_eq(task->cred->uid, GLOBAL_ROOT_UID) || 941609fcd1bSEric W. Biederman !uid_eq(task->cred->euid, GLOBAL_ROOT_UID))) 9429590837bSKentaro Takeda return false; 9439590837bSKentaro Takeda exe = tomoyo_get_exe(); 9449590837bSKentaro Takeda if (!exe) 9459590837bSKentaro Takeda return false; 9466bd5ce60STetsuo Handa list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], head.list, 9476bd5ce60STetsuo Handa srcu_read_lock_held(&tomoyo_ss)) { 94877b513ddSTetsuo Handa if (!ptr->head.is_deleted && 94977b513ddSTetsuo Handa (!tomoyo_pathcmp(domainname, ptr->manager) || 95077b513ddSTetsuo Handa !strcmp(exe, ptr->manager->name))) { 9519590837bSKentaro Takeda found = true; 9529590837bSKentaro Takeda break; 9539590837bSKentaro Takeda } 9549590837bSKentaro Takeda } 9559590837bSKentaro Takeda if (!found) { /* Reduce error messages. */ 9569590837bSKentaro Takeda static pid_t last_pid; 9579590837bSKentaro Takeda const pid_t pid = current->pid; 958cdcf6723STetsuo Handa 9599590837bSKentaro Takeda if (last_pid != pid) { 960cdcf6723STetsuo Handa pr_warn("%s ( %s ) is not permitted to update policies.\n", 961cdcf6723STetsuo Handa domainname->name, exe); 9629590837bSKentaro Takeda last_pid = pid; 9639590837bSKentaro Takeda } 9649590837bSKentaro Takeda } 9658e2d39a1STetsuo Handa kfree(exe); 9669590837bSKentaro Takeda return found; 9679590837bSKentaro Takeda } 9689590837bSKentaro Takeda 96959df3166STetsuo Handa static struct tomoyo_domain_info *tomoyo_find_domain_by_qid 97059df3166STetsuo Handa (unsigned int serial); 97159df3166STetsuo Handa 9729590837bSKentaro Takeda /** 973bd03a3e4STetsuo Handa * tomoyo_select_domain - Parse select command. 9749590837bSKentaro Takeda * 9759590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 9769590837bSKentaro Takeda * @data: String to parse. 9779590837bSKentaro Takeda * 9789590837bSKentaro Takeda * Returns true on success, false otherwise. 979fdb8ebb7STetsuo Handa * 980fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 9819590837bSKentaro Takeda */ 982bd03a3e4STetsuo Handa static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, 983bd03a3e4STetsuo Handa const char *data) 9849590837bSKentaro Takeda { 9859590837bSKentaro Takeda unsigned int pid; 9869590837bSKentaro Takeda struct tomoyo_domain_info *domain = NULL; 9879b244373STetsuo Handa bool global_pid = false; 988cdcf6723STetsuo Handa 989bd03a3e4STetsuo Handa if (strncmp(data, "select ", 7)) 990bd03a3e4STetsuo Handa return false; 991bd03a3e4STetsuo Handa data += 7; 9929b244373STetsuo Handa if (sscanf(data, "pid=%u", &pid) == 1 || 9939b244373STetsuo Handa (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) { 9949590837bSKentaro Takeda struct task_struct *p; 995cdcf6723STetsuo Handa 9961fcdc7c5STetsuo Handa rcu_read_lock(); 9979b244373STetsuo Handa if (global_pid) 9989b244373STetsuo Handa p = find_task_by_pid_ns(pid, &init_pid_ns); 9999b244373STetsuo Handa else 10009590837bSKentaro Takeda p = find_task_by_vpid(pid); 10019590837bSKentaro Takeda if (p) 10028c6cb983STetsuo Handa domain = tomoyo_task(p)->domain_info; 10031fcdc7c5STetsuo Handa rcu_read_unlock(); 10049590837bSKentaro Takeda } else if (!strncmp(data, "domain=", 7)) { 100575093152STetsuo Handa if (tomoyo_domain_def(data + 7)) 10069590837bSKentaro Takeda domain = tomoyo_find_domain(data + 7); 100759df3166STetsuo Handa } else if (sscanf(data, "Q=%u", &pid) == 1) { 100859df3166STetsuo Handa domain = tomoyo_find_domain_by_qid(pid); 10099590837bSKentaro Takeda } else 10109590837bSKentaro Takeda return false; 10110df7e8b8STetsuo Handa head->w.domain = domain; 10129590837bSKentaro Takeda /* Accessing read_buf is safe because head->io_sem is held. */ 10139590837bSKentaro Takeda if (!head->read_buf) 10149590837bSKentaro Takeda return true; /* Do nothing if open(O_WRONLY). */ 1015f23571e8STetsuo Handa memset(&head->r, 0, sizeof(head->r)); 1016f23571e8STetsuo Handa head->r.print_this_domain_only = true; 101768eda8f5SDan Carpenter if (domain) 1018f23571e8STetsuo Handa head->r.domain = &domain->list; 101968eda8f5SDan Carpenter else 102027acbf41SZou Wei head->r.eof = true; 10219590837bSKentaro Takeda tomoyo_io_printf(head, "# select %s\n", data); 1022475e6fa3STetsuo Handa if (domain && domain->is_deleted) 10239590837bSKentaro Takeda tomoyo_io_printf(head, "# This is a deleted domain.\n"); 10249590837bSKentaro Takeda return true; 10259590837bSKentaro Takeda } 10269590837bSKentaro Takeda 10279590837bSKentaro Takeda /** 1028731d37aaSTetsuo Handa * tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry. 1029731d37aaSTetsuo Handa * 1030731d37aaSTetsuo Handa * @a: Pointer to "struct tomoyo_acl_info". 1031731d37aaSTetsuo Handa * @b: Pointer to "struct tomoyo_acl_info". 1032731d37aaSTetsuo Handa * 1033731d37aaSTetsuo Handa * Returns true if @a == @b, false otherwise. 1034731d37aaSTetsuo Handa */ 1035731d37aaSTetsuo Handa static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a, 1036731d37aaSTetsuo Handa const struct tomoyo_acl_info *b) 1037731d37aaSTetsuo Handa { 1038731d37aaSTetsuo Handa const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head); 1039731d37aaSTetsuo Handa const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head); 1040cdcf6723STetsuo Handa 1041731d37aaSTetsuo Handa return p1->domainname == p2->domainname; 1042731d37aaSTetsuo Handa } 1043731d37aaSTetsuo Handa 1044731d37aaSTetsuo Handa /** 1045731d37aaSTetsuo Handa * tomoyo_write_task - Update task related list. 1046731d37aaSTetsuo Handa * 1047731d37aaSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param". 1048731d37aaSTetsuo Handa * 1049731d37aaSTetsuo Handa * Returns 0 on success, negative value otherwise. 1050731d37aaSTetsuo Handa * 1051731d37aaSTetsuo Handa * Caller holds tomoyo_read_lock(). 1052731d37aaSTetsuo Handa */ 1053731d37aaSTetsuo Handa static int tomoyo_write_task(struct tomoyo_acl_param *param) 1054731d37aaSTetsuo Handa { 1055731d37aaSTetsuo Handa int error = -EINVAL; 1056cdcf6723STetsuo Handa 1057731d37aaSTetsuo Handa if (tomoyo_str_starts(¶m->data, "manual_domain_transition ")) { 1058731d37aaSTetsuo Handa struct tomoyo_task_acl e = { 1059731d37aaSTetsuo Handa .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL, 1060731d37aaSTetsuo Handa .domainname = tomoyo_get_domainname(param), 1061731d37aaSTetsuo Handa }; 1062cdcf6723STetsuo Handa 1063731d37aaSTetsuo Handa if (e.domainname) 1064731d37aaSTetsuo Handa error = tomoyo_update_domain(&e.head, sizeof(e), param, 1065731d37aaSTetsuo Handa tomoyo_same_task_acl, 1066731d37aaSTetsuo Handa NULL); 1067731d37aaSTetsuo Handa tomoyo_put_name(e.domainname); 1068731d37aaSTetsuo Handa } 1069731d37aaSTetsuo Handa return error; 1070731d37aaSTetsuo Handa } 1071731d37aaSTetsuo Handa 1072731d37aaSTetsuo Handa /** 1073ccf135f5STetsuo Handa * tomoyo_delete_domain - Delete a domain. 1074ccf135f5STetsuo Handa * 1075ccf135f5STetsuo Handa * @domainname: The name of domain. 1076ccf135f5STetsuo Handa * 10777d7473dbSTetsuo Handa * Returns 0 on success, negative value otherwise. 1078fdb8ebb7STetsuo Handa * 1079fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 1080ccf135f5STetsuo Handa */ 1081ccf135f5STetsuo Handa static int tomoyo_delete_domain(char *domainname) 1082ccf135f5STetsuo Handa { 1083ccf135f5STetsuo Handa struct tomoyo_domain_info *domain; 1084ccf135f5STetsuo Handa struct tomoyo_path_info name; 1085ccf135f5STetsuo Handa 1086ccf135f5STetsuo Handa name.name = domainname; 1087ccf135f5STetsuo Handa tomoyo_fill_path_info(&name); 108829282381STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) 10897d7473dbSTetsuo Handa return -EINTR; 1090ccf135f5STetsuo Handa /* Is there an active domain? */ 10916bd5ce60STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list, 10926bd5ce60STetsuo Handa srcu_read_lock_held(&tomoyo_ss)) { 1093ccf135f5STetsuo Handa /* Never delete tomoyo_kernel_domain */ 1094ccf135f5STetsuo Handa if (domain == &tomoyo_kernel_domain) 1095ccf135f5STetsuo Handa continue; 1096ccf135f5STetsuo Handa if (domain->is_deleted || 1097ccf135f5STetsuo Handa tomoyo_pathcmp(domain->domainname, &name)) 1098ccf135f5STetsuo Handa continue; 1099ccf135f5STetsuo Handa domain->is_deleted = true; 1100ccf135f5STetsuo Handa break; 1101ccf135f5STetsuo Handa } 1102f737d95dSTetsuo Handa mutex_unlock(&tomoyo_policy_lock); 1103ccf135f5STetsuo Handa return 0; 1104ccf135f5STetsuo Handa } 1105ccf135f5STetsuo Handa 1106ccf135f5STetsuo Handa /** 1107e2bf6907STetsuo Handa * tomoyo_write_domain2 - Write domain policy. 110817fcfbd9STetsuo Handa * 1109bd03a3e4STetsuo Handa * @ns: Pointer to "struct tomoyo_policy_namespace". 1110a238cf5bSTetsuo Handa * @list: Pointer to "struct list_head". 1111a238cf5bSTetsuo Handa * @data: Policy to be interpreted. 1112a238cf5bSTetsuo Handa * @is_delete: True if it is a delete request. 111317fcfbd9STetsuo Handa * 111417fcfbd9STetsuo Handa * Returns 0 on success, negative value otherwise. 111517fcfbd9STetsuo Handa * 111617fcfbd9STetsuo Handa * Caller holds tomoyo_read_lock(). 111717fcfbd9STetsuo Handa */ 1118bd03a3e4STetsuo Handa static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, 1119bd03a3e4STetsuo Handa struct list_head *list, char *data, 112017fcfbd9STetsuo Handa const bool is_delete) 112117fcfbd9STetsuo Handa { 1122a238cf5bSTetsuo Handa struct tomoyo_acl_param param = { 1123bd03a3e4STetsuo Handa .ns = ns, 1124a238cf5bSTetsuo Handa .list = list, 1125a238cf5bSTetsuo Handa .data = data, 1126a238cf5bSTetsuo Handa .is_delete = is_delete, 1127a238cf5bSTetsuo Handa }; 1128a238cf5bSTetsuo Handa static const struct { 1129a238cf5bSTetsuo Handa const char *keyword; 1130cdcf6723STetsuo Handa int (*write)(struct tomoyo_acl_param *param); 1131731d37aaSTetsuo Handa } tomoyo_callback[5] = { 1132a238cf5bSTetsuo Handa { "file ", tomoyo_write_file }, 1133059d84dbSTetsuo Handa { "network inet ", tomoyo_write_inet_network }, 1134059d84dbSTetsuo Handa { "network unix ", tomoyo_write_unix_network }, 1135d58e0da8STetsuo Handa { "misc ", tomoyo_write_misc }, 1136731d37aaSTetsuo Handa { "task ", tomoyo_write_task }, 1137a238cf5bSTetsuo Handa }; 1138a238cf5bSTetsuo Handa u8 i; 1139d58e0da8STetsuo Handa 1140d58e0da8STetsuo Handa for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) { 1141a238cf5bSTetsuo Handa if (!tomoyo_str_starts(¶m.data, 1142a238cf5bSTetsuo Handa tomoyo_callback[i].keyword)) 1143a238cf5bSTetsuo Handa continue; 1144a238cf5bSTetsuo Handa return tomoyo_callback[i].write(¶m); 1145a238cf5bSTetsuo Handa } 1146a238cf5bSTetsuo Handa return -EINVAL; 114717fcfbd9STetsuo Handa } 114817fcfbd9STetsuo Handa 11492c47ab93STetsuo Handa /* String table for domain flags. */ 11502c47ab93STetsuo Handa const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = { 11512c47ab93STetsuo Handa [TOMOYO_DIF_QUOTA_WARNED] = "quota_exceeded\n", 11522c47ab93STetsuo Handa [TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n", 11532c47ab93STetsuo Handa }; 11542c47ab93STetsuo Handa 115517fcfbd9STetsuo Handa /** 1156e2bf6907STetsuo Handa * tomoyo_write_domain - Write domain policy. 11579590837bSKentaro Takeda * 11589590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 11599590837bSKentaro Takeda * 11609590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 1161fdb8ebb7STetsuo Handa * 1162fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 11639590837bSKentaro Takeda */ 1164e2bf6907STetsuo Handa static int tomoyo_write_domain(struct tomoyo_io_buffer *head) 11659590837bSKentaro Takeda { 11669590837bSKentaro Takeda char *data = head->write_buf; 1167bd03a3e4STetsuo Handa struct tomoyo_policy_namespace *ns; 11680df7e8b8STetsuo Handa struct tomoyo_domain_info *domain = head->w.domain; 1169bd03a3e4STetsuo Handa const bool is_delete = head->w.is_delete; 1170bd03a3e4STetsuo Handa bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); 11714b425641STetsuo Handa unsigned int idx; 1172cdcf6723STetsuo Handa 1173bd03a3e4STetsuo Handa if (*data == '<') { 11747d7473dbSTetsuo Handa int ret = 0; 1175cdcf6723STetsuo Handa 11769590837bSKentaro Takeda domain = NULL; 11779590837bSKentaro Takeda if (is_delete) 11787d7473dbSTetsuo Handa ret = tomoyo_delete_domain(data); 1179fdb8ebb7STetsuo Handa else if (is_select) 11809590837bSKentaro Takeda domain = tomoyo_find_domain(data); 1181fdb8ebb7STetsuo Handa else 1182bd03a3e4STetsuo Handa domain = tomoyo_assign_domain(data, false); 11830df7e8b8STetsuo Handa head->w.domain = domain; 11847d7473dbSTetsuo Handa return ret; 11859590837bSKentaro Takeda } 11869590837bSKentaro Takeda if (!domain) 11879590837bSKentaro Takeda return -EINVAL; 1188bd03a3e4STetsuo Handa ns = domain->ns; 11894b425641STetsuo Handa if (sscanf(data, "use_profile %u", &idx) == 1 11904b425641STetsuo Handa && idx < TOMOYO_MAX_PROFILES) { 11914b425641STetsuo Handa if (!tomoyo_policy_loaded || ns->profile_ptr[idx]) 119232997144STetsuo Handa if (!is_delete) 11934b425641STetsuo Handa domain->profile = (u8) idx; 119432997144STetsuo Handa return 0; 119532997144STetsuo Handa } 11964b425641STetsuo Handa if (sscanf(data, "use_group %u\n", &idx) == 1 11974b425641STetsuo Handa && idx < TOMOYO_MAX_ACL_GROUPS) { 11984b425641STetsuo Handa if (!is_delete) 11994b425641STetsuo Handa set_bit(idx, domain->group); 12004b425641STetsuo Handa else 12014b425641STetsuo Handa clear_bit(idx, domain->group); 12024b425641STetsuo Handa return 0; 12034b425641STetsuo Handa } 12044b425641STetsuo Handa for (idx = 0; idx < TOMOYO_MAX_DOMAIN_INFO_FLAGS; idx++) { 12054b425641STetsuo Handa const char *cp = tomoyo_dif[idx]; 1206cdcf6723STetsuo Handa 12072c47ab93STetsuo Handa if (strncmp(data, cp, strlen(cp) - 1)) 12082c47ab93STetsuo Handa continue; 12094b425641STetsuo Handa domain->flags[idx] = !is_delete; 12109b244373STetsuo Handa return 0; 12119b244373STetsuo Handa } 1212bd03a3e4STetsuo Handa return tomoyo_write_domain2(ns, &domain->acl_info_list, data, 1213bd03a3e4STetsuo Handa is_delete); 12149590837bSKentaro Takeda } 12159590837bSKentaro Takeda 12169590837bSKentaro Takeda /** 12172066a361STetsuo Handa * tomoyo_print_condition - Print condition part. 12182066a361STetsuo Handa * 12192066a361STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 12202066a361STetsuo Handa * @cond: Pointer to "struct tomoyo_condition". 12212066a361STetsuo Handa * 12222066a361STetsuo Handa * Returns true on success, false otherwise. 12232066a361STetsuo Handa */ 12242066a361STetsuo Handa static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, 12252066a361STetsuo Handa const struct tomoyo_condition *cond) 12262066a361STetsuo Handa { 12272066a361STetsuo Handa switch (head->r.cond_step) { 12282066a361STetsuo Handa case 0: 12292066a361STetsuo Handa head->r.cond_index = 0; 12302066a361STetsuo Handa head->r.cond_step++; 12316bce98edSTetsuo Handa if (cond->transit) { 12326bce98edSTetsuo Handa tomoyo_set_space(head); 12336bce98edSTetsuo Handa tomoyo_set_string(head, cond->transit->name); 12346bce98edSTetsuo Handa } 1235df561f66SGustavo A. R. Silva fallthrough; 12362066a361STetsuo Handa case 1: 12372066a361STetsuo Handa { 12382066a361STetsuo Handa const u16 condc = cond->condc; 12392066a361STetsuo Handa const struct tomoyo_condition_element *condp = 12402066a361STetsuo Handa (typeof(condp)) (cond + 1); 12412066a361STetsuo Handa const struct tomoyo_number_union *numbers_p = 12422066a361STetsuo Handa (typeof(numbers_p)) (condp + condc); 12432ca9bf45STetsuo Handa const struct tomoyo_name_union *names_p = 12442ca9bf45STetsuo Handa (typeof(names_p)) 12452ca9bf45STetsuo Handa (numbers_p + cond->numbers_count); 12465b636857STetsuo Handa const struct tomoyo_argv *argv = 12475b636857STetsuo Handa (typeof(argv)) (names_p + cond->names_count); 12485b636857STetsuo Handa const struct tomoyo_envp *envp = 12495b636857STetsuo Handa (typeof(envp)) (argv + cond->argc); 12502066a361STetsuo Handa u16 skip; 1251cdcf6723STetsuo Handa 12522066a361STetsuo Handa for (skip = 0; skip < head->r.cond_index; skip++) { 12532066a361STetsuo Handa const u8 left = condp->left; 12542066a361STetsuo Handa const u8 right = condp->right; 1255cdcf6723STetsuo Handa 12562066a361STetsuo Handa condp++; 12572066a361STetsuo Handa switch (left) { 12585b636857STetsuo Handa case TOMOYO_ARGV_ENTRY: 12595b636857STetsuo Handa argv++; 12605b636857STetsuo Handa continue; 12615b636857STetsuo Handa case TOMOYO_ENVP_ENTRY: 12625b636857STetsuo Handa envp++; 12635b636857STetsuo Handa continue; 12642066a361STetsuo Handa case TOMOYO_NUMBER_UNION: 12652066a361STetsuo Handa numbers_p++; 12662066a361STetsuo Handa break; 12672066a361STetsuo Handa } 12682066a361STetsuo Handa switch (right) { 12692ca9bf45STetsuo Handa case TOMOYO_NAME_UNION: 12702ca9bf45STetsuo Handa names_p++; 12712ca9bf45STetsuo Handa break; 12722066a361STetsuo Handa case TOMOYO_NUMBER_UNION: 12732066a361STetsuo Handa numbers_p++; 12742066a361STetsuo Handa break; 12752066a361STetsuo Handa } 12762066a361STetsuo Handa } 12772066a361STetsuo Handa while (head->r.cond_index < condc) { 12782066a361STetsuo Handa const u8 match = condp->equals; 12792066a361STetsuo Handa const u8 left = condp->left; 12802066a361STetsuo Handa const u8 right = condp->right; 1281cdcf6723STetsuo Handa 12822066a361STetsuo Handa if (!tomoyo_flush(head)) 12832066a361STetsuo Handa return false; 12842066a361STetsuo Handa condp++; 12852066a361STetsuo Handa head->r.cond_index++; 12862066a361STetsuo Handa tomoyo_set_space(head); 12872066a361STetsuo Handa switch (left) { 12885b636857STetsuo Handa case TOMOYO_ARGV_ENTRY: 12895b636857STetsuo Handa tomoyo_io_printf(head, 12905b636857STetsuo Handa "exec.argv[%lu]%s=\"", 1291cdcf6723STetsuo Handa argv->index, argv->is_not ? "!" : ""); 12925b636857STetsuo Handa tomoyo_set_string(head, 12935b636857STetsuo Handa argv->value->name); 12945b636857STetsuo Handa tomoyo_set_string(head, "\""); 12955b636857STetsuo Handa argv++; 12965b636857STetsuo Handa continue; 12975b636857STetsuo Handa case TOMOYO_ENVP_ENTRY: 12985b636857STetsuo Handa tomoyo_set_string(head, 12995b636857STetsuo Handa "exec.envp[\""); 13005b636857STetsuo Handa tomoyo_set_string(head, 13015b636857STetsuo Handa envp->name->name); 1302cdcf6723STetsuo Handa tomoyo_io_printf(head, "\"]%s=", envp->is_not ? "!" : ""); 13035b636857STetsuo Handa if (envp->value) { 13045b636857STetsuo Handa tomoyo_set_string(head, "\""); 1305cdcf6723STetsuo Handa tomoyo_set_string(head, envp->value->name); 13065b636857STetsuo Handa tomoyo_set_string(head, "\""); 13075b636857STetsuo Handa } else { 13085b636857STetsuo Handa tomoyo_set_string(head, 13095b636857STetsuo Handa "NULL"); 13105b636857STetsuo Handa } 13115b636857STetsuo Handa envp++; 13125b636857STetsuo Handa continue; 13132066a361STetsuo Handa case TOMOYO_NUMBER_UNION: 13142066a361STetsuo Handa tomoyo_print_number_union_nospace 13152066a361STetsuo Handa (head, numbers_p++); 13162066a361STetsuo Handa break; 13172066a361STetsuo Handa default: 13182066a361STetsuo Handa tomoyo_set_string(head, 13192066a361STetsuo Handa tomoyo_condition_keyword[left]); 13202066a361STetsuo Handa break; 13212066a361STetsuo Handa } 13222066a361STetsuo Handa tomoyo_set_string(head, match ? "=" : "!="); 13232066a361STetsuo Handa switch (right) { 13242ca9bf45STetsuo Handa case TOMOYO_NAME_UNION: 13252ca9bf45STetsuo Handa tomoyo_print_name_union_quoted 13262ca9bf45STetsuo Handa (head, names_p++); 13272ca9bf45STetsuo Handa break; 13282066a361STetsuo Handa case TOMOYO_NUMBER_UNION: 13292066a361STetsuo Handa tomoyo_print_number_union_nospace 13302066a361STetsuo Handa (head, numbers_p++); 13312066a361STetsuo Handa break; 13322066a361STetsuo Handa default: 13332066a361STetsuo Handa tomoyo_set_string(head, 13342066a361STetsuo Handa tomoyo_condition_keyword[right]); 13352066a361STetsuo Handa break; 13362066a361STetsuo Handa } 13372066a361STetsuo Handa } 13382066a361STetsuo Handa } 13392066a361STetsuo Handa head->r.cond_step++; 1340df561f66SGustavo A. R. Silva fallthrough; 13412066a361STetsuo Handa case 2: 13422066a361STetsuo Handa if (!tomoyo_flush(head)) 13432066a361STetsuo Handa break; 13442066a361STetsuo Handa head->r.cond_step++; 1345df561f66SGustavo A. R. Silva fallthrough; 13462066a361STetsuo Handa case 3: 13471f067a68STetsuo Handa if (cond->grant_log != TOMOYO_GRANTLOG_AUTO) 13481f067a68STetsuo Handa tomoyo_io_printf(head, " grant_log=%s", 1349ea181a34SLucas De Marchi str_yes_no(cond->grant_log == 13501f067a68STetsuo Handa TOMOYO_GRANTLOG_YES)); 13512066a361STetsuo Handa tomoyo_set_lf(head); 13522066a361STetsuo Handa return true; 13532066a361STetsuo Handa } 13542066a361STetsuo Handa return false; 13552066a361STetsuo Handa } 13562066a361STetsuo Handa 13572066a361STetsuo Handa /** 135832997144STetsuo Handa * tomoyo_set_group - Print "acl_group " header keyword and category name. 13599590837bSKentaro Takeda * 13600d2171d7STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 13610d2171d7STetsuo Handa * @category: Category name. 13629590837bSKentaro Takeda * 13630d2171d7STetsuo Handa * Returns nothing. 13649590837bSKentaro Takeda */ 13650d2171d7STetsuo Handa static void tomoyo_set_group(struct tomoyo_io_buffer *head, 13660d2171d7STetsuo Handa const char *category) 13679590837bSKentaro Takeda { 1368bd03a3e4STetsuo Handa if (head->type == TOMOYO_EXCEPTIONPOLICY) { 1369bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 137032997144STetsuo Handa tomoyo_io_printf(head, "acl_group %u ", 137132997144STetsuo Handa head->r.acl_group_index); 1372bd03a3e4STetsuo Handa } 13730d2171d7STetsuo Handa tomoyo_set_string(head, category); 13742106ccd9STetsuo Handa } 13752106ccd9STetsuo Handa 13762106ccd9STetsuo Handa /** 13779590837bSKentaro Takeda * tomoyo_print_entry - Print an ACL entry. 13789590837bSKentaro Takeda * 13799590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 13805db5a39bSTetsuo Handa * @acl: Pointer to an ACL entry. 13819590837bSKentaro Takeda * 13829590837bSKentaro Takeda * Returns true on success, false otherwise. 13839590837bSKentaro Takeda */ 13849590837bSKentaro Takeda static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, 13855db5a39bSTetsuo Handa struct tomoyo_acl_info *acl) 13869590837bSKentaro Takeda { 13875db5a39bSTetsuo Handa const u8 acl_type = acl->type; 13880d2171d7STetsuo Handa bool first = true; 1389f23571e8STetsuo Handa u8 bit; 13909590837bSKentaro Takeda 13912066a361STetsuo Handa if (head->r.print_cond_part) 13922066a361STetsuo Handa goto print_cond_part; 13935db5a39bSTetsuo Handa if (acl->is_deleted) 1394237ab459STetsuo Handa return true; 1395f23571e8STetsuo Handa if (!tomoyo_flush(head)) 1396f23571e8STetsuo Handa return false; 1397f23571e8STetsuo Handa else if (acl_type == TOMOYO_TYPE_PATH_ACL) { 13985db5a39bSTetsuo Handa struct tomoyo_path_acl *ptr = 13995db5a39bSTetsuo Handa container_of(acl, typeof(*ptr), head); 14005db5a39bSTetsuo Handa const u16 perm = ptr->perm; 1401cdcf6723STetsuo Handa 14020d2171d7STetsuo Handa for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { 14035db5a39bSTetsuo Handa if (!(perm & (1 << bit))) 14045db5a39bSTetsuo Handa continue; 1405bd03a3e4STetsuo Handa if (head->r.print_transition_related_only && 14065db5a39bSTetsuo Handa bit != TOMOYO_TYPE_EXECUTE) 14075db5a39bSTetsuo Handa continue; 14080d2171d7STetsuo Handa if (first) { 14090d2171d7STetsuo Handa tomoyo_set_group(head, "file "); 14100d2171d7STetsuo Handa first = false; 14110d2171d7STetsuo Handa } else { 14120d2171d7STetsuo Handa tomoyo_set_slash(head); 14139590837bSKentaro Takeda } 14140d2171d7STetsuo Handa tomoyo_set_string(head, tomoyo_path_keyword[bit]); 14150d2171d7STetsuo Handa } 14160d2171d7STetsuo Handa if (first) 14170d2171d7STetsuo Handa return true; 1418f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->name); 1419731d37aaSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) { 1420731d37aaSTetsuo Handa struct tomoyo_task_acl *ptr = 1421731d37aaSTetsuo Handa container_of(acl, typeof(*ptr), head); 1422cdcf6723STetsuo Handa 1423731d37aaSTetsuo Handa tomoyo_set_group(head, "task "); 1424731d37aaSTetsuo Handa tomoyo_set_string(head, "manual_domain_transition "); 1425731d37aaSTetsuo Handa tomoyo_set_string(head, ptr->domainname->name); 1426bd03a3e4STetsuo Handa } else if (head->r.print_transition_related_only) { 1427063821c8STetsuo Handa return true; 14285db5a39bSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) { 14295db5a39bSTetsuo Handa struct tomoyo_path2_acl *ptr = 14305db5a39bSTetsuo Handa container_of(acl, typeof(*ptr), head); 14310d2171d7STetsuo Handa const u8 perm = ptr->perm; 1432cdcf6723STetsuo Handa 14330d2171d7STetsuo Handa for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { 14340d2171d7STetsuo Handa if (!(perm & (1 << bit))) 14350d2171d7STetsuo Handa continue; 14360d2171d7STetsuo Handa if (first) { 14370d2171d7STetsuo Handa tomoyo_set_group(head, "file "); 14380d2171d7STetsuo Handa first = false; 14390d2171d7STetsuo Handa } else { 14400d2171d7STetsuo Handa tomoyo_set_slash(head); 14410d2171d7STetsuo Handa } 14420d2171d7STetsuo Handa tomoyo_set_string(head, tomoyo_mac_keywords 14430d2171d7STetsuo Handa [tomoyo_pp2mac[bit]]); 14440d2171d7STetsuo Handa } 14450d2171d7STetsuo Handa if (first) 14460d2171d7STetsuo Handa return true; 1447f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->name1); 1448f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->name2); 14495db5a39bSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) { 14505db5a39bSTetsuo Handa struct tomoyo_path_number_acl *ptr = 14515db5a39bSTetsuo Handa container_of(acl, typeof(*ptr), head); 14520d2171d7STetsuo Handa const u8 perm = ptr->perm; 1453cdcf6723STetsuo Handa 14540d2171d7STetsuo Handa for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) { 14550d2171d7STetsuo Handa if (!(perm & (1 << bit))) 14560d2171d7STetsuo Handa continue; 14570d2171d7STetsuo Handa if (first) { 14580d2171d7STetsuo Handa tomoyo_set_group(head, "file "); 14590d2171d7STetsuo Handa first = false; 14600d2171d7STetsuo Handa } else { 14610d2171d7STetsuo Handa tomoyo_set_slash(head); 14620d2171d7STetsuo Handa } 14630d2171d7STetsuo Handa tomoyo_set_string(head, tomoyo_mac_keywords 14640d2171d7STetsuo Handa [tomoyo_pn2mac[bit]]); 14650d2171d7STetsuo Handa } 14660d2171d7STetsuo Handa if (first) 14670d2171d7STetsuo Handa return true; 1468f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->name); 1469f23571e8STetsuo Handa tomoyo_print_number_union(head, &ptr->number); 14705db5a39bSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) { 14715db5a39bSTetsuo Handa struct tomoyo_mkdev_acl *ptr = 14725db5a39bSTetsuo Handa container_of(acl, typeof(*ptr), head); 14730d2171d7STetsuo Handa const u8 perm = ptr->perm; 1474cdcf6723STetsuo Handa 14750d2171d7STetsuo Handa for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) { 14760d2171d7STetsuo Handa if (!(perm & (1 << bit))) 14770d2171d7STetsuo Handa continue; 14780d2171d7STetsuo Handa if (first) { 14790d2171d7STetsuo Handa tomoyo_set_group(head, "file "); 14800d2171d7STetsuo Handa first = false; 14810d2171d7STetsuo Handa } else { 14820d2171d7STetsuo Handa tomoyo_set_slash(head); 14830d2171d7STetsuo Handa } 14840d2171d7STetsuo Handa tomoyo_set_string(head, tomoyo_mac_keywords 14850d2171d7STetsuo Handa [tomoyo_pnnn2mac[bit]]); 14860d2171d7STetsuo Handa } 14870d2171d7STetsuo Handa if (first) 14880d2171d7STetsuo Handa return true; 1489f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->name); 1490f23571e8STetsuo Handa tomoyo_print_number_union(head, &ptr->mode); 1491f23571e8STetsuo Handa tomoyo_print_number_union(head, &ptr->major); 1492f23571e8STetsuo Handa tomoyo_print_number_union(head, &ptr->minor); 1493059d84dbSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_INET_ACL) { 1494059d84dbSTetsuo Handa struct tomoyo_inet_acl *ptr = 1495059d84dbSTetsuo Handa container_of(acl, typeof(*ptr), head); 1496059d84dbSTetsuo Handa const u8 perm = ptr->perm; 1497059d84dbSTetsuo Handa 1498059d84dbSTetsuo Handa for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { 1499059d84dbSTetsuo Handa if (!(perm & (1 << bit))) 1500059d84dbSTetsuo Handa continue; 1501059d84dbSTetsuo Handa if (first) { 1502059d84dbSTetsuo Handa tomoyo_set_group(head, "network inet "); 1503059d84dbSTetsuo Handa tomoyo_set_string(head, tomoyo_proto_keyword 1504059d84dbSTetsuo Handa [ptr->protocol]); 1505059d84dbSTetsuo Handa tomoyo_set_space(head); 1506059d84dbSTetsuo Handa first = false; 1507059d84dbSTetsuo Handa } else { 1508059d84dbSTetsuo Handa tomoyo_set_slash(head); 1509059d84dbSTetsuo Handa } 1510059d84dbSTetsuo Handa tomoyo_set_string(head, tomoyo_socket_keyword[bit]); 1511059d84dbSTetsuo Handa } 1512059d84dbSTetsuo Handa if (first) 1513059d84dbSTetsuo Handa return true; 1514059d84dbSTetsuo Handa tomoyo_set_space(head); 1515059d84dbSTetsuo Handa if (ptr->address.group) { 1516059d84dbSTetsuo Handa tomoyo_set_string(head, "@"); 1517059d84dbSTetsuo Handa tomoyo_set_string(head, ptr->address.group->group_name 1518059d84dbSTetsuo Handa ->name); 1519059d84dbSTetsuo Handa } else { 1520059d84dbSTetsuo Handa char buf[128]; 1521cdcf6723STetsuo Handa 1522059d84dbSTetsuo Handa tomoyo_print_ip(buf, sizeof(buf), &ptr->address); 1523059d84dbSTetsuo Handa tomoyo_io_printf(head, "%s", buf); 1524059d84dbSTetsuo Handa } 1525059d84dbSTetsuo Handa tomoyo_print_number_union(head, &ptr->port); 1526059d84dbSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_UNIX_ACL) { 1527059d84dbSTetsuo Handa struct tomoyo_unix_acl *ptr = 1528059d84dbSTetsuo Handa container_of(acl, typeof(*ptr), head); 1529059d84dbSTetsuo Handa const u8 perm = ptr->perm; 1530059d84dbSTetsuo Handa 1531059d84dbSTetsuo Handa for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) { 1532059d84dbSTetsuo Handa if (!(perm & (1 << bit))) 1533059d84dbSTetsuo Handa continue; 1534059d84dbSTetsuo Handa if (first) { 1535059d84dbSTetsuo Handa tomoyo_set_group(head, "network unix "); 1536059d84dbSTetsuo Handa tomoyo_set_string(head, tomoyo_proto_keyword 1537059d84dbSTetsuo Handa [ptr->protocol]); 1538059d84dbSTetsuo Handa tomoyo_set_space(head); 1539059d84dbSTetsuo Handa first = false; 1540059d84dbSTetsuo Handa } else { 1541059d84dbSTetsuo Handa tomoyo_set_slash(head); 1542059d84dbSTetsuo Handa } 1543059d84dbSTetsuo Handa tomoyo_set_string(head, tomoyo_socket_keyword[bit]); 1544059d84dbSTetsuo Handa } 1545059d84dbSTetsuo Handa if (first) 1546059d84dbSTetsuo Handa return true; 1547059d84dbSTetsuo Handa tomoyo_print_name_union(head, &ptr->name); 15485db5a39bSTetsuo Handa } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { 15495db5a39bSTetsuo Handa struct tomoyo_mount_acl *ptr = 15505db5a39bSTetsuo Handa container_of(acl, typeof(*ptr), head); 1551cdcf6723STetsuo Handa 15520d2171d7STetsuo Handa tomoyo_set_group(head, "file mount"); 1553f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->dev_name); 1554f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->dir_name); 1555f23571e8STetsuo Handa tomoyo_print_name_union(head, &ptr->fs_type); 1556f23571e8STetsuo Handa tomoyo_print_number_union(head, &ptr->flags); 1557d58e0da8STetsuo Handa } else if (acl_type == TOMOYO_TYPE_ENV_ACL) { 1558d58e0da8STetsuo Handa struct tomoyo_env_acl *ptr = 1559d58e0da8STetsuo Handa container_of(acl, typeof(*ptr), head); 1560d58e0da8STetsuo Handa 1561d58e0da8STetsuo Handa tomoyo_set_group(head, "misc env "); 1562d58e0da8STetsuo Handa tomoyo_set_string(head, ptr->env->name); 15639590837bSKentaro Takeda } 15642066a361STetsuo Handa if (acl->cond) { 15652066a361STetsuo Handa head->r.print_cond_part = true; 15662066a361STetsuo Handa head->r.cond_step = 0; 15672066a361STetsuo Handa if (!tomoyo_flush(head)) 15682066a361STetsuo Handa return false; 15692066a361STetsuo Handa print_cond_part: 15702066a361STetsuo Handa if (!tomoyo_print_condition(head, acl->cond)) 15712066a361STetsuo Handa return false; 15722066a361STetsuo Handa head->r.print_cond_part = false; 15732066a361STetsuo Handa } else { 15740d2171d7STetsuo Handa tomoyo_set_lf(head); 15752066a361STetsuo Handa } 15765db5a39bSTetsuo Handa return true; 1577f23571e8STetsuo Handa } 1578f23571e8STetsuo Handa 1579f23571e8STetsuo Handa /** 1580f23571e8STetsuo Handa * tomoyo_read_domain2 - Read domain policy. 1581f23571e8STetsuo Handa * 1582f23571e8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 158332997144STetsuo Handa * @list: Pointer to "struct list_head". 1584f23571e8STetsuo Handa * 1585f23571e8STetsuo Handa * Caller holds tomoyo_read_lock(). 1586f23571e8STetsuo Handa * 1587f23571e8STetsuo Handa * Returns true on success, false otherwise. 1588f23571e8STetsuo Handa */ 1589f23571e8STetsuo Handa static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, 159032997144STetsuo Handa struct list_head *list) 1591f23571e8STetsuo Handa { 159232997144STetsuo Handa list_for_each_cookie(head->r.acl, list) { 1593f23571e8STetsuo Handa struct tomoyo_acl_info *ptr = 1594f23571e8STetsuo Handa list_entry(head->r.acl, typeof(*ptr), list); 1595cdcf6723STetsuo Handa 1596f23571e8STetsuo Handa if (!tomoyo_print_entry(head, ptr)) 15979590837bSKentaro Takeda return false; 15989590837bSKentaro Takeda } 1599f23571e8STetsuo Handa head->r.acl = NULL; 1600f23571e8STetsuo Handa return true; 1601f23571e8STetsuo Handa } 16029590837bSKentaro Takeda 16039590837bSKentaro Takeda /** 1604e2bf6907STetsuo Handa * tomoyo_read_domain - Read domain policy. 16059590837bSKentaro Takeda * 16069590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 16079590837bSKentaro Takeda * 1608fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 16099590837bSKentaro Takeda */ 1610e2bf6907STetsuo Handa static void tomoyo_read_domain(struct tomoyo_io_buffer *head) 16119590837bSKentaro Takeda { 1612f23571e8STetsuo Handa if (head->r.eof) 16138fbe71f0STetsuo Handa return; 1614f23571e8STetsuo Handa list_for_each_cookie(head->r.domain, &tomoyo_domain_list) { 1615475e6fa3STetsuo Handa struct tomoyo_domain_info *domain = 1616f23571e8STetsuo Handa list_entry(head->r.domain, typeof(*domain), list); 16172c47ab93STetsuo Handa u8 i; 1618cdcf6723STetsuo Handa 1619cdcf6723STetsuo Handa switch (head->r.step) { 1620f23571e8STetsuo Handa case 0: 1621f23571e8STetsuo Handa if (domain->is_deleted && 1622f23571e8STetsuo Handa !head->r.print_this_domain_only) 16239590837bSKentaro Takeda continue; 16249590837bSKentaro Takeda /* Print domainname and flags. */ 1625f23571e8STetsuo Handa tomoyo_set_string(head, domain->domainname->name); 1626f23571e8STetsuo Handa tomoyo_set_lf(head); 1627b5bc60b4STetsuo Handa tomoyo_io_printf(head, "use_profile %u\n", 1628f23571e8STetsuo Handa domain->profile); 16292c47ab93STetsuo Handa for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++) 16302c47ab93STetsuo Handa if (domain->flags[i]) 16312c47ab93STetsuo Handa tomoyo_set_string(head, tomoyo_dif[i]); 16324b425641STetsuo Handa head->r.index = 0; 16334b425641STetsuo Handa head->r.step++; 1634df561f66SGustavo A. R. Silva fallthrough; 16354b425641STetsuo Handa case 1: 16364b425641STetsuo Handa while (head->r.index < TOMOYO_MAX_ACL_GROUPS) { 16374b425641STetsuo Handa i = head->r.index++; 16384b425641STetsuo Handa if (!test_bit(i, domain->group)) 16394b425641STetsuo Handa continue; 16404b425641STetsuo Handa tomoyo_io_printf(head, "use_group %u\n", i); 16414b425641STetsuo Handa if (!tomoyo_flush(head)) 16424b425641STetsuo Handa return; 16434b425641STetsuo Handa } 16444b425641STetsuo Handa head->r.index = 0; 1645f23571e8STetsuo Handa head->r.step++; 1646f23571e8STetsuo Handa tomoyo_set_lf(head); 1647df561f66SGustavo A. R. Silva fallthrough; 16484b425641STetsuo Handa case 2: 164932997144STetsuo Handa if (!tomoyo_read_domain2(head, &domain->acl_info_list)) 1650f23571e8STetsuo Handa return; 1651f23571e8STetsuo Handa head->r.step++; 1652f23571e8STetsuo Handa if (!tomoyo_set_lf(head)) 1653f23571e8STetsuo Handa return; 1654df561f66SGustavo A. R. Silva fallthrough; 16554b425641STetsuo Handa case 3: 1656f23571e8STetsuo Handa head->r.step = 0; 1657f23571e8STetsuo Handa if (head->r.print_this_domain_only) 1658f23571e8STetsuo Handa goto done; 16599590837bSKentaro Takeda } 16609590837bSKentaro Takeda } 1661f23571e8STetsuo Handa done: 1662f23571e8STetsuo Handa head->r.eof = true; 16639590837bSKentaro Takeda } 16649590837bSKentaro Takeda 16659590837bSKentaro Takeda /** 16669590837bSKentaro Takeda * tomoyo_write_pid: Specify PID to obtain domainname. 16679590837bSKentaro Takeda * 16689590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 16699590837bSKentaro Takeda * 16709590837bSKentaro Takeda * Returns 0. 16719590837bSKentaro Takeda */ 16729590837bSKentaro Takeda static int tomoyo_write_pid(struct tomoyo_io_buffer *head) 16739590837bSKentaro Takeda { 1674f23571e8STetsuo Handa head->r.eof = false; 16759590837bSKentaro Takeda return 0; 16769590837bSKentaro Takeda } 16779590837bSKentaro Takeda 16789590837bSKentaro Takeda /** 16799590837bSKentaro Takeda * tomoyo_read_pid - Get domainname of the specified PID. 16809590837bSKentaro Takeda * 16819590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 16829590837bSKentaro Takeda * 16839590837bSKentaro Takeda * Returns the domainname which the specified PID is in on success, 16849590837bSKentaro Takeda * empty string otherwise. 16859590837bSKentaro Takeda * The PID is specified by tomoyo_write_pid() so that the user can obtain 16869590837bSKentaro Takeda * using read()/write() interface rather than sysctl() interface. 16879590837bSKentaro Takeda */ 16888fbe71f0STetsuo Handa static void tomoyo_read_pid(struct tomoyo_io_buffer *head) 16899590837bSKentaro Takeda { 1690f23571e8STetsuo Handa char *buf = head->write_buf; 1691f23571e8STetsuo Handa bool global_pid = false; 1692f23571e8STetsuo Handa unsigned int pid; 16939590837bSKentaro Takeda struct task_struct *p; 16949590837bSKentaro Takeda struct tomoyo_domain_info *domain = NULL; 1695f23571e8STetsuo Handa 1696f23571e8STetsuo Handa /* Accessing write_buf is safe because head->io_sem is held. */ 1697f23571e8STetsuo Handa if (!buf) { 1698f23571e8STetsuo Handa head->r.eof = true; 1699f23571e8STetsuo Handa return; /* Do nothing if open(O_RDONLY). */ 1700f23571e8STetsuo Handa } 1701f23571e8STetsuo Handa if (head->r.w_pos || head->r.eof) 1702f23571e8STetsuo Handa return; 1703f23571e8STetsuo Handa head->r.eof = true; 1704f23571e8STetsuo Handa if (tomoyo_str_starts(&buf, "global-pid ")) 1705f23571e8STetsuo Handa global_pid = true; 1706dbdb75bdSDing Xiang if (kstrtouint(buf, 10, &pid)) 1707dbdb75bdSDing Xiang return; 17081fcdc7c5STetsuo Handa rcu_read_lock(); 1709f23571e8STetsuo Handa if (global_pid) 1710f23571e8STetsuo Handa p = find_task_by_pid_ns(pid, &init_pid_ns); 1711f23571e8STetsuo Handa else 17129590837bSKentaro Takeda p = find_task_by_vpid(pid); 17139590837bSKentaro Takeda if (p) 17148c6cb983STetsuo Handa domain = tomoyo_task(p)->domain_info; 17151fcdc7c5STetsuo Handa rcu_read_unlock(); 1716f23571e8STetsuo Handa if (!domain) 1717f23571e8STetsuo Handa return; 1718f23571e8STetsuo Handa tomoyo_io_printf(head, "%u %u ", pid, domain->profile); 1719f23571e8STetsuo Handa tomoyo_set_string(head, domain->domainname->name); 17209590837bSKentaro Takeda } 17219590837bSKentaro Takeda 17220f2a55d5STetsuo Handa /* String table for domain transition control keywords. */ 17235448ec4fSTetsuo Handa static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { 1724bd03a3e4STetsuo Handa [TOMOYO_TRANSITION_CONTROL_NO_RESET] = "no_reset_domain ", 1725bd03a3e4STetsuo Handa [TOMOYO_TRANSITION_CONTROL_RESET] = "reset_domain ", 1726b5bc60b4STetsuo Handa [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ", 1727b5bc60b4STetsuo Handa [TOMOYO_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ", 1728b5bc60b4STetsuo Handa [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ", 1729b5bc60b4STetsuo Handa [TOMOYO_TRANSITION_CONTROL_KEEP] = "keep_domain ", 17305448ec4fSTetsuo Handa }; 17315448ec4fSTetsuo Handa 17320f2a55d5STetsuo Handa /* String table for grouping keywords. */ 1733e2bf6907STetsuo Handa static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = { 1734b5bc60b4STetsuo Handa [TOMOYO_PATH_GROUP] = "path_group ", 1735b5bc60b4STetsuo Handa [TOMOYO_NUMBER_GROUP] = "number_group ", 1736059d84dbSTetsuo Handa [TOMOYO_ADDRESS_GROUP] = "address_group ", 1737e2bf6907STetsuo Handa }; 1738e2bf6907STetsuo Handa 17399590837bSKentaro Takeda /** 1740e2bf6907STetsuo Handa * tomoyo_write_exception - Write exception policy. 17419590837bSKentaro Takeda * 17429590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 17439590837bSKentaro Takeda * 17449590837bSKentaro Takeda * Returns 0 on success, negative value otherwise. 1745fdb8ebb7STetsuo Handa * 1746fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 17479590837bSKentaro Takeda */ 1748e2bf6907STetsuo Handa static int tomoyo_write_exception(struct tomoyo_io_buffer *head) 17499590837bSKentaro Takeda { 1750bd03a3e4STetsuo Handa const bool is_delete = head->w.is_delete; 1751a238cf5bSTetsuo Handa struct tomoyo_acl_param param = { 1752bd03a3e4STetsuo Handa .ns = head->w.ns, 1753bd03a3e4STetsuo Handa .is_delete = is_delete, 1754a238cf5bSTetsuo Handa .data = head->write_buf, 1755e2bf6907STetsuo Handa }; 1756a238cf5bSTetsuo Handa u8 i; 1757cdcf6723STetsuo Handa 1758a238cf5bSTetsuo Handa if (tomoyo_str_starts(¶m.data, "aggregator ")) 1759a238cf5bSTetsuo Handa return tomoyo_write_aggregator(¶m); 1760e2bf6907STetsuo Handa for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) 1761a238cf5bSTetsuo Handa if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i])) 1762a238cf5bSTetsuo Handa return tomoyo_write_transition_control(¶m, i); 1763e2bf6907STetsuo Handa for (i = 0; i < TOMOYO_MAX_GROUP; i++) 1764a238cf5bSTetsuo Handa if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i])) 1765a238cf5bSTetsuo Handa return tomoyo_write_group(¶m, i); 176632997144STetsuo Handa if (tomoyo_str_starts(¶m.data, "acl_group ")) { 176732997144STetsuo Handa unsigned int group; 176832997144STetsuo Handa char *data; 1769cdcf6723STetsuo Handa 177032997144STetsuo Handa group = simple_strtoul(param.data, &data, 10); 177132997144STetsuo Handa if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ') 1772bd03a3e4STetsuo Handa return tomoyo_write_domain2 1773bd03a3e4STetsuo Handa (head->w.ns, &head->w.ns->acl_group[group], 1774bd03a3e4STetsuo Handa data, is_delete); 177532997144STetsuo Handa } 17769590837bSKentaro Takeda return -EINVAL; 17779590837bSKentaro Takeda } 17789590837bSKentaro Takeda 177931845e8cSTetsuo Handa /** 1780059d84dbSTetsuo Handa * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list. 178131845e8cSTetsuo Handa * 178231845e8cSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 178331845e8cSTetsuo Handa * @idx: Index number. 178431845e8cSTetsuo Handa * 178531845e8cSTetsuo Handa * Returns true on success, false otherwise. 178631845e8cSTetsuo Handa * 178731845e8cSTetsuo Handa * Caller holds tomoyo_read_lock(). 178831845e8cSTetsuo Handa */ 178931845e8cSTetsuo Handa static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) 179031845e8cSTetsuo Handa { 1791bd03a3e4STetsuo Handa struct tomoyo_policy_namespace *ns = 1792bd03a3e4STetsuo Handa container_of(head->r.ns, typeof(*ns), namespace_list); 1793bd03a3e4STetsuo Handa struct list_head *list = &ns->group_list[idx]; 1794cdcf6723STetsuo Handa 1795bd03a3e4STetsuo Handa list_for_each_cookie(head->r.group, list) { 179631845e8cSTetsuo Handa struct tomoyo_group *group = 17970df7e8b8STetsuo Handa list_entry(head->r.group, typeof(*group), head.list); 1798cdcf6723STetsuo Handa 1799f23571e8STetsuo Handa list_for_each_cookie(head->r.acl, &group->member_list) { 180031845e8cSTetsuo Handa struct tomoyo_acl_head *ptr = 1801f23571e8STetsuo Handa list_entry(head->r.acl, typeof(*ptr), list); 1802cdcf6723STetsuo Handa 180331845e8cSTetsuo Handa if (ptr->is_deleted) 180431845e8cSTetsuo Handa continue; 1805f23571e8STetsuo Handa if (!tomoyo_flush(head)) 180631845e8cSTetsuo Handa return false; 1807bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 1808f23571e8STetsuo Handa tomoyo_set_string(head, tomoyo_group_name[idx]); 1809f23571e8STetsuo Handa tomoyo_set_string(head, group->group_name->name); 1810f23571e8STetsuo Handa if (idx == TOMOYO_PATH_GROUP) { 1811f23571e8STetsuo Handa tomoyo_set_space(head); 1812f23571e8STetsuo Handa tomoyo_set_string(head, container_of 1813f23571e8STetsuo Handa (ptr, struct tomoyo_path_group, 1814f23571e8STetsuo Handa head)->member_name->name); 1815f23571e8STetsuo Handa } else if (idx == TOMOYO_NUMBER_GROUP) { 1816f23571e8STetsuo Handa tomoyo_print_number_union(head, &container_of 1817f23571e8STetsuo Handa (ptr, 1818f23571e8STetsuo Handa struct tomoyo_number_group, 1819f23571e8STetsuo Handa head)->number); 1820059d84dbSTetsuo Handa } else if (idx == TOMOYO_ADDRESS_GROUP) { 1821059d84dbSTetsuo Handa char buffer[128]; 1822059d84dbSTetsuo Handa struct tomoyo_address_group *member = 1823059d84dbSTetsuo Handa container_of(ptr, typeof(*member), 1824059d84dbSTetsuo Handa head); 1825cdcf6723STetsuo Handa 1826059d84dbSTetsuo Handa tomoyo_print_ip(buffer, sizeof(buffer), 1827059d84dbSTetsuo Handa &member->address); 1828059d84dbSTetsuo Handa tomoyo_io_printf(head, " %s", buffer); 182931845e8cSTetsuo Handa } 1830f23571e8STetsuo Handa tomoyo_set_lf(head); 183131845e8cSTetsuo Handa } 1832f23571e8STetsuo Handa head->r.acl = NULL; 1833f23571e8STetsuo Handa } 1834f23571e8STetsuo Handa head->r.group = NULL; 183531845e8cSTetsuo Handa return true; 183631845e8cSTetsuo Handa } 183731845e8cSTetsuo Handa 183831845e8cSTetsuo Handa /** 183931845e8cSTetsuo Handa * tomoyo_read_policy - Read "struct tomoyo_..._entry" list. 184031845e8cSTetsuo Handa * 184131845e8cSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 184231845e8cSTetsuo Handa * @idx: Index number. 184331845e8cSTetsuo Handa * 184431845e8cSTetsuo Handa * Returns true on success, false otherwise. 184531845e8cSTetsuo Handa * 184631845e8cSTetsuo Handa * Caller holds tomoyo_read_lock(). 184731845e8cSTetsuo Handa */ 184831845e8cSTetsuo Handa static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) 184931845e8cSTetsuo Handa { 1850bd03a3e4STetsuo Handa struct tomoyo_policy_namespace *ns = 1851bd03a3e4STetsuo Handa container_of(head->r.ns, typeof(*ns), namespace_list); 1852bd03a3e4STetsuo Handa struct list_head *list = &ns->policy_list[idx]; 1853cdcf6723STetsuo Handa 1854bd03a3e4STetsuo Handa list_for_each_cookie(head->r.acl, list) { 1855475e6fa3STetsuo Handa struct tomoyo_acl_head *acl = 1856f23571e8STetsuo Handa container_of(head->r.acl, typeof(*acl), list); 185731845e8cSTetsuo Handa if (acl->is_deleted) 185831845e8cSTetsuo Handa continue; 1859f23571e8STetsuo Handa if (!tomoyo_flush(head)) 1860f23571e8STetsuo Handa return false; 186131845e8cSTetsuo Handa switch (idx) { 18625448ec4fSTetsuo Handa case TOMOYO_ID_TRANSITION_CONTROL: 186331845e8cSTetsuo Handa { 18645448ec4fSTetsuo Handa struct tomoyo_transition_control *ptr = 186531845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1866cdcf6723STetsuo Handa 1867bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 18680d2171d7STetsuo Handa tomoyo_set_string(head, tomoyo_transition_type 1869f23571e8STetsuo Handa [ptr->type]); 18700d2171d7STetsuo Handa tomoyo_set_string(head, ptr->program ? 18710d2171d7STetsuo Handa ptr->program->name : "any"); 1872f23571e8STetsuo Handa tomoyo_set_string(head, " from "); 18730d2171d7STetsuo Handa tomoyo_set_string(head, ptr->domainname ? 18740d2171d7STetsuo Handa ptr->domainname->name : 18750d2171d7STetsuo Handa "any"); 187631845e8cSTetsuo Handa } 187731845e8cSTetsuo Handa break; 187831845e8cSTetsuo Handa case TOMOYO_ID_AGGREGATOR: 187931845e8cSTetsuo Handa { 1880e2bf6907STetsuo Handa struct tomoyo_aggregator *ptr = 188131845e8cSTetsuo Handa container_of(acl, typeof(*ptr), head); 1882cdcf6723STetsuo Handa 1883bd03a3e4STetsuo Handa tomoyo_print_namespace(head); 1884b5bc60b4STetsuo Handa tomoyo_set_string(head, "aggregator "); 1885f23571e8STetsuo Handa tomoyo_set_string(head, 1886f23571e8STetsuo Handa ptr->original_name->name); 1887f23571e8STetsuo Handa tomoyo_set_space(head); 1888f23571e8STetsuo Handa tomoyo_set_string(head, 1889f23571e8STetsuo Handa ptr->aggregated_name->name); 189031845e8cSTetsuo Handa } 189131845e8cSTetsuo Handa break; 189231845e8cSTetsuo Handa default: 189331845e8cSTetsuo Handa continue; 189431845e8cSTetsuo Handa } 1895f23571e8STetsuo Handa tomoyo_set_lf(head); 189631845e8cSTetsuo Handa } 1897f23571e8STetsuo Handa head->r.acl = NULL; 189831845e8cSTetsuo Handa return true; 189931845e8cSTetsuo Handa } 190031845e8cSTetsuo Handa 19019590837bSKentaro Takeda /** 1902e2bf6907STetsuo Handa * tomoyo_read_exception - Read exception policy. 19039590837bSKentaro Takeda * 19049590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 19059590837bSKentaro Takeda * 1906fdb8ebb7STetsuo Handa * Caller holds tomoyo_read_lock(). 19079590837bSKentaro Takeda */ 1908e2bf6907STetsuo Handa static void tomoyo_read_exception(struct tomoyo_io_buffer *head) 19099590837bSKentaro Takeda { 1910bd03a3e4STetsuo Handa struct tomoyo_policy_namespace *ns = 1911bd03a3e4STetsuo Handa container_of(head->r.ns, typeof(*ns), namespace_list); 1912cdcf6723STetsuo Handa 1913f23571e8STetsuo Handa if (head->r.eof) 191431845e8cSTetsuo Handa return; 1915f23571e8STetsuo Handa while (head->r.step < TOMOYO_MAX_POLICY && 1916f23571e8STetsuo Handa tomoyo_read_policy(head, head->r.step)) 1917f23571e8STetsuo Handa head->r.step++; 1918f23571e8STetsuo Handa if (head->r.step < TOMOYO_MAX_POLICY) 191931845e8cSTetsuo Handa return; 1920f23571e8STetsuo Handa while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP && 1921f23571e8STetsuo Handa tomoyo_read_group(head, head->r.step - TOMOYO_MAX_POLICY)) 1922f23571e8STetsuo Handa head->r.step++; 1923f23571e8STetsuo Handa if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP) 192431845e8cSTetsuo Handa return; 192532997144STetsuo Handa while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP 192632997144STetsuo Handa + TOMOYO_MAX_ACL_GROUPS) { 192732997144STetsuo Handa head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY 192832997144STetsuo Handa - TOMOYO_MAX_GROUP; 1929bd03a3e4STetsuo Handa if (!tomoyo_read_domain2(head, &ns->acl_group 193032997144STetsuo Handa [head->r.acl_group_index])) 193132997144STetsuo Handa return; 193232997144STetsuo Handa head->r.step++; 193332997144STetsuo Handa } 1934f23571e8STetsuo Handa head->r.eof = true; 19359590837bSKentaro Takeda } 19369590837bSKentaro Takeda 1937eadd99ccSTetsuo Handa /* Wait queue for kernel -> userspace notification. */ 193817fcfbd9STetsuo Handa static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait); 1939eadd99ccSTetsuo Handa /* Wait queue for userspace -> kernel notification. */ 1940eadd99ccSTetsuo Handa static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait); 194117fcfbd9STetsuo Handa 194217fcfbd9STetsuo Handa /* Structure for query. */ 1943e2bf6907STetsuo Handa struct tomoyo_query { 194417fcfbd9STetsuo Handa struct list_head list; 194559df3166STetsuo Handa struct tomoyo_domain_info *domain; 194617fcfbd9STetsuo Handa char *query; 1947eadd99ccSTetsuo Handa size_t query_len; 194817fcfbd9STetsuo Handa unsigned int serial; 1949eadd99ccSTetsuo Handa u8 timer; 1950eadd99ccSTetsuo Handa u8 answer; 1951eadd99ccSTetsuo Handa u8 retry; 195217fcfbd9STetsuo Handa }; 195317fcfbd9STetsuo Handa 1954e2bf6907STetsuo Handa /* The list for "struct tomoyo_query". */ 195517fcfbd9STetsuo Handa static LIST_HEAD(tomoyo_query_list); 195617fcfbd9STetsuo Handa 1957eadd99ccSTetsuo Handa /* Lock for manipulating tomoyo_query_list. */ 1958eadd99ccSTetsuo Handa static DEFINE_SPINLOCK(tomoyo_query_list_lock); 1959eadd99ccSTetsuo Handa 196017fcfbd9STetsuo Handa /* 196117fcfbd9STetsuo Handa * Number of "struct file" referring /sys/kernel/security/tomoyo/query 196217fcfbd9STetsuo Handa * interface. 196317fcfbd9STetsuo Handa */ 196417fcfbd9STetsuo Handa static atomic_t tomoyo_query_observers = ATOMIC_INIT(0); 196517fcfbd9STetsuo Handa 196617fcfbd9STetsuo Handa /** 19672ca9bf45STetsuo Handa * tomoyo_truncate - Truncate a line. 19682ca9bf45STetsuo Handa * 19692ca9bf45STetsuo Handa * @str: String to truncate. 19702ca9bf45STetsuo Handa * 19712ca9bf45STetsuo Handa * Returns length of truncated @str. 19722ca9bf45STetsuo Handa */ 19732ca9bf45STetsuo Handa static int tomoyo_truncate(char *str) 19742ca9bf45STetsuo Handa { 19752ca9bf45STetsuo Handa char *start = str; 1976cdcf6723STetsuo Handa 19772ca9bf45STetsuo Handa while (*(unsigned char *) str > (unsigned char) ' ') 19782ca9bf45STetsuo Handa str++; 19792ca9bf45STetsuo Handa *str = '\0'; 19802ca9bf45STetsuo Handa return strlen(start) + 1; 19812ca9bf45STetsuo Handa } 19822ca9bf45STetsuo Handa 19832ca9bf45STetsuo Handa /** 1984eadd99ccSTetsuo Handa * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode. 1985eadd99ccSTetsuo Handa * 1986eadd99ccSTetsuo Handa * @domain: Pointer to "struct tomoyo_domain_info". 1987eadd99ccSTetsuo Handa * @header: Lines containing ACL. 1988eadd99ccSTetsuo Handa * 1989eadd99ccSTetsuo Handa * Returns nothing. 1990eadd99ccSTetsuo Handa */ 1991eadd99ccSTetsuo Handa static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header) 1992eadd99ccSTetsuo Handa { 1993eadd99ccSTetsuo Handa char *buffer; 19942ca9bf45STetsuo Handa char *realpath = NULL; 19955b636857STetsuo Handa char *argv0 = NULL; 19962ca9bf45STetsuo Handa char *symlink = NULL; 1997eadd99ccSTetsuo Handa char *cp = strchr(header, '\n'); 1998eadd99ccSTetsuo Handa int len; 1999cdcf6723STetsuo Handa 2000eadd99ccSTetsuo Handa if (!cp) 2001eadd99ccSTetsuo Handa return; 2002eadd99ccSTetsuo Handa cp = strchr(cp + 1, '\n'); 2003eadd99ccSTetsuo Handa if (!cp) 2004eadd99ccSTetsuo Handa return; 2005eadd99ccSTetsuo Handa *cp++ = '\0'; 2006eadd99ccSTetsuo Handa len = strlen(cp) + 1; 20072ca9bf45STetsuo Handa /* strstr() will return NULL if ordering is wrong. */ 20082ca9bf45STetsuo Handa if (*cp == 'f') { 20095b636857STetsuo Handa argv0 = strstr(header, " argv[]={ \""); 20105b636857STetsuo Handa if (argv0) { 20115b636857STetsuo Handa argv0 += 10; 20125b636857STetsuo Handa len += tomoyo_truncate(argv0) + 14; 20135b636857STetsuo Handa } 20142ca9bf45STetsuo Handa realpath = strstr(header, " exec={ realpath=\""); 20152ca9bf45STetsuo Handa if (realpath) { 20162ca9bf45STetsuo Handa realpath += 8; 20172ca9bf45STetsuo Handa len += tomoyo_truncate(realpath) + 6; 20182ca9bf45STetsuo Handa } 20192ca9bf45STetsuo Handa symlink = strstr(header, " symlink.target=\""); 20202ca9bf45STetsuo Handa if (symlink) 20212ca9bf45STetsuo Handa len += tomoyo_truncate(symlink + 1) + 1; 20222ca9bf45STetsuo Handa } 2023eadd99ccSTetsuo Handa buffer = kmalloc(len, GFP_NOFS); 2024eadd99ccSTetsuo Handa if (!buffer) 2025eadd99ccSTetsuo Handa return; 2026eadd99ccSTetsuo Handa snprintf(buffer, len - 1, "%s", cp); 20272ca9bf45STetsuo Handa if (realpath) 20282ca9bf45STetsuo Handa tomoyo_addprintf(buffer, len, " exec.%s", realpath); 20295b636857STetsuo Handa if (argv0) 20305b636857STetsuo Handa tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0); 20312ca9bf45STetsuo Handa if (symlink) 20322ca9bf45STetsuo Handa tomoyo_addprintf(buffer, len, "%s", symlink); 2033eadd99ccSTetsuo Handa tomoyo_normalize_line(buffer); 2034b22b8b9fSTetsuo Handa if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer, 2035b22b8b9fSTetsuo Handa false)) 2036b22b8b9fSTetsuo Handa tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); 2037eadd99ccSTetsuo Handa kfree(buffer); 2038eadd99ccSTetsuo Handa } 2039eadd99ccSTetsuo Handa 2040eadd99ccSTetsuo Handa /** 204117fcfbd9STetsuo Handa * tomoyo_supervisor - Ask for the supervisor's decision. 204217fcfbd9STetsuo Handa * 204317fcfbd9STetsuo Handa * @r: Pointer to "struct tomoyo_request_info". 204417fcfbd9STetsuo Handa * @fmt: The printf()'s format string, followed by parameters. 204517fcfbd9STetsuo Handa * 204617fcfbd9STetsuo Handa * Returns 0 if the supervisor decided to permit the access request which 204717fcfbd9STetsuo Handa * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the 204817fcfbd9STetsuo Handa * supervisor decided to retry the access request which violated the policy in 204917fcfbd9STetsuo Handa * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise. 205017fcfbd9STetsuo Handa */ 205117fcfbd9STetsuo Handa int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) 205217fcfbd9STetsuo Handa { 205317fcfbd9STetsuo Handa va_list args; 2054eadd99ccSTetsuo Handa int error; 205517fcfbd9STetsuo Handa int len; 205617fcfbd9STetsuo Handa static unsigned int tomoyo_serial; 2057eadd99ccSTetsuo Handa struct tomoyo_query entry = { }; 205817fcfbd9STetsuo Handa bool quota_exceeded = false; 2059cdcf6723STetsuo Handa 2060eadd99ccSTetsuo Handa va_start(args, fmt); 206189868773SAl Viro len = vsnprintf(NULL, 0, fmt, args) + 1; 2062eadd99ccSTetsuo Handa va_end(args); 2063eadd99ccSTetsuo Handa /* Write /sys/kernel/security/tomoyo/audit. */ 2064eadd99ccSTetsuo Handa va_start(args, fmt); 2065eadd99ccSTetsuo Handa tomoyo_write_log2(r, len, fmt, args); 2066eadd99ccSTetsuo Handa va_end(args); 2067eadd99ccSTetsuo Handa /* Nothing more to do if granted. */ 2068eadd99ccSTetsuo Handa if (r->granted) 2069eadd99ccSTetsuo Handa return 0; 2070b22b8b9fSTetsuo Handa if (r->mode) 2071b22b8b9fSTetsuo Handa tomoyo_update_stat(r->mode); 207217fcfbd9STetsuo Handa switch (r->mode) { 2073eadd99ccSTetsuo Handa case TOMOYO_CONFIG_ENFORCING: 2074eadd99ccSTetsuo Handa error = -EPERM; 2075eadd99ccSTetsuo Handa if (atomic_read(&tomoyo_query_observers)) 2076eadd99ccSTetsuo Handa break; 2077eadd99ccSTetsuo Handa goto out; 207817fcfbd9STetsuo Handa case TOMOYO_CONFIG_LEARNING: 2079eadd99ccSTetsuo Handa error = 0; 2080eadd99ccSTetsuo Handa /* Check max_learning_entry parameter. */ 2081eadd99ccSTetsuo Handa if (tomoyo_domain_quota_is_ok(r)) 2082eadd99ccSTetsuo Handa break; 2083df561f66SGustavo A. R. Silva fallthrough; 2084eadd99ccSTetsuo Handa default: 208517fcfbd9STetsuo Handa return 0; 208617fcfbd9STetsuo Handa } 2087eadd99ccSTetsuo Handa /* Get message. */ 208817fcfbd9STetsuo Handa va_start(args, fmt); 2089eadd99ccSTetsuo Handa entry.query = tomoyo_init_log(r, len, fmt, args); 209017fcfbd9STetsuo Handa va_end(args); 2091eadd99ccSTetsuo Handa if (!entry.query) 209217fcfbd9STetsuo Handa goto out; 2093eadd99ccSTetsuo Handa entry.query_len = strlen(entry.query) + 1; 2094eadd99ccSTetsuo Handa if (!error) { 2095eadd99ccSTetsuo Handa tomoyo_add_entry(r->domain, entry.query); 209617fcfbd9STetsuo Handa goto out; 2097eadd99ccSTetsuo Handa } 2098c120c984SVlastimil Babka len = kmalloc_size_roundup(entry.query_len); 209959df3166STetsuo Handa entry.domain = r->domain; 210017fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 2101eadd99ccSTetsuo Handa if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] && 2102eadd99ccSTetsuo Handa tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len 2103eadd99ccSTetsuo Handa >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) { 210417fcfbd9STetsuo Handa quota_exceeded = true; 210517fcfbd9STetsuo Handa } else { 2106eadd99ccSTetsuo Handa entry.serial = tomoyo_serial++; 2107eadd99ccSTetsuo Handa entry.retry = r->retry; 2108eadd99ccSTetsuo Handa tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len; 2109eadd99ccSTetsuo Handa list_add_tail(&entry.list, &tomoyo_query_list); 211017fcfbd9STetsuo Handa } 211117fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 211217fcfbd9STetsuo Handa if (quota_exceeded) 211317fcfbd9STetsuo Handa goto out; 211417fcfbd9STetsuo Handa /* Give 10 seconds for supervisor's opinion. */ 2115eadd99ccSTetsuo Handa while (entry.timer < 10) { 2116eadd99ccSTetsuo Handa wake_up_all(&tomoyo_query_wait); 2117eadd99ccSTetsuo Handa if (wait_event_interruptible_timeout 2118eadd99ccSTetsuo Handa (tomoyo_answer_wait, entry.answer || 2119eadd99ccSTetsuo Handa !atomic_read(&tomoyo_query_observers), HZ)) 212017fcfbd9STetsuo Handa break; 2121eadd99ccSTetsuo Handa entry.timer++; 212217fcfbd9STetsuo Handa } 212317fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 2124eadd99ccSTetsuo Handa list_del(&entry.list); 2125eadd99ccSTetsuo Handa tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len; 212617fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 2127eadd99ccSTetsuo Handa switch (entry.answer) { 212817fcfbd9STetsuo Handa case 3: /* Asked to retry by administrator. */ 212917fcfbd9STetsuo Handa error = TOMOYO_RETRY_REQUEST; 213017fcfbd9STetsuo Handa r->retry++; 213117fcfbd9STetsuo Handa break; 213217fcfbd9STetsuo Handa case 1: 213317fcfbd9STetsuo Handa /* Granted by administrator. */ 213417fcfbd9STetsuo Handa error = 0; 213517fcfbd9STetsuo Handa break; 213617fcfbd9STetsuo Handa default: 2137eadd99ccSTetsuo Handa /* Timed out or rejected by administrator. */ 213817fcfbd9STetsuo Handa break; 213917fcfbd9STetsuo Handa } 214017fcfbd9STetsuo Handa out: 2141eadd99ccSTetsuo Handa kfree(entry.query); 214217fcfbd9STetsuo Handa return error; 214317fcfbd9STetsuo Handa } 214417fcfbd9STetsuo Handa 214517fcfbd9STetsuo Handa /** 214659df3166STetsuo Handa * tomoyo_find_domain_by_qid - Get domain by query id. 214759df3166STetsuo Handa * 214859df3166STetsuo Handa * @serial: Query ID assigned by tomoyo_supervisor(). 214959df3166STetsuo Handa * 215059df3166STetsuo Handa * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. 215159df3166STetsuo Handa */ 215259df3166STetsuo Handa static struct tomoyo_domain_info *tomoyo_find_domain_by_qid 215359df3166STetsuo Handa (unsigned int serial) 215459df3166STetsuo Handa { 215559df3166STetsuo Handa struct tomoyo_query *ptr; 215659df3166STetsuo Handa struct tomoyo_domain_info *domain = NULL; 2157cdcf6723STetsuo Handa 215859df3166STetsuo Handa spin_lock(&tomoyo_query_list_lock); 215959df3166STetsuo Handa list_for_each_entry(ptr, &tomoyo_query_list, list) { 21606041e834STetsuo Handa if (ptr->serial != serial) 216159df3166STetsuo Handa continue; 216259df3166STetsuo Handa domain = ptr->domain; 216359df3166STetsuo Handa break; 216459df3166STetsuo Handa } 216559df3166STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 216659df3166STetsuo Handa return domain; 216759df3166STetsuo Handa } 216859df3166STetsuo Handa 216959df3166STetsuo Handa /** 217017fcfbd9STetsuo Handa * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query. 217117fcfbd9STetsuo Handa * 217217fcfbd9STetsuo Handa * @file: Pointer to "struct file". 217317fcfbd9STetsuo Handa * @wait: Pointer to "poll_table". 217417fcfbd9STetsuo Handa * 2175a9a08845SLinus Torvalds * Returns EPOLLIN | EPOLLRDNORM when ready to read, 0 otherwise. 217617fcfbd9STetsuo Handa * 217717fcfbd9STetsuo Handa * Waits for access requests which violated policy in enforcing mode. 217817fcfbd9STetsuo Handa */ 2179c0d4be28SAl Viro static __poll_t tomoyo_poll_query(struct file *file, poll_table *wait) 218017fcfbd9STetsuo Handa { 21816041e834STetsuo Handa if (!list_empty(&tomoyo_query_list)) 2182a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM; 218317fcfbd9STetsuo Handa poll_wait(file, &tomoyo_query_wait, wait); 21846041e834STetsuo Handa if (!list_empty(&tomoyo_query_list)) 2185a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM; 218617fcfbd9STetsuo Handa return 0; 218717fcfbd9STetsuo Handa } 218817fcfbd9STetsuo Handa 218917fcfbd9STetsuo Handa /** 219017fcfbd9STetsuo Handa * tomoyo_read_query - Read access requests which violated policy in enforcing mode. 219117fcfbd9STetsuo Handa * 219217fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 219317fcfbd9STetsuo Handa */ 21948fbe71f0STetsuo Handa static void tomoyo_read_query(struct tomoyo_io_buffer *head) 219517fcfbd9STetsuo Handa { 219617fcfbd9STetsuo Handa struct list_head *tmp; 21972c47ab93STetsuo Handa unsigned int pos = 0; 21982c47ab93STetsuo Handa size_t len = 0; 219917fcfbd9STetsuo Handa char *buf; 2200cdcf6723STetsuo Handa 2201f23571e8STetsuo Handa if (head->r.w_pos) 22028fbe71f0STetsuo Handa return; 220317fcfbd9STetsuo Handa kfree(head->read_buf); 220417fcfbd9STetsuo Handa head->read_buf = NULL; 220517fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 220617fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 2207e2bf6907STetsuo Handa struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2208cdcf6723STetsuo Handa 2209f23571e8STetsuo Handa if (pos++ != head->r.query_index) 221017fcfbd9STetsuo Handa continue; 221117fcfbd9STetsuo Handa len = ptr->query_len; 221217fcfbd9STetsuo Handa break; 221317fcfbd9STetsuo Handa } 221417fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 221517fcfbd9STetsuo Handa if (!len) { 2216f23571e8STetsuo Handa head->r.query_index = 0; 22178fbe71f0STetsuo Handa return; 221817fcfbd9STetsuo Handa } 2219eadd99ccSTetsuo Handa buf = kzalloc(len + 32, GFP_NOFS); 222017fcfbd9STetsuo Handa if (!buf) 22218fbe71f0STetsuo Handa return; 222217fcfbd9STetsuo Handa pos = 0; 222317fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 222417fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 2225e2bf6907STetsuo Handa struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2226cdcf6723STetsuo Handa 2227f23571e8STetsuo Handa if (pos++ != head->r.query_index) 222817fcfbd9STetsuo Handa continue; 222917fcfbd9STetsuo Handa /* 223017fcfbd9STetsuo Handa * Some query can be skipped because tomoyo_query_list 223117fcfbd9STetsuo Handa * can change, but I don't care. 223217fcfbd9STetsuo Handa */ 223317fcfbd9STetsuo Handa if (len == ptr->query_len) 2234eadd99ccSTetsuo Handa snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial, 2235eadd99ccSTetsuo Handa ptr->retry, ptr->query); 223617fcfbd9STetsuo Handa break; 223717fcfbd9STetsuo Handa } 223817fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 223917fcfbd9STetsuo Handa if (buf[0]) { 224017fcfbd9STetsuo Handa head->read_buf = buf; 2241f23571e8STetsuo Handa head->r.w[head->r.w_pos++] = buf; 2242f23571e8STetsuo Handa head->r.query_index++; 224317fcfbd9STetsuo Handa } else { 224417fcfbd9STetsuo Handa kfree(buf); 224517fcfbd9STetsuo Handa } 224617fcfbd9STetsuo Handa } 224717fcfbd9STetsuo Handa 224817fcfbd9STetsuo Handa /** 224917fcfbd9STetsuo Handa * tomoyo_write_answer - Write the supervisor's decision. 225017fcfbd9STetsuo Handa * 225117fcfbd9STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 225217fcfbd9STetsuo Handa * 225317fcfbd9STetsuo Handa * Returns 0 on success, -EINVAL otherwise. 225417fcfbd9STetsuo Handa */ 225517fcfbd9STetsuo Handa static int tomoyo_write_answer(struct tomoyo_io_buffer *head) 225617fcfbd9STetsuo Handa { 225717fcfbd9STetsuo Handa char *data = head->write_buf; 225817fcfbd9STetsuo Handa struct list_head *tmp; 225917fcfbd9STetsuo Handa unsigned int serial; 226017fcfbd9STetsuo Handa unsigned int answer; 2261cdcf6723STetsuo Handa 226217fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 226317fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 2264e2bf6907STetsuo Handa struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2265cdcf6723STetsuo Handa 226617fcfbd9STetsuo Handa ptr->timer = 0; 226717fcfbd9STetsuo Handa } 226817fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 226917fcfbd9STetsuo Handa if (sscanf(data, "A%u=%u", &serial, &answer) != 2) 227017fcfbd9STetsuo Handa return -EINVAL; 227117fcfbd9STetsuo Handa spin_lock(&tomoyo_query_list_lock); 227217fcfbd9STetsuo Handa list_for_each(tmp, &tomoyo_query_list) { 2273e2bf6907STetsuo Handa struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); 2274cdcf6723STetsuo Handa 227517fcfbd9STetsuo Handa if (ptr->serial != serial) 227617fcfbd9STetsuo Handa continue; 227717fcfbd9STetsuo Handa ptr->answer = answer; 22786041e834STetsuo Handa /* Remove from tomoyo_query_list. */ 22796041e834STetsuo Handa if (ptr->answer) 22806041e834STetsuo Handa list_del_init(&ptr->list); 228117fcfbd9STetsuo Handa break; 228217fcfbd9STetsuo Handa } 228317fcfbd9STetsuo Handa spin_unlock(&tomoyo_query_list_lock); 228417fcfbd9STetsuo Handa return 0; 228517fcfbd9STetsuo Handa } 228617fcfbd9STetsuo Handa 228717fcfbd9STetsuo Handa /** 22889590837bSKentaro Takeda * tomoyo_read_version: Get version. 22899590837bSKentaro Takeda * 22909590837bSKentaro Takeda * @head: Pointer to "struct tomoyo_io_buffer". 22919590837bSKentaro Takeda * 22929590837bSKentaro Takeda * Returns version information. 22939590837bSKentaro Takeda */ 22948fbe71f0STetsuo Handa static void tomoyo_read_version(struct tomoyo_io_buffer *head) 22959590837bSKentaro Takeda { 2296f23571e8STetsuo Handa if (!head->r.eof) { 2297861f4bcfSTetsuo Handa tomoyo_io_printf(head, "2.6.0"); 2298f23571e8STetsuo Handa head->r.eof = true; 22999590837bSKentaro Takeda } 23009590837bSKentaro Takeda } 23019590837bSKentaro Takeda 2302b22b8b9fSTetsuo Handa /* String table for /sys/kernel/security/tomoyo/stat interface. */ 2303b22b8b9fSTetsuo Handa static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = { 2304b22b8b9fSTetsuo Handa [TOMOYO_STAT_POLICY_UPDATES] = "update:", 2305b22b8b9fSTetsuo Handa [TOMOYO_STAT_POLICY_LEARNING] = "violation in learning mode:", 2306b22b8b9fSTetsuo Handa [TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:", 2307b22b8b9fSTetsuo Handa [TOMOYO_STAT_POLICY_ENFORCING] = "violation in enforcing mode:", 2308b22b8b9fSTetsuo Handa }; 2309b22b8b9fSTetsuo Handa 2310b22b8b9fSTetsuo Handa /* String table for /sys/kernel/security/tomoyo/stat interface. */ 2311b22b8b9fSTetsuo Handa static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = { 2312b22b8b9fSTetsuo Handa [TOMOYO_MEMORY_POLICY] = "policy:", 2313b22b8b9fSTetsuo Handa [TOMOYO_MEMORY_AUDIT] = "audit log:", 2314b22b8b9fSTetsuo Handa [TOMOYO_MEMORY_QUERY] = "query message:", 2315b22b8b9fSTetsuo Handa }; 2316b22b8b9fSTetsuo Handa 2317b22b8b9fSTetsuo Handa /* Counter for number of updates. */ 2318a8772fadSTetsuo Handa static atomic_t tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; 2319a8772fadSTetsuo Handa /* Timestamp counter for last updated. */ 232092734092SArnd Bergmann static time64_t tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; 2321b22b8b9fSTetsuo Handa 2322b22b8b9fSTetsuo Handa /** 2323b22b8b9fSTetsuo Handa * tomoyo_update_stat - Update statistic counters. 2324b22b8b9fSTetsuo Handa * 2325b22b8b9fSTetsuo Handa * @index: Index for policy type. 2326b22b8b9fSTetsuo Handa * 2327b22b8b9fSTetsuo Handa * Returns nothing. 2328b22b8b9fSTetsuo Handa */ 2329b22b8b9fSTetsuo Handa void tomoyo_update_stat(const u8 index) 2330b22b8b9fSTetsuo Handa { 2331a8772fadSTetsuo Handa atomic_inc(&tomoyo_stat_updated[index]); 233292734092SArnd Bergmann tomoyo_stat_modified[index] = ktime_get_real_seconds(); 2333b22b8b9fSTetsuo Handa } 2334b22b8b9fSTetsuo Handa 2335b22b8b9fSTetsuo Handa /** 2336b22b8b9fSTetsuo Handa * tomoyo_read_stat - Read statistic data. 2337b22b8b9fSTetsuo Handa * 2338b22b8b9fSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 2339b22b8b9fSTetsuo Handa * 2340b22b8b9fSTetsuo Handa * Returns nothing. 2341b22b8b9fSTetsuo Handa */ 2342b22b8b9fSTetsuo Handa static void tomoyo_read_stat(struct tomoyo_io_buffer *head) 2343b22b8b9fSTetsuo Handa { 2344b22b8b9fSTetsuo Handa u8 i; 2345b22b8b9fSTetsuo Handa unsigned int total = 0; 2346cdcf6723STetsuo Handa 2347b22b8b9fSTetsuo Handa if (head->r.eof) 2348b22b8b9fSTetsuo Handa return; 2349b22b8b9fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) { 2350b22b8b9fSTetsuo Handa tomoyo_io_printf(head, "Policy %-30s %10u", 2351b22b8b9fSTetsuo Handa tomoyo_policy_headers[i], 2352a8772fadSTetsuo Handa atomic_read(&tomoyo_stat_updated[i])); 2353b22b8b9fSTetsuo Handa if (tomoyo_stat_modified[i]) { 2354b22b8b9fSTetsuo Handa struct tomoyo_time stamp; 2355cdcf6723STetsuo Handa 2356b22b8b9fSTetsuo Handa tomoyo_convert_time(tomoyo_stat_modified[i], &stamp); 2357cdcf6723STetsuo Handa tomoyo_io_printf(head, " (Last: %04u/%02u/%02u %02u:%02u:%02u)", 2358b22b8b9fSTetsuo Handa stamp.year, stamp.month, stamp.day, 2359b22b8b9fSTetsuo Handa stamp.hour, stamp.min, stamp.sec); 2360b22b8b9fSTetsuo Handa } 2361b22b8b9fSTetsuo Handa tomoyo_set_lf(head); 2362b22b8b9fSTetsuo Handa } 2363b22b8b9fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) { 2364b22b8b9fSTetsuo Handa unsigned int used = tomoyo_memory_used[i]; 2365cdcf6723STetsuo Handa 2366b22b8b9fSTetsuo Handa total += used; 2367b22b8b9fSTetsuo Handa tomoyo_io_printf(head, "Memory used by %-22s %10u", 2368b22b8b9fSTetsuo Handa tomoyo_memory_headers[i], used); 2369b22b8b9fSTetsuo Handa used = tomoyo_memory_quota[i]; 2370b22b8b9fSTetsuo Handa if (used) 2371b22b8b9fSTetsuo Handa tomoyo_io_printf(head, " (Quota: %10u)", used); 2372b22b8b9fSTetsuo Handa tomoyo_set_lf(head); 2373b22b8b9fSTetsuo Handa } 2374b22b8b9fSTetsuo Handa tomoyo_io_printf(head, "Total memory used: %10u\n", 2375b22b8b9fSTetsuo Handa total); 2376b22b8b9fSTetsuo Handa head->r.eof = true; 2377b22b8b9fSTetsuo Handa } 2378b22b8b9fSTetsuo Handa 2379b22b8b9fSTetsuo Handa /** 2380b22b8b9fSTetsuo Handa * tomoyo_write_stat - Set memory quota. 2381b22b8b9fSTetsuo Handa * 2382b22b8b9fSTetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 2383b22b8b9fSTetsuo Handa * 2384b22b8b9fSTetsuo Handa * Returns 0. 2385b22b8b9fSTetsuo Handa */ 2386b22b8b9fSTetsuo Handa static int tomoyo_write_stat(struct tomoyo_io_buffer *head) 2387b22b8b9fSTetsuo Handa { 2388b22b8b9fSTetsuo Handa char *data = head->write_buf; 2389b22b8b9fSTetsuo Handa u8 i; 2390cdcf6723STetsuo Handa 2391b22b8b9fSTetsuo Handa if (tomoyo_str_starts(&data, "Memory used by ")) 2392b22b8b9fSTetsuo Handa for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) 2393b22b8b9fSTetsuo Handa if (tomoyo_str_starts(&data, tomoyo_memory_headers[i])) 2394b22b8b9fSTetsuo Handa sscanf(data, "%u", &tomoyo_memory_quota[i]); 2395b22b8b9fSTetsuo Handa return 0; 2396b22b8b9fSTetsuo Handa } 2397b22b8b9fSTetsuo Handa 23989590837bSKentaro Takeda /** 23999590837bSKentaro Takeda * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface. 24009590837bSKentaro Takeda * 24019590837bSKentaro Takeda * @type: Type of interface. 24029590837bSKentaro Takeda * @file: Pointer to "struct file". 24039590837bSKentaro Takeda * 24042e503bbbSTetsuo Handa * Returns 0 on success, negative value otherwise. 24059590837bSKentaro Takeda */ 2406c3ef1500STetsuo Handa int tomoyo_open_control(const u8 type, struct file *file) 24079590837bSKentaro Takeda { 24084e5d6f7eSTetsuo Handa struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); 24099590837bSKentaro Takeda 24109590837bSKentaro Takeda if (!head) 24119590837bSKentaro Takeda return -ENOMEM; 24129590837bSKentaro Takeda mutex_init(&head->io_sem); 241317fcfbd9STetsuo Handa head->type = type; 24149590837bSKentaro Takeda switch (type) { 24159590837bSKentaro Takeda case TOMOYO_DOMAINPOLICY: 24169590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/domain_policy */ 2417e2bf6907STetsuo Handa head->write = tomoyo_write_domain; 2418e2bf6907STetsuo Handa head->read = tomoyo_read_domain; 24199590837bSKentaro Takeda break; 24209590837bSKentaro Takeda case TOMOYO_EXCEPTIONPOLICY: 24219590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/exception_policy */ 2422e2bf6907STetsuo Handa head->write = tomoyo_write_exception; 2423e2bf6907STetsuo Handa head->read = tomoyo_read_exception; 24249590837bSKentaro Takeda break; 2425eadd99ccSTetsuo Handa case TOMOYO_AUDIT: 2426eadd99ccSTetsuo Handa /* /sys/kernel/security/tomoyo/audit */ 2427eadd99ccSTetsuo Handa head->poll = tomoyo_poll_log; 2428eadd99ccSTetsuo Handa head->read = tomoyo_read_log; 2429eadd99ccSTetsuo Handa break; 24309590837bSKentaro Takeda case TOMOYO_PROCESS_STATUS: 24319590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/.process_status */ 24329590837bSKentaro Takeda head->write = tomoyo_write_pid; 24339590837bSKentaro Takeda head->read = tomoyo_read_pid; 24349590837bSKentaro Takeda break; 24359590837bSKentaro Takeda case TOMOYO_VERSION: 24369590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/version */ 24379590837bSKentaro Takeda head->read = tomoyo_read_version; 24389590837bSKentaro Takeda head->readbuf_size = 128; 24399590837bSKentaro Takeda break; 2440b22b8b9fSTetsuo Handa case TOMOYO_STAT: 2441b22b8b9fSTetsuo Handa /* /sys/kernel/security/tomoyo/stat */ 2442b22b8b9fSTetsuo Handa head->write = tomoyo_write_stat; 2443b22b8b9fSTetsuo Handa head->read = tomoyo_read_stat; 2444b22b8b9fSTetsuo Handa head->readbuf_size = 1024; 24459590837bSKentaro Takeda break; 24469590837bSKentaro Takeda case TOMOYO_PROFILE: 24479590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/profile */ 24489590837bSKentaro Takeda head->write = tomoyo_write_profile; 24499590837bSKentaro Takeda head->read = tomoyo_read_profile; 24509590837bSKentaro Takeda break; 245117fcfbd9STetsuo Handa case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */ 245217fcfbd9STetsuo Handa head->poll = tomoyo_poll_query; 245317fcfbd9STetsuo Handa head->write = tomoyo_write_answer; 245417fcfbd9STetsuo Handa head->read = tomoyo_read_query; 245517fcfbd9STetsuo Handa break; 24569590837bSKentaro Takeda case TOMOYO_MANAGER: 24579590837bSKentaro Takeda /* /sys/kernel/security/tomoyo/manager */ 2458e2bf6907STetsuo Handa head->write = tomoyo_write_manager; 2459e2bf6907STetsuo Handa head->read = tomoyo_read_manager; 24609590837bSKentaro Takeda break; 24619590837bSKentaro Takeda } 24629590837bSKentaro Takeda if (!(file->f_mode & FMODE_READ)) { 24639590837bSKentaro Takeda /* 24649590837bSKentaro Takeda * No need to allocate read_buf since it is not opened 24659590837bSKentaro Takeda * for reading. 24669590837bSKentaro Takeda */ 24679590837bSKentaro Takeda head->read = NULL; 246817fcfbd9STetsuo Handa head->poll = NULL; 246917fcfbd9STetsuo Handa } else if (!head->poll) { 247017fcfbd9STetsuo Handa /* Don't allocate read_buf for poll() access. */ 24719590837bSKentaro Takeda if (!head->readbuf_size) 24729590837bSKentaro Takeda head->readbuf_size = 4096 * 2; 24734e5d6f7eSTetsuo Handa head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); 24749590837bSKentaro Takeda if (!head->read_buf) { 24758e2d39a1STetsuo Handa kfree(head); 24769590837bSKentaro Takeda return -ENOMEM; 24779590837bSKentaro Takeda } 24789590837bSKentaro Takeda } 24799590837bSKentaro Takeda if (!(file->f_mode & FMODE_WRITE)) { 24809590837bSKentaro Takeda /* 24819590837bSKentaro Takeda * No need to allocate write_buf since it is not opened 24829590837bSKentaro Takeda * for writing. 24839590837bSKentaro Takeda */ 24849590837bSKentaro Takeda head->write = NULL; 24859590837bSKentaro Takeda } else if (head->write) { 24869590837bSKentaro Takeda head->writebuf_size = 4096 * 2; 24874e5d6f7eSTetsuo Handa head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); 24889590837bSKentaro Takeda if (!head->write_buf) { 24898e2d39a1STetsuo Handa kfree(head->read_buf); 24908e2d39a1STetsuo Handa kfree(head); 24919590837bSKentaro Takeda return -ENOMEM; 24929590837bSKentaro Takeda } 24939590837bSKentaro Takeda } 24949590837bSKentaro Takeda /* 249517fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , increment the 249617fcfbd9STetsuo Handa * observer counter. 249717fcfbd9STetsuo Handa * The obserber counter is used by tomoyo_supervisor() to see if 249817fcfbd9STetsuo Handa * there is some process monitoring /sys/kernel/security/tomoyo/query. 249917fcfbd9STetsuo Handa */ 25007c75964fSTetsuo Handa if (type == TOMOYO_QUERY) 250117fcfbd9STetsuo Handa atomic_inc(&tomoyo_query_observers); 25022e503bbbSTetsuo Handa file->private_data = head; 25032e503bbbSTetsuo Handa tomoyo_notify_gc(head, true); 25049590837bSKentaro Takeda return 0; 25059590837bSKentaro Takeda } 25069590837bSKentaro Takeda 25079590837bSKentaro Takeda /** 25080849e3baSTetsuo Handa * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. 25090849e3baSTetsuo Handa * 25100849e3baSTetsuo Handa * @file: Pointer to "struct file". 25116041e834STetsuo Handa * @wait: Pointer to "poll_table". Maybe NULL. 25120849e3baSTetsuo Handa * 2513a9a08845SLinus Torvalds * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write, 2514a9a08845SLinus Torvalds * EPOLLOUT | EPOLLWRNORM otherwise. 25150849e3baSTetsuo Handa */ 2516c0d4be28SAl Viro __poll_t tomoyo_poll_control(struct file *file, poll_table *wait) 25170849e3baSTetsuo Handa { 25180849e3baSTetsuo Handa struct tomoyo_io_buffer *head = file->private_data; 2519cdcf6723STetsuo Handa 25206041e834STetsuo Handa if (head->poll) 2521a9a08845SLinus Torvalds return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM; 2522a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM; 25230849e3baSTetsuo Handa } 25240849e3baSTetsuo Handa 25250849e3baSTetsuo Handa /** 2526bd03a3e4STetsuo Handa * tomoyo_set_namespace_cursor - Set namespace to read. 2527bd03a3e4STetsuo Handa * 2528bd03a3e4STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 2529bd03a3e4STetsuo Handa * 2530bd03a3e4STetsuo Handa * Returns nothing. 2531bd03a3e4STetsuo Handa */ 2532bd03a3e4STetsuo Handa static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head) 2533bd03a3e4STetsuo Handa { 2534bd03a3e4STetsuo Handa struct list_head *ns; 2535cdcf6723STetsuo Handa 2536bd03a3e4STetsuo Handa if (head->type != TOMOYO_EXCEPTIONPOLICY && 2537bd03a3e4STetsuo Handa head->type != TOMOYO_PROFILE) 2538bd03a3e4STetsuo Handa return; 2539bd03a3e4STetsuo Handa /* 2540bd03a3e4STetsuo Handa * If this is the first read, or reading previous namespace finished 2541bd03a3e4STetsuo Handa * and has more namespaces to read, update the namespace cursor. 2542bd03a3e4STetsuo Handa */ 2543bd03a3e4STetsuo Handa ns = head->r.ns; 2544bd03a3e4STetsuo Handa if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) { 2545bd03a3e4STetsuo Handa /* Clearing is OK because tomoyo_flush() returned true. */ 2546bd03a3e4STetsuo Handa memset(&head->r, 0, sizeof(head->r)); 2547bd03a3e4STetsuo Handa head->r.ns = ns ? ns->next : tomoyo_namespace_list.next; 2548bd03a3e4STetsuo Handa } 2549bd03a3e4STetsuo Handa } 2550bd03a3e4STetsuo Handa 2551bd03a3e4STetsuo Handa /** 2552bd03a3e4STetsuo Handa * tomoyo_has_more_namespace - Check for unread namespaces. 2553bd03a3e4STetsuo Handa * 2554bd03a3e4STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 2555bd03a3e4STetsuo Handa * 2556bd03a3e4STetsuo Handa * Returns true if we have more entries to print, false otherwise. 2557bd03a3e4STetsuo Handa */ 2558bd03a3e4STetsuo Handa static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head) 2559bd03a3e4STetsuo Handa { 2560bd03a3e4STetsuo Handa return (head->type == TOMOYO_EXCEPTIONPOLICY || 2561bd03a3e4STetsuo Handa head->type == TOMOYO_PROFILE) && head->r.eof && 2562bd03a3e4STetsuo Handa head->r.ns->next != &tomoyo_namespace_list; 2563bd03a3e4STetsuo Handa } 2564bd03a3e4STetsuo Handa 2565bd03a3e4STetsuo Handa /** 25669590837bSKentaro Takeda * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface. 25679590837bSKentaro Takeda * 25680df7e8b8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 256915269fb1STetsuo Handa * @buffer: Pointer to buffer to write to. 25709590837bSKentaro Takeda * @buffer_len: Size of @buffer. 25719590837bSKentaro Takeda * 25729590837bSKentaro Takeda * Returns bytes read on success, negative value otherwise. 25739590837bSKentaro Takeda */ 25742c47ab93STetsuo Handa ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer, 25759590837bSKentaro Takeda const int buffer_len) 25769590837bSKentaro Takeda { 2577f23571e8STetsuo Handa int len; 25782e503bbbSTetsuo Handa int idx; 25799590837bSKentaro Takeda 25809590837bSKentaro Takeda if (!head->read) 2581cdcf6723STetsuo Handa return -EINVAL; 25829590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 25839590837bSKentaro Takeda return -EINTR; 2584f23571e8STetsuo Handa head->read_user_buf = buffer; 2585f23571e8STetsuo Handa head->read_user_buf_avail = buffer_len; 25862e503bbbSTetsuo Handa idx = tomoyo_read_lock(); 2587f23571e8STetsuo Handa if (tomoyo_flush(head)) 25889590837bSKentaro Takeda /* Call the policy handler. */ 2589bd03a3e4STetsuo Handa do { 2590bd03a3e4STetsuo Handa tomoyo_set_namespace_cursor(head); 25918fbe71f0STetsuo Handa head->read(head); 2592bd03a3e4STetsuo Handa } while (tomoyo_flush(head) && 2593bd03a3e4STetsuo Handa tomoyo_has_more_namespace(head)); 25942e503bbbSTetsuo Handa tomoyo_read_unlock(idx); 2595f23571e8STetsuo Handa len = head->read_user_buf - buffer; 25969590837bSKentaro Takeda mutex_unlock(&head->io_sem); 25979590837bSKentaro Takeda return len; 25989590837bSKentaro Takeda } 25999590837bSKentaro Takeda 26009590837bSKentaro Takeda /** 2601bd03a3e4STetsuo Handa * tomoyo_parse_policy - Parse a policy line. 2602bd03a3e4STetsuo Handa * 260315269fb1STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 2604bd03a3e4STetsuo Handa * @line: Line to parse. 2605bd03a3e4STetsuo Handa * 2606bd03a3e4STetsuo Handa * Returns 0 on success, negative value otherwise. 2607bd03a3e4STetsuo Handa * 2608bd03a3e4STetsuo Handa * Caller holds tomoyo_read_lock(). 2609bd03a3e4STetsuo Handa */ 2610bd03a3e4STetsuo Handa static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) 2611bd03a3e4STetsuo Handa { 2612bd03a3e4STetsuo Handa /* Delete request? */ 2613bd03a3e4STetsuo Handa head->w.is_delete = !strncmp(line, "delete ", 7); 2614bd03a3e4STetsuo Handa if (head->w.is_delete) 2615bd03a3e4STetsuo Handa memmove(line, line + 7, strlen(line + 7) + 1); 2616bd03a3e4STetsuo Handa /* Selecting namespace to update. */ 2617bd03a3e4STetsuo Handa if (head->type == TOMOYO_EXCEPTIONPOLICY || 2618bd03a3e4STetsuo Handa head->type == TOMOYO_PROFILE) { 2619bd03a3e4STetsuo Handa if (*line == '<') { 2620bd03a3e4STetsuo Handa char *cp = strchr(line, ' '); 2621cdcf6723STetsuo Handa 2622bd03a3e4STetsuo Handa if (cp) { 2623bd03a3e4STetsuo Handa *cp++ = '\0'; 2624bd03a3e4STetsuo Handa head->w.ns = tomoyo_assign_namespace(line); 2625bd03a3e4STetsuo Handa memmove(line, cp, strlen(cp) + 1); 2626bd03a3e4STetsuo Handa } else 2627bd03a3e4STetsuo Handa head->w.ns = NULL; 2628bd03a3e4STetsuo Handa } else 2629bd03a3e4STetsuo Handa head->w.ns = &tomoyo_kernel_namespace; 2630bd03a3e4STetsuo Handa /* Don't allow updating if namespace is invalid. */ 2631bd03a3e4STetsuo Handa if (!head->w.ns) 2632bd03a3e4STetsuo Handa return -ENOENT; 2633bd03a3e4STetsuo Handa } 2634bd03a3e4STetsuo Handa /* Do the update. */ 2635bd03a3e4STetsuo Handa return head->write(head); 2636bd03a3e4STetsuo Handa } 2637bd03a3e4STetsuo Handa 2638bd03a3e4STetsuo Handa /** 26399590837bSKentaro Takeda * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface. 26409590837bSKentaro Takeda * 26410df7e8b8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 26429590837bSKentaro Takeda * @buffer: Pointer to buffer to read from. 26439590837bSKentaro Takeda * @buffer_len: Size of @buffer. 26449590837bSKentaro Takeda * 26459590837bSKentaro Takeda * Returns @buffer_len on success, negative value otherwise. 26469590837bSKentaro Takeda */ 26472c47ab93STetsuo Handa ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head, 26480df7e8b8STetsuo Handa const char __user *buffer, const int buffer_len) 26499590837bSKentaro Takeda { 26509590837bSKentaro Takeda int error = buffer_len; 2651bd03a3e4STetsuo Handa size_t avail_len = buffer_len; 26522f03fc34STetsuo Handa char *cp0; 26532e503bbbSTetsuo Handa int idx; 2654cdcf6723STetsuo Handa 26559590837bSKentaro Takeda if (!head->write) 2656cdcf6723STetsuo Handa return -EINVAL; 26579590837bSKentaro Takeda if (mutex_lock_interruptible(&head->io_sem)) 26589590837bSKentaro Takeda return -EINTR; 26592f03fc34STetsuo Handa cp0 = head->write_buf; 2660e0b057b4STetsuo Handa head->read_user_buf_avail = 0; 26612e503bbbSTetsuo Handa idx = tomoyo_read_lock(); 26629590837bSKentaro Takeda /* Read a line and dispatch it to the policy handler. */ 26639590837bSKentaro Takeda while (avail_len > 0) { 26649590837bSKentaro Takeda char c; 2665cdcf6723STetsuo Handa 26660df7e8b8STetsuo Handa if (head->w.avail >= head->writebuf_size - 1) { 2667bd03a3e4STetsuo Handa const int len = head->writebuf_size * 2; 2668bd03a3e4STetsuo Handa char *cp = kzalloc(len, GFP_NOFS); 2669cdcf6723STetsuo Handa 2670bd03a3e4STetsuo Handa if (!cp) { 26719590837bSKentaro Takeda error = -ENOMEM; 26729590837bSKentaro Takeda break; 2673bd03a3e4STetsuo Handa } 2674bd03a3e4STetsuo Handa memmove(cp, cp0, head->w.avail); 2675bd03a3e4STetsuo Handa kfree(cp0); 2676bd03a3e4STetsuo Handa head->write_buf = cp; 2677bd03a3e4STetsuo Handa cp0 = cp; 2678bd03a3e4STetsuo Handa head->writebuf_size = len; 2679bd03a3e4STetsuo Handa } 2680bd03a3e4STetsuo Handa if (get_user(c, buffer)) { 26819590837bSKentaro Takeda error = -EFAULT; 26829590837bSKentaro Takeda break; 26839590837bSKentaro Takeda } 26849590837bSKentaro Takeda buffer++; 26859590837bSKentaro Takeda avail_len--; 26860df7e8b8STetsuo Handa cp0[head->w.avail++] = c; 26879590837bSKentaro Takeda if (c != '\n') 26889590837bSKentaro Takeda continue; 26890df7e8b8STetsuo Handa cp0[head->w.avail - 1] = '\0'; 26900df7e8b8STetsuo Handa head->w.avail = 0; 26919590837bSKentaro Takeda tomoyo_normalize_line(cp0); 2692bd03a3e4STetsuo Handa if (!strcmp(cp0, "reset")) { 2693bd03a3e4STetsuo Handa head->w.ns = &tomoyo_kernel_namespace; 2694bd03a3e4STetsuo Handa head->w.domain = NULL; 2695bd03a3e4STetsuo Handa memset(&head->r, 0, sizeof(head->r)); 2696bd03a3e4STetsuo Handa continue; 26979590837bSKentaro Takeda } 2698bd03a3e4STetsuo Handa /* Don't allow updating policies by non manager programs. */ 2699bd03a3e4STetsuo Handa switch (head->type) { 2700bd03a3e4STetsuo Handa case TOMOYO_PROCESS_STATUS: 2701bd03a3e4STetsuo Handa /* This does not write anything. */ 2702bd03a3e4STetsuo Handa break; 2703bd03a3e4STetsuo Handa case TOMOYO_DOMAINPOLICY: 2704bd03a3e4STetsuo Handa if (tomoyo_select_domain(head, cp0)) 2705bd03a3e4STetsuo Handa continue; 2706df561f66SGustavo A. R. Silva fallthrough; 2707bd03a3e4STetsuo Handa case TOMOYO_EXCEPTIONPOLICY: 2708bd03a3e4STetsuo Handa if (!strcmp(cp0, "select transition_only")) { 2709bd03a3e4STetsuo Handa head->r.print_transition_related_only = true; 2710bd03a3e4STetsuo Handa continue; 2711bd03a3e4STetsuo Handa } 2712df561f66SGustavo A. R. Silva fallthrough; 2713bd03a3e4STetsuo Handa default: 2714bd03a3e4STetsuo Handa if (!tomoyo_manager()) { 2715bd03a3e4STetsuo Handa error = -EPERM; 2716bd03a3e4STetsuo Handa goto out; 2717bd03a3e4STetsuo Handa } 2718bd03a3e4STetsuo Handa } 2719bd03a3e4STetsuo Handa switch (tomoyo_parse_policy(head, cp0)) { 2720bd03a3e4STetsuo Handa case -EPERM: 2721bd03a3e4STetsuo Handa error = -EPERM; 2722bd03a3e4STetsuo Handa goto out; 2723b22b8b9fSTetsuo Handa case 0: 2724b22b8b9fSTetsuo Handa switch (head->type) { 2725b22b8b9fSTetsuo Handa case TOMOYO_DOMAINPOLICY: 2726b22b8b9fSTetsuo Handa case TOMOYO_EXCEPTIONPOLICY: 2727b22b8b9fSTetsuo Handa case TOMOYO_STAT: 2728b22b8b9fSTetsuo Handa case TOMOYO_PROFILE: 2729b22b8b9fSTetsuo Handa case TOMOYO_MANAGER: 2730b22b8b9fSTetsuo Handa tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES); 2731b22b8b9fSTetsuo Handa break; 2732b22b8b9fSTetsuo Handa default: 2733b22b8b9fSTetsuo Handa break; 2734b22b8b9fSTetsuo Handa } 2735b22b8b9fSTetsuo Handa break; 2736bd03a3e4STetsuo Handa } 2737bd03a3e4STetsuo Handa } 2738bd03a3e4STetsuo Handa out: 27392e503bbbSTetsuo Handa tomoyo_read_unlock(idx); 27409590837bSKentaro Takeda mutex_unlock(&head->io_sem); 27419590837bSKentaro Takeda return error; 27429590837bSKentaro Takeda } 27439590837bSKentaro Takeda 27449590837bSKentaro Takeda /** 27459590837bSKentaro Takeda * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface. 27469590837bSKentaro Takeda * 27470df7e8b8STetsuo Handa * @head: Pointer to "struct tomoyo_io_buffer". 27489590837bSKentaro Takeda */ 2749e53cfda5SAl Viro void tomoyo_close_control(struct tomoyo_io_buffer *head) 27509590837bSKentaro Takeda { 275117fcfbd9STetsuo Handa /* 275217fcfbd9STetsuo Handa * If the file is /sys/kernel/security/tomoyo/query , decrement the 275317fcfbd9STetsuo Handa * observer counter. 275417fcfbd9STetsuo Handa */ 27552e503bbbSTetsuo Handa if (head->type == TOMOYO_QUERY && 27562e503bbbSTetsuo Handa atomic_dec_and_test(&tomoyo_query_observers)) 27572e503bbbSTetsuo Handa wake_up_all(&tomoyo_answer_wait); 27582e503bbbSTetsuo Handa tomoyo_notify_gc(head, false); 27599590837bSKentaro Takeda } 27609590837bSKentaro Takeda 27619590837bSKentaro Takeda /** 2762c3ef1500STetsuo Handa * tomoyo_check_profile - Check all profiles currently assigned to domains are defined. 27639590837bSKentaro Takeda */ 2764c3ef1500STetsuo Handa void tomoyo_check_profile(void) 27659590837bSKentaro Takeda { 2766c3ef1500STetsuo Handa struct tomoyo_domain_info *domain; 2767c3ef1500STetsuo Handa const int idx = tomoyo_read_lock(); 2768cdcf6723STetsuo Handa 2769c3ef1500STetsuo Handa tomoyo_policy_loaded = true; 2770861f4bcfSTetsuo Handa pr_info("TOMOYO: 2.6.0\n"); 27716bd5ce60STetsuo Handa list_for_each_entry_rcu(domain, &tomoyo_domain_list, list, 27726bd5ce60STetsuo Handa srcu_read_lock_held(&tomoyo_ss)) { 2773c3ef1500STetsuo Handa const u8 profile = domain->profile; 2774861f4bcfSTetsuo Handa struct tomoyo_policy_namespace *ns = domain->ns; 2775cdcf6723STetsuo Handa 2776861f4bcfSTetsuo Handa if (ns->profile_version == 20110903) { 2777861f4bcfSTetsuo Handa pr_info_once("Converting profile version from %u to %u.\n", 2778861f4bcfSTetsuo Handa 20110903, 20150505); 2779861f4bcfSTetsuo Handa ns->profile_version = 20150505; 2780861f4bcfSTetsuo Handa } 2781861f4bcfSTetsuo Handa if (ns->profile_version != 20150505) 2782cdcf6723STetsuo Handa pr_err("Profile version %u is not supported.\n", 2783bd03a3e4STetsuo Handa ns->profile_version); 2784bd03a3e4STetsuo Handa else if (!ns->profile_ptr[profile]) 2785cdcf6723STetsuo Handa pr_err("Profile %u (used by '%s') is not defined.\n", 2786c3ef1500STetsuo Handa profile, domain->domainname->name); 2787bd03a3e4STetsuo Handa else 2788bd03a3e4STetsuo Handa continue; 2789861f4bcfSTetsuo Handa pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n"); 2790*c6144a21STetsuo Handa pr_err("Please see https://tomoyo.sourceforge.net/2.6/ for more information.\n"); 2791bd03a3e4STetsuo Handa panic("STOP!"); 27929590837bSKentaro Takeda } 2793c3ef1500STetsuo Handa tomoyo_read_unlock(idx); 2794cdcf6723STetsuo Handa pr_info("Mandatory Access Control activated.\n"); 27959590837bSKentaro Takeda } 2796efe836abSTetsuo Handa 2797efe836abSTetsuo Handa /** 2798efe836abSTetsuo Handa * tomoyo_load_builtin_policy - Load built-in policy. 2799efe836abSTetsuo Handa * 2800efe836abSTetsuo Handa * Returns nothing. 2801efe836abSTetsuo Handa */ 2802efe836abSTetsuo Handa void __init tomoyo_load_builtin_policy(void) 2803efe836abSTetsuo Handa { 2804e80b1859STetsuo Handa #ifdef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING 2805e80b1859STetsuo Handa static char tomoyo_builtin_profile[] __initdata = 2806e80b1859STetsuo Handa "PROFILE_VERSION=20150505\n" 2807e80b1859STetsuo Handa "0-CONFIG={ mode=learning grant_log=no reject_log=yes }\n"; 2808e80b1859STetsuo Handa static char tomoyo_builtin_exception_policy[] __initdata = 2809e80b1859STetsuo Handa "aggregator proc:/self/exe /proc/self/exe\n"; 2810e80b1859STetsuo Handa static char tomoyo_builtin_domain_policy[] __initdata = ""; 2811e80b1859STetsuo Handa static char tomoyo_builtin_manager[] __initdata = ""; 2812e80b1859STetsuo Handa static char tomoyo_builtin_stat[] __initdata = ""; 2813e80b1859STetsuo Handa #else 2814efe836abSTetsuo Handa /* 2815efe836abSTetsuo Handa * This include file is manually created and contains built-in policy 2816efe836abSTetsuo Handa * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy", 2817efe836abSTetsuo Handa * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager", 2818efe836abSTetsuo Handa * "tomoyo_builtin_stat" in the form of "static char [] __initdata". 2819efe836abSTetsuo Handa */ 2820efe836abSTetsuo Handa #include "builtin-policy.h" 2821e80b1859STetsuo Handa #endif 2822efe836abSTetsuo Handa u8 i; 2823efe836abSTetsuo Handa const int idx = tomoyo_read_lock(); 2824cdcf6723STetsuo Handa 2825efe836abSTetsuo Handa for (i = 0; i < 5; i++) { 2826efe836abSTetsuo Handa struct tomoyo_io_buffer head = { }; 2827efe836abSTetsuo Handa char *start = ""; 2828cdcf6723STetsuo Handa 2829efe836abSTetsuo Handa switch (i) { 2830efe836abSTetsuo Handa case 0: 2831efe836abSTetsuo Handa start = tomoyo_builtin_profile; 2832efe836abSTetsuo Handa head.type = TOMOYO_PROFILE; 2833efe836abSTetsuo Handa head.write = tomoyo_write_profile; 2834efe836abSTetsuo Handa break; 2835efe836abSTetsuo Handa case 1: 2836efe836abSTetsuo Handa start = tomoyo_builtin_exception_policy; 2837efe836abSTetsuo Handa head.type = TOMOYO_EXCEPTIONPOLICY; 2838efe836abSTetsuo Handa head.write = tomoyo_write_exception; 2839efe836abSTetsuo Handa break; 2840efe836abSTetsuo Handa case 2: 2841efe836abSTetsuo Handa start = tomoyo_builtin_domain_policy; 2842efe836abSTetsuo Handa head.type = TOMOYO_DOMAINPOLICY; 2843efe836abSTetsuo Handa head.write = tomoyo_write_domain; 2844efe836abSTetsuo Handa break; 2845efe836abSTetsuo Handa case 3: 2846efe836abSTetsuo Handa start = tomoyo_builtin_manager; 2847efe836abSTetsuo Handa head.type = TOMOYO_MANAGER; 2848efe836abSTetsuo Handa head.write = tomoyo_write_manager; 2849efe836abSTetsuo Handa break; 2850efe836abSTetsuo Handa case 4: 2851efe836abSTetsuo Handa start = tomoyo_builtin_stat; 2852efe836abSTetsuo Handa head.type = TOMOYO_STAT; 2853efe836abSTetsuo Handa head.write = tomoyo_write_stat; 2854efe836abSTetsuo Handa break; 2855efe836abSTetsuo Handa } 2856efe836abSTetsuo Handa while (1) { 2857efe836abSTetsuo Handa char *end = strchr(start, '\n'); 2858cdcf6723STetsuo Handa 2859efe836abSTetsuo Handa if (!end) 2860efe836abSTetsuo Handa break; 2861efe836abSTetsuo Handa *end = '\0'; 2862efe836abSTetsuo Handa tomoyo_normalize_line(start); 2863efe836abSTetsuo Handa head.write_buf = start; 2864efe836abSTetsuo Handa tomoyo_parse_policy(&head, start); 2865efe836abSTetsuo Handa start = end + 1; 2866efe836abSTetsuo Handa } 2867efe836abSTetsuo Handa } 2868efe836abSTetsuo Handa tomoyo_read_unlock(idx); 28690e4ae0e0STetsuo Handa #ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER 28700e4ae0e0STetsuo Handa tomoyo_check_profile(); 28710e4ae0e0STetsuo Handa #endif 2872efe836abSTetsuo Handa } 2873