securityfs_if.c 7.36 KB
Newer Older
1
/*
Tetsuo Handa's avatar
Tetsuo Handa committed
2
 * security/tomoyo/securityfs_if.c
3
 *
Tetsuo Handa's avatar
Tetsuo Handa committed
4
 * Copyright (C) 2005-2011  NTT DATA CORPORATION
5
6
7
8
9
 */

#include <linux/security.h>
#include "common.h"

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
 * tomoyo_check_task_acl - Check permission for task operation.
 *
 * @r:   Pointer to "struct tomoyo_request_info".
 * @ptr: Pointer to "struct tomoyo_acl_info".
 *
 * Returns true if granted, false otherwise.
 */
static bool tomoyo_check_task_acl(struct tomoyo_request_info *r,
				  const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl),
							 head);
	return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname);
}

/**
 * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface.
 *
 * @file:  Pointer to "struct file".
 * @buf:   Domainname to transit to.
 * @count: Size of @buf.
 * @ppos:  Unused.
 *
 * Returns @count on success, negative value otherwise.
 *
 * If domain transition was permitted but the domain transition failed, this
 * function returns error rather than terminating current thread with SIGKILL.
 */
static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
			      size_t count, loff_t *ppos)
{
	char *data;
	int error;
	if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
		return -ENOMEM;
	data = kzalloc(count + 1, GFP_NOFS);
	if (!data)
		return -ENOMEM;
	if (copy_from_user(data, buf, count)) {
		error = -EFAULT;
		goto out;
	}
	tomoyo_normalize_line(data);
	if (tomoyo_correct_domain(data)) {
		const int idx = tomoyo_read_lock();
		struct tomoyo_path_info name;
		struct tomoyo_request_info r;
		name.name = data;
		tomoyo_fill_path_info(&name);
		/* Check "task manual_domain_transition" permission. */
		tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
		r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL;
		r.param.task.domainname = &name;
		tomoyo_check_acl(&r, tomoyo_check_task_acl);
		if (!r.granted)
			error = -EPERM;
		else {
			struct tomoyo_domain_info *new_domain =
				tomoyo_assign_domain(data, true);
			if (!new_domain) {
				error = -ENOENT;
			} else {
				struct cred *cred = prepare_creds();
				if (!cred) {
					error = -ENOMEM;
				} else {
					struct tomoyo_domain_info *old_domain =
						cred->security;
					cred->security = new_domain;
					atomic_inc(&new_domain->users);
					atomic_dec(&old_domain->users);
					commit_creds(cred);
					error = 0;
				}
			}
		}
		tomoyo_read_unlock(idx);
	} else
		error = -EINVAL;
out:
	kfree(data);
	return error ? error : count;
}

/**
 * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface.
 *
 * @file:  Pointer to "struct file".
 * @buf:   Domainname which current thread belongs to.
 * @count: Size of @buf.
 * @ppos:  Bytes read by now.
 *
 * Returns read size on success, negative value otherwise.
 */
static ssize_t tomoyo_read_self(struct file *file, char __user *buf,
				size_t count, loff_t *ppos)
{
	const char *domain = tomoyo_domain()->domainname->name;
	loff_t len = strlen(domain);
	loff_t pos = *ppos;
	if (pos >= len || !count)
		return 0;
	len -= pos;
	if (count < len)
		len = count;
	if (copy_to_user(buf, domain + pos, len))
		return -EFAULT;
	*ppos += len;
	return len;
}

/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */
static const struct file_operations tomoyo_self_operations = {
	.write = tomoyo_write_self,
	.read  = tomoyo_read_self,
};

128
129
130
131
132
133
134
135
136
137
/**
 * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
 *
 * @inode: Pointer to "struct inode".
 * @file:  Pointer to "struct file".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_open(struct inode *inode, struct file *file)
{
Al Viro's avatar
Al Viro committed
138
	const int key = ((u8 *) file_inode(file)->i_private)
139
140
141
142
143
144
145
146
147
148
149
150
		- ((u8 *) NULL);
	return tomoyo_open_control(key, file);
}

/**
 * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
 *
 * @file:  Pointer to "struct file".
 *
 */
static int tomoyo_release(struct inode *inode, struct file *file)
{
151
152
	tomoyo_close_control(file->private_data);
	return 0;
153
154
}

155
/**
Tetsuo Handa's avatar
Tetsuo Handa committed
156
 * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface.
157
158
 *
 * @file: Pointer to "struct file".
159
 * @wait: Pointer to "poll_table". Maybe NULL.
160
 *
161
162
 * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write,
 * POLLOUT | POLLWRNORM otherwise.
163
164
165
166
167
168
 */
static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
{
	return tomoyo_poll_control(file, wait);
}

169
170
171
172
173
174
175
176
177
178
179
180
181
/**
 * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
 *
 * @file:  Pointer to "struct file".
 * @buf:   Pointer to buffer.
 * @count: Size of @buf.
 * @ppos:  Unused.
 *
 * Returns bytes read on success, negative value otherwise.
 */
static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
			   loff_t *ppos)
{
Tetsuo Handa's avatar
Tetsuo Handa committed
182
	return tomoyo_read_control(file->private_data, buf, count);
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
}

/**
 * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
 *
 * @file:  Pointer to "struct file".
 * @buf:   Pointer to buffer.
 * @count: Size of @buf.
 * @ppos:  Unused.
 *
 * Returns @count on success, negative value otherwise.
 */
static ssize_t tomoyo_write(struct file *file, const char __user *buf,
			    size_t count, loff_t *ppos)
{
Tetsuo Handa's avatar
Tetsuo Handa committed
198
	return tomoyo_write_control(file->private_data, buf, count);
199
200
201
202
203
204
205
206
207
208
209
210
}

/*
 * tomoyo_operations is a "struct file_operations" which is used for handling
 * /sys/kernel/security/tomoyo/ interface.
 *
 * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
 * See tomoyo_io_buffer for internals.
 */
static const struct file_operations tomoyo_operations = {
	.open    = tomoyo_open,
	.release = tomoyo_release,
211
	.poll    = tomoyo_poll,
212
213
	.read    = tomoyo_read,
	.write   = tomoyo_write,
214
	.llseek  = noop_llseek,
215
216
217
218
219
220
221
222
223
224
225
226
};

/**
 * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
 *
 * @name:   The name of the interface file.
 * @mode:   The permission of the interface file.
 * @parent: The parent directory.
 * @key:    Type of interface.
 *
 * Returns nothing.
 */
227
static void __init tomoyo_create_entry(const char *name, const umode_t mode,
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
				       struct dentry *parent, const u8 key)
{
	securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
			       &tomoyo_operations);
}

/**
 * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
 *
 * Returns 0.
 */
static int __init tomoyo_initerface_init(void)
{
	struct dentry *tomoyo_dir;

	/* Don't create securityfs entries unless registered. */
	if (current_cred()->security != &tomoyo_kernel_domain)
		return 0;

	tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
	tomoyo_create_entry("query",            0600, tomoyo_dir,
			    TOMOYO_QUERY);
	tomoyo_create_entry("domain_policy",    0600, tomoyo_dir,
			    TOMOYO_DOMAINPOLICY);
	tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
			    TOMOYO_EXCEPTIONPOLICY);
Tetsuo Handa's avatar
Tetsuo Handa committed
254
255
	tomoyo_create_entry("audit",            0400, tomoyo_dir,
			    TOMOYO_AUDIT);
256
257
	tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
			    TOMOYO_PROCESS_STATUS);
258
259
	tomoyo_create_entry("stat",             0644, tomoyo_dir,
			    TOMOYO_STAT);
260
261
262
263
264
265
	tomoyo_create_entry("profile",          0600, tomoyo_dir,
			    TOMOYO_PROFILE);
	tomoyo_create_entry("manager",          0600, tomoyo_dir,
			    TOMOYO_MANAGER);
	tomoyo_create_entry("version",          0400, tomoyo_dir,
			    TOMOYO_VERSION);
266
267
	securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL,
			       &tomoyo_self_operations);
268
	tomoyo_load_builtin_policy();
269
270
271
272
	return 0;
}

fs_initcall(tomoyo_initerface_init);