18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * security/tomoyo/securityfs_if.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2011 NTT DATA CORPORATION 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/security.h> 98c2ecf20Sopenharmony_ci#include "common.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/** 128c2ecf20Sopenharmony_ci * tomoyo_check_task_acl - Check permission for task operation. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info". 158c2ecf20Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_acl_info". 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Returns true if granted, false otherwise. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistatic bool tomoyo_check_task_acl(struct tomoyo_request_info *r, 208c2ecf20Sopenharmony_ci const struct tomoyo_acl_info *ptr) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), 238c2ecf20Sopenharmony_ci head); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 328c2ecf20Sopenharmony_ci * @buf: Domainname to transit to. 338c2ecf20Sopenharmony_ci * @count: Size of @buf. 348c2ecf20Sopenharmony_ci * @ppos: Unused. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Returns @count on success, negative value otherwise. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * If domain transition was permitted but the domain transition failed, this 398c2ecf20Sopenharmony_ci * function returns error rather than terminating current thread with SIGKILL. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic ssize_t tomoyo_write_self(struct file *file, const char __user *buf, 428c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci char *data; 458c2ecf20Sopenharmony_ci int error; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) 488c2ecf20Sopenharmony_ci return -ENOMEM; 498c2ecf20Sopenharmony_ci data = memdup_user_nul(buf, count); 508c2ecf20Sopenharmony_ci if (IS_ERR(data)) 518c2ecf20Sopenharmony_ci return PTR_ERR(data); 528c2ecf20Sopenharmony_ci tomoyo_normalize_line(data); 538c2ecf20Sopenharmony_ci if (tomoyo_correct_domain(data)) { 548c2ecf20Sopenharmony_ci const int idx = tomoyo_read_lock(); 558c2ecf20Sopenharmony_ci struct tomoyo_path_info name; 568c2ecf20Sopenharmony_ci struct tomoyo_request_info r; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci name.name = data; 598c2ecf20Sopenharmony_ci tomoyo_fill_path_info(&name); 608c2ecf20Sopenharmony_ci /* Check "task manual_domain_transition" permission. */ 618c2ecf20Sopenharmony_ci tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 628c2ecf20Sopenharmony_ci r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL; 638c2ecf20Sopenharmony_ci r.param.task.domainname = &name; 648c2ecf20Sopenharmony_ci tomoyo_check_acl(&r, tomoyo_check_task_acl); 658c2ecf20Sopenharmony_ci if (!r.granted) 668c2ecf20Sopenharmony_ci error = -EPERM; 678c2ecf20Sopenharmony_ci else { 688c2ecf20Sopenharmony_ci struct tomoyo_domain_info *new_domain = 698c2ecf20Sopenharmony_ci tomoyo_assign_domain(data, true); 708c2ecf20Sopenharmony_ci if (!new_domain) { 718c2ecf20Sopenharmony_ci error = -ENOENT; 728c2ecf20Sopenharmony_ci } else { 738c2ecf20Sopenharmony_ci struct tomoyo_task *s = tomoyo_task(current); 748c2ecf20Sopenharmony_ci struct tomoyo_domain_info *old_domain = 758c2ecf20Sopenharmony_ci s->domain_info; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci s->domain_info = new_domain; 788c2ecf20Sopenharmony_ci atomic_inc(&new_domain->users); 798c2ecf20Sopenharmony_ci atomic_dec(&old_domain->users); 808c2ecf20Sopenharmony_ci error = 0; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci tomoyo_read_unlock(idx); 848c2ecf20Sopenharmony_ci } else 858c2ecf20Sopenharmony_ci error = -EINVAL; 868c2ecf20Sopenharmony_ci kfree(data); 878c2ecf20Sopenharmony_ci return error ? error : count; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/** 918c2ecf20Sopenharmony_ci * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 948c2ecf20Sopenharmony_ci * @buf: Domainname which current thread belongs to. 958c2ecf20Sopenharmony_ci * @count: Size of @buf. 968c2ecf20Sopenharmony_ci * @ppos: Bytes read by now. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * Returns read size on success, negative value otherwise. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_cistatic ssize_t tomoyo_read_self(struct file *file, char __user *buf, 1018c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci const char *domain = tomoyo_domain()->domainname->name; 1048c2ecf20Sopenharmony_ci loff_t len = strlen(domain); 1058c2ecf20Sopenharmony_ci loff_t pos = *ppos; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (pos >= len || !count) 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci len -= pos; 1108c2ecf20Sopenharmony_ci if (count < len) 1118c2ecf20Sopenharmony_ci len = count; 1128c2ecf20Sopenharmony_ci if (copy_to_user(buf, domain + pos, len)) 1138c2ecf20Sopenharmony_ci return -EFAULT; 1148c2ecf20Sopenharmony_ci *ppos += len; 1158c2ecf20Sopenharmony_ci return len; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */ 1198c2ecf20Sopenharmony_cistatic const struct file_operations tomoyo_self_operations = { 1208c2ecf20Sopenharmony_ci .write = tomoyo_write_self, 1218c2ecf20Sopenharmony_ci .read = tomoyo_read_self, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * @inode: Pointer to "struct inode". 1288c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Returns 0 on success, negative value otherwise. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cistatic int tomoyo_open(struct inode *inode, struct file *file) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci const int key = ((u8 *) file_inode(file)->i_private) 1358c2ecf20Sopenharmony_ci - ((u8 *) NULL); 1368c2ecf20Sopenharmony_ci return tomoyo_open_control(key, file); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/** 1408c2ecf20Sopenharmony_ci * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic int tomoyo_release(struct inode *inode, struct file *file) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci tomoyo_close_control(file->private_data); 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/** 1528c2ecf20Sopenharmony_ci * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 1558c2ecf20Sopenharmony_ci * @wait: Pointer to "poll_table". Maybe NULL. 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write, 1588c2ecf20Sopenharmony_ci * EPOLLOUT | EPOLLWRNORM otherwise. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic __poll_t tomoyo_poll(struct file *file, poll_table *wait) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return tomoyo_poll_control(file, wait); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 1698c2ecf20Sopenharmony_ci * @buf: Pointer to buffer. 1708c2ecf20Sopenharmony_ci * @count: Size of @buf. 1718c2ecf20Sopenharmony_ci * @ppos: Unused. 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * Returns bytes read on success, negative value otherwise. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, 1768c2ecf20Sopenharmony_ci loff_t *ppos) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return tomoyo_read_control(file->private_data, buf, count); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/** 1828c2ecf20Sopenharmony_ci * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci * @file: Pointer to "struct file". 1858c2ecf20Sopenharmony_ci * @buf: Pointer to buffer. 1868c2ecf20Sopenharmony_ci * @count: Size of @buf. 1878c2ecf20Sopenharmony_ci * @ppos: Unused. 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * Returns @count on success, negative value otherwise. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic ssize_t tomoyo_write(struct file *file, const char __user *buf, 1928c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci return tomoyo_write_control(file->private_data, buf, count); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* 1988c2ecf20Sopenharmony_ci * tomoyo_operations is a "struct file_operations" which is used for handling 1998c2ecf20Sopenharmony_ci * /sys/kernel/security/tomoyo/ interface. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). 2028c2ecf20Sopenharmony_ci * See tomoyo_io_buffer for internals. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic const struct file_operations tomoyo_operations = { 2058c2ecf20Sopenharmony_ci .open = tomoyo_open, 2068c2ecf20Sopenharmony_ci .release = tomoyo_release, 2078c2ecf20Sopenharmony_ci .poll = tomoyo_poll, 2088c2ecf20Sopenharmony_ci .read = tomoyo_read, 2098c2ecf20Sopenharmony_ci .write = tomoyo_write, 2108c2ecf20Sopenharmony_ci .llseek = noop_llseek, 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/** 2148c2ecf20Sopenharmony_ci * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * @name: The name of the interface file. 2178c2ecf20Sopenharmony_ci * @mode: The permission of the interface file. 2188c2ecf20Sopenharmony_ci * @parent: The parent directory. 2198c2ecf20Sopenharmony_ci * @key: Type of interface. 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Returns nothing. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_cistatic void __init tomoyo_create_entry(const char *name, const umode_t mode, 2248c2ecf20Sopenharmony_ci struct dentry *parent, const u8 key) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key, 2278c2ecf20Sopenharmony_ci &tomoyo_operations); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * Returns 0. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_cistatic int __init tomoyo_initerface_init(void) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct tomoyo_domain_info *domain; 2388c2ecf20Sopenharmony_ci struct dentry *tomoyo_dir; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!tomoyo_enabled) 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci domain = tomoyo_domain(); 2438c2ecf20Sopenharmony_ci /* Don't create securityfs entries unless registered. */ 2448c2ecf20Sopenharmony_ci if (domain != &tomoyo_kernel_domain) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci tomoyo_dir = securityfs_create_dir("tomoyo", NULL); 2488c2ecf20Sopenharmony_ci tomoyo_create_entry("query", 0600, tomoyo_dir, 2498c2ecf20Sopenharmony_ci TOMOYO_QUERY); 2508c2ecf20Sopenharmony_ci tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, 2518c2ecf20Sopenharmony_ci TOMOYO_DOMAINPOLICY); 2528c2ecf20Sopenharmony_ci tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, 2538c2ecf20Sopenharmony_ci TOMOYO_EXCEPTIONPOLICY); 2548c2ecf20Sopenharmony_ci tomoyo_create_entry("audit", 0400, tomoyo_dir, 2558c2ecf20Sopenharmony_ci TOMOYO_AUDIT); 2568c2ecf20Sopenharmony_ci tomoyo_create_entry(".process_status", 0600, tomoyo_dir, 2578c2ecf20Sopenharmony_ci TOMOYO_PROCESS_STATUS); 2588c2ecf20Sopenharmony_ci tomoyo_create_entry("stat", 0644, tomoyo_dir, 2598c2ecf20Sopenharmony_ci TOMOYO_STAT); 2608c2ecf20Sopenharmony_ci tomoyo_create_entry("profile", 0600, tomoyo_dir, 2618c2ecf20Sopenharmony_ci TOMOYO_PROFILE); 2628c2ecf20Sopenharmony_ci tomoyo_create_entry("manager", 0600, tomoyo_dir, 2638c2ecf20Sopenharmony_ci TOMOYO_MANAGER); 2648c2ecf20Sopenharmony_ci tomoyo_create_entry("version", 0400, tomoyo_dir, 2658c2ecf20Sopenharmony_ci TOMOYO_VERSION); 2668c2ecf20Sopenharmony_ci securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, 2678c2ecf20Sopenharmony_ci &tomoyo_self_operations); 2688c2ecf20Sopenharmony_ci tomoyo_load_builtin_policy(); 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cifs_initcall(tomoyo_initerface_init); 273