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