162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * security/tomoyo/securityfs_if.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005-2011 NTT DATA CORPORATION 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/security.h> 962306a36Sopenharmony_ci#include "common.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/** 1262306a36Sopenharmony_ci * tomoyo_check_task_acl - Check permission for task operation. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * @r: Pointer to "struct tomoyo_request_info". 1562306a36Sopenharmony_ci * @ptr: Pointer to "struct tomoyo_acl_info". 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Returns true if granted, false otherwise. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_cistatic bool tomoyo_check_task_acl(struct tomoyo_request_info *r, 2062306a36Sopenharmony_ci const struct tomoyo_acl_info *ptr) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), 2362306a36Sopenharmony_ci head); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname); 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * @file: Pointer to "struct file". 3262306a36Sopenharmony_ci * @buf: Domainname to transit to. 3362306a36Sopenharmony_ci * @count: Size of @buf. 3462306a36Sopenharmony_ci * @ppos: Unused. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Returns @count on success, negative value otherwise. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * If domain transition was permitted but the domain transition failed, this 3962306a36Sopenharmony_ci * function returns error rather than terminating current thread with SIGKILL. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_cistatic ssize_t tomoyo_write_self(struct file *file, const char __user *buf, 4262306a36Sopenharmony_ci size_t count, loff_t *ppos) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci char *data; 4562306a36Sopenharmony_ci int error; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) 4862306a36Sopenharmony_ci return -ENOMEM; 4962306a36Sopenharmony_ci data = memdup_user_nul(buf, count); 5062306a36Sopenharmony_ci if (IS_ERR(data)) 5162306a36Sopenharmony_ci return PTR_ERR(data); 5262306a36Sopenharmony_ci tomoyo_normalize_line(data); 5362306a36Sopenharmony_ci if (tomoyo_correct_domain(data)) { 5462306a36Sopenharmony_ci const int idx = tomoyo_read_lock(); 5562306a36Sopenharmony_ci struct tomoyo_path_info name; 5662306a36Sopenharmony_ci struct tomoyo_request_info r; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci name.name = data; 5962306a36Sopenharmony_ci tomoyo_fill_path_info(&name); 6062306a36Sopenharmony_ci /* Check "task manual_domain_transition" permission. */ 6162306a36Sopenharmony_ci tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 6262306a36Sopenharmony_ci r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL; 6362306a36Sopenharmony_ci r.param.task.domainname = &name; 6462306a36Sopenharmony_ci tomoyo_check_acl(&r, tomoyo_check_task_acl); 6562306a36Sopenharmony_ci if (!r.granted) 6662306a36Sopenharmony_ci error = -EPERM; 6762306a36Sopenharmony_ci else { 6862306a36Sopenharmony_ci struct tomoyo_domain_info *new_domain = 6962306a36Sopenharmony_ci tomoyo_assign_domain(data, true); 7062306a36Sopenharmony_ci if (!new_domain) { 7162306a36Sopenharmony_ci error = -ENOENT; 7262306a36Sopenharmony_ci } else { 7362306a36Sopenharmony_ci struct tomoyo_task *s = tomoyo_task(current); 7462306a36Sopenharmony_ci struct tomoyo_domain_info *old_domain = 7562306a36Sopenharmony_ci s->domain_info; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci s->domain_info = new_domain; 7862306a36Sopenharmony_ci atomic_inc(&new_domain->users); 7962306a36Sopenharmony_ci atomic_dec(&old_domain->users); 8062306a36Sopenharmony_ci error = 0; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci tomoyo_read_unlock(idx); 8462306a36Sopenharmony_ci } else 8562306a36Sopenharmony_ci error = -EINVAL; 8662306a36Sopenharmony_ci kfree(data); 8762306a36Sopenharmony_ci return error ? error : count; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/** 9162306a36Sopenharmony_ci * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * @file: Pointer to "struct file". 9462306a36Sopenharmony_ci * @buf: Domainname which current thread belongs to. 9562306a36Sopenharmony_ci * @count: Size of @buf. 9662306a36Sopenharmony_ci * @ppos: Bytes read by now. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * Returns read size on success, negative value otherwise. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic ssize_t tomoyo_read_self(struct file *file, char __user *buf, 10162306a36Sopenharmony_ci size_t count, loff_t *ppos) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci const char *domain = tomoyo_domain()->domainname->name; 10462306a36Sopenharmony_ci loff_t len = strlen(domain); 10562306a36Sopenharmony_ci loff_t pos = *ppos; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (pos >= len || !count) 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci len -= pos; 11062306a36Sopenharmony_ci if (count < len) 11162306a36Sopenharmony_ci len = count; 11262306a36Sopenharmony_ci if (copy_to_user(buf, domain + pos, len)) 11362306a36Sopenharmony_ci return -EFAULT; 11462306a36Sopenharmony_ci *ppos += len; 11562306a36Sopenharmony_ci return len; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */ 11962306a36Sopenharmony_cistatic const struct file_operations tomoyo_self_operations = { 12062306a36Sopenharmony_ci .write = tomoyo_write_self, 12162306a36Sopenharmony_ci .read = tomoyo_read_self, 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * @inode: Pointer to "struct inode". 12862306a36Sopenharmony_ci * @file: Pointer to "struct file". 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * Returns 0 on success, negative value otherwise. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_cistatic int tomoyo_open(struct inode *inode, struct file *file) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci const u8 key = (uintptr_t) file_inode(file)->i_private; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return tomoyo_open_control(key, file); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * @inode: Pointer to "struct inode". 14362306a36Sopenharmony_ci * @file: Pointer to "struct file". 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic int tomoyo_release(struct inode *inode, struct file *file) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci tomoyo_close_control(file->private_data); 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/** 15362306a36Sopenharmony_ci * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * @file: Pointer to "struct file". 15662306a36Sopenharmony_ci * @wait: Pointer to "poll_table". Maybe NULL. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write, 15962306a36Sopenharmony_ci * EPOLLOUT | EPOLLWRNORM otherwise. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_cistatic __poll_t tomoyo_poll(struct file *file, poll_table *wait) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci return tomoyo_poll_control(file, wait); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/** 16762306a36Sopenharmony_ci * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * @file: Pointer to "struct file". 17062306a36Sopenharmony_ci * @buf: Pointer to buffer. 17162306a36Sopenharmony_ci * @count: Size of @buf. 17262306a36Sopenharmony_ci * @ppos: Unused. 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * Returns bytes read on success, negative value otherwise. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistatic ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, 17762306a36Sopenharmony_ci loff_t *ppos) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci return tomoyo_read_control(file->private_data, buf, count); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * @file: Pointer to "struct file". 18662306a36Sopenharmony_ci * @buf: Pointer to buffer. 18762306a36Sopenharmony_ci * @count: Size of @buf. 18862306a36Sopenharmony_ci * @ppos: Unused. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * Returns @count on success, negative value otherwise. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cistatic ssize_t tomoyo_write(struct file *file, const char __user *buf, 19362306a36Sopenharmony_ci size_t count, loff_t *ppos) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci return tomoyo_write_control(file->private_data, buf, count); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* 19962306a36Sopenharmony_ci * tomoyo_operations is a "struct file_operations" which is used for handling 20062306a36Sopenharmony_ci * /sys/kernel/security/tomoyo/ interface. 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). 20362306a36Sopenharmony_ci * See tomoyo_io_buffer for internals. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cistatic const struct file_operations tomoyo_operations = { 20662306a36Sopenharmony_ci .open = tomoyo_open, 20762306a36Sopenharmony_ci .release = tomoyo_release, 20862306a36Sopenharmony_ci .poll = tomoyo_poll, 20962306a36Sopenharmony_ci .read = tomoyo_read, 21062306a36Sopenharmony_ci .write = tomoyo_write, 21162306a36Sopenharmony_ci .llseek = noop_llseek, 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * @name: The name of the interface file. 21862306a36Sopenharmony_ci * @mode: The permission of the interface file. 21962306a36Sopenharmony_ci * @parent: The parent directory. 22062306a36Sopenharmony_ci * @key: Type of interface. 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * Returns nothing. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic void __init tomoyo_create_entry(const char *name, const umode_t mode, 22562306a36Sopenharmony_ci struct dentry *parent, const u8 key) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci securityfs_create_file(name, mode, parent, (void *) (uintptr_t) key, 22862306a36Sopenharmony_ci &tomoyo_operations); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/** 23262306a36Sopenharmony_ci * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * Returns 0. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_cistatic int __init tomoyo_initerface_init(void) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct tomoyo_domain_info *domain; 23962306a36Sopenharmony_ci struct dentry *tomoyo_dir; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (!tomoyo_enabled) 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci domain = tomoyo_domain(); 24462306a36Sopenharmony_ci /* Don't create securityfs entries unless registered. */ 24562306a36Sopenharmony_ci if (domain != &tomoyo_kernel_domain) 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci tomoyo_dir = securityfs_create_dir("tomoyo", NULL); 24962306a36Sopenharmony_ci tomoyo_create_entry("query", 0600, tomoyo_dir, 25062306a36Sopenharmony_ci TOMOYO_QUERY); 25162306a36Sopenharmony_ci tomoyo_create_entry("domain_policy", 0600, tomoyo_dir, 25262306a36Sopenharmony_ci TOMOYO_DOMAINPOLICY); 25362306a36Sopenharmony_ci tomoyo_create_entry("exception_policy", 0600, tomoyo_dir, 25462306a36Sopenharmony_ci TOMOYO_EXCEPTIONPOLICY); 25562306a36Sopenharmony_ci tomoyo_create_entry("audit", 0400, tomoyo_dir, 25662306a36Sopenharmony_ci TOMOYO_AUDIT); 25762306a36Sopenharmony_ci tomoyo_create_entry(".process_status", 0600, tomoyo_dir, 25862306a36Sopenharmony_ci TOMOYO_PROCESS_STATUS); 25962306a36Sopenharmony_ci tomoyo_create_entry("stat", 0644, tomoyo_dir, 26062306a36Sopenharmony_ci TOMOYO_STAT); 26162306a36Sopenharmony_ci tomoyo_create_entry("profile", 0600, tomoyo_dir, 26262306a36Sopenharmony_ci TOMOYO_PROFILE); 26362306a36Sopenharmony_ci tomoyo_create_entry("manager", 0600, tomoyo_dir, 26462306a36Sopenharmony_ci TOMOYO_MANAGER); 26562306a36Sopenharmony_ci tomoyo_create_entry("version", 0400, tomoyo_dir, 26662306a36Sopenharmony_ci TOMOYO_VERSION); 26762306a36Sopenharmony_ci securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL, 26862306a36Sopenharmony_ci &tomoyo_self_operations); 26962306a36Sopenharmony_ci tomoyo_load_builtin_policy(); 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cifs_initcall(tomoyo_initerface_init); 274