blob: 131816878e503731ca5ac16282df2770b94772bf [file] [log] [blame]
Thomas Gleixnera10e7632019-05-31 01:09:32 -07001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/* Updated: Karl MacMillan <kmacmillan@tresys.com>
3 *
Eric Paris18729812008-04-17 14:15:45 -04004 * Added conditional policy language extensions
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Paul Moore82c21bf2011-08-01 11:10:33 +00006 * Updated: Hewlett-Packard <paul@paul-moore.com>
Paul Moore3bb56b22008-01-29 08:38:19 -05007 *
Eric Paris18729812008-04-17 14:15:45 -04008 * Added support for the policy capability bitmap
Paul Moore3bb56b22008-01-29 08:38:19 -05009 *
10 * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
12 * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/pagemap.h>
17#include <linux/slab.h>
18#include <linux/vmalloc.h>
19#include <linux/fs.h>
David Howells920f50b2019-03-25 16:38:30 +000020#include <linux/fs_context.h>
Stephen Smalley0619f0f2018-03-20 11:59:11 -040021#include <linux/mount.h>
Ingo Molnarbb0030792006-03-22 00:09:14 -080022#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/init.h>
24#include <linux/string.h>
25#include <linux/security.h>
26#include <linux/major.h>
27#include <linux/seq_file.h>
28#include <linux/percpu.h>
Steve Grubbaf601e42006-01-04 14:08:39 +000029#include <linux/audit.h>
Eric Parisf5269712008-05-14 11:27:45 -040030#include <linux/uaccess.h>
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -070031#include <linux/kobject.h>
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -040032#include <linux/ctype.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34/* selinuxfs pseudo filesystem for exporting the security policy API.
35 Based on the proc code and the fs/nfsd/nfsctl.c code. */
36
37#include "flask.h"
38#include "avc.h"
39#include "avc_ss.h"
40#include "security.h"
41#include "objsec.h"
42#include "conditional.h"
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044enum sel_inos {
45 SEL_ROOT_INO = 2,
46 SEL_LOAD, /* load policy */
47 SEL_ENFORCE, /* get or set enforcing status */
48 SEL_CONTEXT, /* validate context */
49 SEL_ACCESS, /* compute access decision */
50 SEL_CREATE, /* compute create labeling decision */
51 SEL_RELABEL, /* compute relabeling decision */
52 SEL_USER, /* compute reachable user contexts */
53 SEL_POLICYVERS, /* return policy version for this kernel */
54 SEL_COMMIT_BOOLS, /* commit new boolean values */
55 SEL_MLS, /* return if MLS policy is enabled */
56 SEL_DISABLE, /* disable SELinux until next reboot */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 SEL_MEMBER, /* compute polyinstantiation membership decision */
58 SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
James Morris4e5ab4c2006-06-09 00:33:33 -070059 SEL_COMPAT_NET, /* whether to use old compat network packet controls */
Eric Paris3f120702007-09-21 14:37:10 -040060 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
61 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
KaiGai Kohei11904162010-09-14 18:28:39 +090062 SEL_STATUS, /* export current status using mmap() */
Eric Pariscee74f42010-10-13 17:50:25 -040063 SEL_POLICY, /* allow userspace to read the in kernel policy */
Andrew Perepechkof9df6452015-12-24 11:09:41 -050064 SEL_VALIDATE_TRANS, /* compute validatetrans decision */
James Carter6174eaf2007-04-04 16:18:39 -040065 SEL_INO_NEXT, /* The next inode number to use */
Linus Torvalds1da177e2005-04-16 15:20:36 -070066};
67
Stephen Smalley0619f0f2018-03-20 11:59:11 -040068struct selinux_fs_info {
69 struct dentry *bool_dir;
70 unsigned int bool_num;
71 char **bool_pending_names;
72 unsigned int *bool_pending_values;
73 struct dentry *class_dir;
74 unsigned long last_class_ino;
75 bool policy_opened;
76 struct dentry *policycap_dir;
77 struct mutex mutex;
78 unsigned long last_ino;
79 struct selinux_state *state;
80 struct super_block *sb;
81};
82
83static int selinux_fs_info_create(struct super_block *sb)
84{
85 struct selinux_fs_info *fsi;
86
87 fsi = kzalloc(sizeof(*fsi), GFP_KERNEL);
88 if (!fsi)
89 return -ENOMEM;
90
91 mutex_init(&fsi->mutex);
92 fsi->last_ino = SEL_INO_NEXT - 1;
93 fsi->state = &selinux_state;
94 fsi->sb = sb;
95 sb->s_fs_info = fsi;
96 return 0;
97}
98
99static void selinux_fs_info_free(struct super_block *sb)
100{
101 struct selinux_fs_info *fsi = sb->s_fs_info;
102 int i;
103
104 if (fsi) {
105 for (i = 0; i < fsi->bool_num; i++)
106 kfree(fsi->bool_pending_names[i]);
107 kfree(fsi->bool_pending_names);
108 kfree(fsi->bool_pending_values);
109 }
110 kfree(sb->s_fs_info);
111 sb->s_fs_info = NULL;
112}
James Carter6174eaf2007-04-04 16:18:39 -0400113
Paul Moore3bb56b22008-01-29 08:38:19 -0500114#define SEL_INITCON_INO_OFFSET 0x01000000
115#define SEL_BOOL_INO_OFFSET 0x02000000
116#define SEL_CLASS_INO_OFFSET 0x04000000
117#define SEL_POLICYCAP_INO_OFFSET 0x08000000
118#define SEL_INO_MASK 0x00ffffff
James Carterf0ee2e42007-04-04 10:11:29 -0400119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define TMPBUFLEN 12
121static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
122 size_t count, loff_t *ppos)
123{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400124 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 char tmpbuf[TMPBUFLEN];
126 ssize_t length;
127
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500128 length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400129 enforcing_enabled(fsi->state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
131}
132
133#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris18729812008-04-17 14:15:45 -0400134static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 size_t count, loff_t *ppos)
136
137{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400138 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
139 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -0500140 char *page = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 ssize_t length;
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500142 int old_value, new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Davi Arnautbfd51622005-10-30 14:59:24 -0800144 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -0500145 return -ENOMEM;
Eric Parisb77a4932010-11-23 11:40:08 -0500146
147 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -0500148 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -0500149 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -0500150
Al Viro8365a712015-12-24 00:08:06 -0500151 page = memdup_user_nul(buf, count);
152 if (IS_ERR(page))
153 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155 length = -EINVAL;
156 if (sscanf(page, "%d", &new_value) != 1)
157 goto out;
158
Stephen Smalleyea49d10ee2016-11-18 09:30:38 -0500159 new_value = !!new_value;
160
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400161 old_value = enforcing_enabled(state);
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500162 if (new_value != old_value) {
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500163 length = avc_has_perm(&selinux_state,
164 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500165 SECCLASS_SECURITY, SECURITY__SETENFORCE,
166 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 if (length)
168 goto out;
Richard Guy Briggscdfb6b32018-05-12 21:58:20 -0400169 audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
Richard Guy Briggs4195ed42018-04-09 19:34:22 -0400170 "enforcing=%d old_enforcing=%d auid=%u ses=%u"
Stephen Smalley6c5a6822019-12-17 09:15:10 -0500171 " enabled=1 old-enabled=1 lsm=selinux res=1",
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500172 new_value, old_value,
Eric W. Biederman581abc02012-08-20 00:09:36 -0700173 from_kuid(&init_user_ns, audit_get_loginuid(current)),
Stephen Smalley6c5a6822019-12-17 09:15:10 -0500174 audit_get_sessionid(current));
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400175 enforcing_set(state, new_value);
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500176 if (new_value)
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500177 avc_ss_reset(state->avc, 0);
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500178 selnl_notify_setenforce(new_value);
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400179 selinux_status_update_setenforce(state, new_value);
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500180 if (!new_value)
Janne Karhunen42df7442019-06-14 15:20:14 +0300181 call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183 length = count;
184out:
Al Viro8365a712015-12-24 00:08:06 -0500185 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 return length;
187}
188#else
189#define sel_write_enforce NULL
190#endif
191
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800192static const struct file_operations sel_enforce_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 .read = sel_read_enforce,
194 .write = sel_write_enforce,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200195 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196};
197
Eric Paris3f120702007-09-21 14:37:10 -0400198static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
199 size_t count, loff_t *ppos)
200{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400201 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
202 struct selinux_state *state = fsi->state;
Eric Paris3f120702007-09-21 14:37:10 -0400203 char tmpbuf[TMPBUFLEN];
204 ssize_t length;
Al Viro496ad9a2013-01-23 17:07:38 -0500205 ino_t ino = file_inode(filp)->i_ino;
Eric Paris3f120702007-09-21 14:37:10 -0400206 int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400207 security_get_reject_unknown(state) :
208 !security_get_allow_unknown(state);
Eric Paris3f120702007-09-21 14:37:10 -0400209
210 length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
211 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
212}
213
214static const struct file_operations sel_handle_unknown_ops = {
215 .read = sel_read_handle_unknown,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200216 .llseek = generic_file_llseek,
Eric Paris3f120702007-09-21 14:37:10 -0400217};
218
KaiGai Kohei11904162010-09-14 18:28:39 +0900219static int sel_open_handle_status(struct inode *inode, struct file *filp)
220{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400221 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
222 struct page *status = selinux_kernel_status_page(fsi->state);
KaiGai Kohei11904162010-09-14 18:28:39 +0900223
224 if (!status)
225 return -ENOMEM;
226
227 filp->private_data = status;
228
229 return 0;
230}
231
232static ssize_t sel_read_handle_status(struct file *filp, char __user *buf,
233 size_t count, loff_t *ppos)
234{
235 struct page *status = filp->private_data;
236
237 BUG_ON(!status);
238
239 return simple_read_from_buffer(buf, count, ppos,
240 page_address(status),
241 sizeof(struct selinux_kernel_status));
242}
243
244static int sel_mmap_handle_status(struct file *filp,
245 struct vm_area_struct *vma)
246{
247 struct page *status = filp->private_data;
248 unsigned long size = vma->vm_end - vma->vm_start;
249
250 BUG_ON(!status);
251
252 /* only allows one page from the head */
253 if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
254 return -EIO;
255 /* disallow writable mapping */
256 if (vma->vm_flags & VM_WRITE)
257 return -EPERM;
258 /* disallow mprotect() turns it into writable */
259 vma->vm_flags &= ~VM_MAYWRITE;
260
261 return remap_pfn_range(vma, vma->vm_start,
262 page_to_pfn(status),
263 size, vma->vm_page_prot);
264}
265
266static const struct file_operations sel_handle_status_ops = {
267 .open = sel_open_handle_status,
268 .read = sel_read_handle_status,
269 .mmap = sel_mmap_handle_status,
270 .llseek = generic_file_llseek,
271};
272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris18729812008-04-17 14:15:45 -0400274static ssize_t sel_write_disable(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 size_t count, loff_t *ppos)
276
277{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400278 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
Al Viro8365a712015-12-24 00:08:06 -0500279 char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 ssize_t length;
281 int new_value;
Richard Guy Briggs4195ed42018-04-09 19:34:22 -0400282 int enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Paul Moore89b223b2019-12-18 21:45:08 -0500284 /* NOTE: we are now officially considering runtime disable as
285 * deprecated, and using it will become increasingly painful
286 * (e.g. sleeping/blocking) as we progress through future
287 * kernel releases until eventually it is removed
288 */
289 pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n");
290
Davi Arnautbfd51622005-10-30 14:59:24 -0800291 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -0500292 return -ENOMEM;
Eric Parisb77a4932010-11-23 11:40:08 -0500293
294 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -0500295 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -0500296 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -0500297
Al Viro8365a712015-12-24 00:08:06 -0500298 page = memdup_user_nul(buf, count);
299 if (IS_ERR(page))
300 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302 length = -EINVAL;
303 if (sscanf(page, "%d", &new_value) != 1)
304 goto out;
305
306 if (new_value) {
Richard Guy Briggs4195ed42018-04-09 19:34:22 -0400307 enforcing = enforcing_enabled(fsi->state);
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400308 length = selinux_disable(fsi->state);
Eric Parisb77a4932010-11-23 11:40:08 -0500309 if (length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 goto out;
Richard Guy Briggscdfb6b32018-05-12 21:58:20 -0400311 audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
Richard Guy Briggs4195ed42018-04-09 19:34:22 -0400312 "enforcing=%d old_enforcing=%d auid=%u ses=%u"
Stephen Smalley6c5a6822019-12-17 09:15:10 -0500313 " enabled=0 old-enabled=1 lsm=selinux res=1",
Richard Guy Briggs4195ed42018-04-09 19:34:22 -0400314 enforcing, enforcing,
Eric W. Biederman581abc02012-08-20 00:09:36 -0700315 from_kuid(&init_user_ns, audit_get_loginuid(current)),
Stephen Smalley6c5a6822019-12-17 09:15:10 -0500316 audit_get_sessionid(current));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 }
318
319 length = count;
320out:
Al Viro8365a712015-12-24 00:08:06 -0500321 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 return length;
323}
324#else
325#define sel_write_disable NULL
326#endif
327
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800328static const struct file_operations sel_disable_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 .write = sel_write_disable,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200330 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331};
332
333static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
Eric Paris18729812008-04-17 14:15:45 -0400334 size_t count, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 char tmpbuf[TMPBUFLEN];
337 ssize_t length;
338
339 length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);
340 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
341}
342
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800343static const struct file_operations sel_policyvers_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 .read = sel_read_policyvers,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200345 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346};
347
348/* declaration for sel_write_load */
Stephen Smalley02a52c52020-08-07 09:29:34 -0400349static int sel_make_bools(struct selinux_fs_info *fsi,
350 struct selinux_policy *newpolicy);
351static int sel_make_classes(struct selinux_fs_info *fsi,
352 struct selinux_policy *newpolicy);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400353
354/* declaration for sel_make_class_dirs */
Al Viroa1c2aa12012-03-18 20:36:59 -0400355static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400356 unsigned long *ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358static ssize_t sel_read_mls(struct file *filp, char __user *buf,
359 size_t count, loff_t *ppos)
360{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400361 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 char tmpbuf[TMPBUFLEN];
363 ssize_t length;
364
Guido Trentalancia0719aaf2010-02-03 16:40:20 +0100365 length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400366 security_mls_enabled(fsi->state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
368}
369
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800370static const struct file_operations sel_mls_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 .read = sel_read_mls,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200372 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373};
374
Eric Pariscee74f42010-10-13 17:50:25 -0400375struct policy_load_memory {
376 size_t len;
377 void *data;
378};
379
380static int sel_open_policy(struct inode *inode, struct file *filp)
381{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400382 struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
383 struct selinux_state *state = fsi->state;
Eric Pariscee74f42010-10-13 17:50:25 -0400384 struct policy_load_memory *plm = NULL;
385 int rc;
386
387 BUG_ON(filp->private_data);
388
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400389 mutex_lock(&fsi->mutex);
Eric Pariscee74f42010-10-13 17:50:25 -0400390
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500391 rc = avc_has_perm(&selinux_state,
392 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500393 SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
Eric Pariscee74f42010-10-13 17:50:25 -0400394 if (rc)
395 goto err;
396
397 rc = -EBUSY;
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400398 if (fsi->policy_opened)
Eric Pariscee74f42010-10-13 17:50:25 -0400399 goto err;
400
401 rc = -ENOMEM;
402 plm = kzalloc(sizeof(*plm), GFP_KERNEL);
403 if (!plm)
404 goto err;
405
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400406 if (i_size_read(inode) != security_policydb_len(state)) {
Al Viro59551022016-01-22 15:40:57 -0500407 inode_lock(inode);
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400408 i_size_write(inode, security_policydb_len(state));
Al Viro59551022016-01-22 15:40:57 -0500409 inode_unlock(inode);
Eric Pariscee74f42010-10-13 17:50:25 -0400410 }
411
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400412 rc = security_read_policy(state, &plm->data, &plm->len);
Eric Pariscee74f42010-10-13 17:50:25 -0400413 if (rc)
414 goto err;
415
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400416 fsi->policy_opened = 1;
Eric Pariscee74f42010-10-13 17:50:25 -0400417
418 filp->private_data = plm;
419
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400420 mutex_unlock(&fsi->mutex);
Eric Pariscee74f42010-10-13 17:50:25 -0400421
422 return 0;
423err:
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400424 mutex_unlock(&fsi->mutex);
Eric Pariscee74f42010-10-13 17:50:25 -0400425
426 if (plm)
427 vfree(plm->data);
428 kfree(plm);
429 return rc;
430}
431
432static int sel_release_policy(struct inode *inode, struct file *filp)
433{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400434 struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
Eric Pariscee74f42010-10-13 17:50:25 -0400435 struct policy_load_memory *plm = filp->private_data;
436
437 BUG_ON(!plm);
438
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400439 fsi->policy_opened = 0;
Eric Pariscee74f42010-10-13 17:50:25 -0400440
441 vfree(plm->data);
442 kfree(plm);
443
444 return 0;
445}
446
447static ssize_t sel_read_policy(struct file *filp, char __user *buf,
448 size_t count, loff_t *ppos)
449{
450 struct policy_load_memory *plm = filp->private_data;
451 int ret;
452
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500453 ret = avc_has_perm(&selinux_state,
454 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500455 SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
Eric Pariscee74f42010-10-13 17:50:25 -0400456 if (ret)
Jann Horn0da74122018-06-28 20:39:54 -0400457 return ret;
Eric Pariscee74f42010-10-13 17:50:25 -0400458
Jann Horn0da74122018-06-28 20:39:54 -0400459 return simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
Eric Pariscee74f42010-10-13 17:50:25 -0400460}
461
Souptick Joarderac9a1f62018-04-14 21:02:41 +0530462static vm_fault_t sel_mmap_policy_fault(struct vm_fault *vmf)
Eric Paris845ca302010-10-13 17:50:31 -0400463{
Dave Jiang11bac802017-02-24 14:56:41 -0800464 struct policy_load_memory *plm = vmf->vma->vm_file->private_data;
Eric Paris845ca302010-10-13 17:50:31 -0400465 unsigned long offset;
466 struct page *page;
467
468 if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
469 return VM_FAULT_SIGBUS;
470
471 offset = vmf->pgoff << PAGE_SHIFT;
472 if (offset >= roundup(plm->len, PAGE_SIZE))
473 return VM_FAULT_SIGBUS;
474
475 page = vmalloc_to_page(plm->data + offset);
476 get_page(page);
477
478 vmf->page = page;
479
480 return 0;
481}
482
Kirill A. Shutemov7cbea8d2015-09-09 15:39:26 -0700483static const struct vm_operations_struct sel_mmap_policy_ops = {
Eric Paris845ca302010-10-13 17:50:31 -0400484 .fault = sel_mmap_policy_fault,
485 .page_mkwrite = sel_mmap_policy_fault,
486};
487
James Morrisad3fa082011-08-30 10:50:12 +1000488static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
Eric Paris845ca302010-10-13 17:50:31 -0400489{
490 if (vma->vm_flags & VM_SHARED) {
491 /* do not allow mprotect to make mapping writable */
492 vma->vm_flags &= ~VM_MAYWRITE;
493
494 if (vma->vm_flags & VM_WRITE)
495 return -EACCES;
496 }
497
Konstantin Khlebnikov314e51b2012-10-08 16:29:02 -0700498 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
Eric Paris845ca302010-10-13 17:50:31 -0400499 vma->vm_ops = &sel_mmap_policy_ops;
500
501 return 0;
502}
503
Eric Pariscee74f42010-10-13 17:50:25 -0400504static const struct file_operations sel_policy_ops = {
505 .open = sel_open_policy,
506 .read = sel_read_policy,
Eric Paris845ca302010-10-13 17:50:31 -0400507 .mmap = sel_mmap_policy,
Eric Pariscee74f42010-10-13 17:50:25 -0400508 .release = sel_release_policy,
Eric Paris47a93a52012-02-16 15:08:39 -0500509 .llseek = generic_file_llseek,
Eric Pariscee74f42010-10-13 17:50:25 -0400510};
511
Stephen Smalley02a52c52020-08-07 09:29:34 -0400512static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
513 struct selinux_policy *newpolicy)
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400514{
515 int ret;
516
Stephen Smalley02a52c52020-08-07 09:29:34 -0400517 ret = sel_make_bools(fsi, newpolicy);
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400518 if (ret) {
519 pr_err("SELinux: failed to load policy booleans\n");
520 return ret;
521 }
522
Stephen Smalley02a52c52020-08-07 09:29:34 -0400523 ret = sel_make_classes(fsi, newpolicy);
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400524 if (ret) {
525 pr_err("SELinux: failed to load policy classes\n");
526 return ret;
527 }
528
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400529 return 0;
530}
531
Eric Paris18729812008-04-17 14:15:45 -0400532static ssize_t sel_write_load(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 size_t count, loff_t *ppos)
534
535{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400536 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
Stephen Smalley02a52c52020-08-07 09:29:34 -0400537 struct selinux_policy *newpolicy;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 ssize_t length;
539 void *data = NULL;
540
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400541 mutex_lock(&fsi->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500543 length = avc_has_perm(&selinux_state,
544 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500545 SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 if (length)
547 goto out;
548
Eric Parisb77a4932010-11-23 11:40:08 -0500549 /* No partial writes. */
550 length = -EINVAL;
551 if (*ppos != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Eric Parisb77a4932010-11-23 11:40:08 -0500554 length = -ENOMEM;
555 data = vmalloc(count);
556 if (!data)
557 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559 length = -EFAULT;
560 if (copy_from_user(data, buf, count) != 0)
561 goto out;
562
Stephen Smalley02a52c52020-08-07 09:29:34 -0400563 length = security_load_policy(fsi->state, data, count, &newpolicy);
Gary Tierney4262fb52017-01-09 10:07:31 -0500564 if (length) {
565 pr_warn_ratelimited("SELinux: failed to load policy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 goto out;
Gary Tierney4262fb52017-01-09 10:07:31 -0500567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Stephen Smalley02a52c52020-08-07 09:29:34 -0400569 length = sel_make_policy_nodes(fsi, newpolicy);
570 if (length) {
571 selinux_policy_cancel(fsi->state, newpolicy);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400572 goto out1;
Stephen Smalley02a52c52020-08-07 09:29:34 -0400573 }
574
575 selinux_policy_commit(fsi->state, newpolicy);
Eric Parisb77a4932010-11-23 11:40:08 -0500576
577 length = count;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400578
579out1:
Richard Guy Briggscdfb6b32018-05-12 21:58:20 -0400580 audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
Richard Guy Briggsd1411362018-04-09 19:36:31 -0400581 "auid=%u ses=%u lsm=selinux res=1",
Eric W. Biederman581abc02012-08-20 00:09:36 -0700582 from_kuid(&init_user_ns, audit_get_loginuid(current)),
Eric Paris4746ec52008-01-08 10:06:53 -0500583 audit_get_sessionid(current));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584out:
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400585 mutex_unlock(&fsi->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 vfree(data);
587 return length;
588}
589
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800590static const struct file_operations sel_load_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 .write = sel_write_load,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200592 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593};
594
Eric Paris18729812008-04-17 14:15:45 -0400595static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400597 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
598 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -0500599 char *canon = NULL;
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800600 u32 sid, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 ssize_t length;
602
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500603 length = avc_has_perm(&selinux_state,
604 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500605 SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500607 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400609 length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500610 if (length)
611 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400613 length = security_sid_to_context(state, sid, &canon, &len);
Eric Parisb77a4932010-11-23 11:40:08 -0500614 if (length)
615 goto out;
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800616
Eric Parisb77a4932010-11-23 11:40:08 -0500617 length = -ERANGE;
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800618 if (len > SIMPLE_TRANSACTION_LIMIT) {
peter enderborgf8b69a52018-06-12 10:09:06 +0200619 pr_err("SELinux: %s: context size (%u) exceeds "
Eric Paris744ba352008-04-17 11:52:44 -0400620 "payload max\n", __func__, len);
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800621 goto out;
622 }
623
624 memcpy(buf, canon, len);
625 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626out:
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800627 kfree(canon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return length;
629}
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
632 size_t count, loff_t *ppos)
633{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400634 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 char tmpbuf[TMPBUFLEN];
636 ssize_t length;
637
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400638 length = scnprintf(tmpbuf, TMPBUFLEN, "%u", fsi->state->checkreqprot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
640}
641
Eric Paris18729812008-04-17 14:15:45 -0400642static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 size_t count, loff_t *ppos)
644{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400645 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
Al Viro8365a712015-12-24 00:08:06 -0500646 char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 ssize_t length;
648 unsigned int new_value;
649
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500650 length = avc_has_perm(&selinux_state,
651 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500652 SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
653 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 if (length)
Al Viro8365a712015-12-24 00:08:06 -0500655 return length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Davi Arnautbfd51622005-10-30 14:59:24 -0800657 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -0500658 return -ENOMEM;
Eric Parisb77a4932010-11-23 11:40:08 -0500659
660 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -0500661 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -0500662 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -0500663
Al Viro8365a712015-12-24 00:08:06 -0500664 page = memdup_user_nul(buf, count);
665 if (IS_ERR(page))
666 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 length = -EINVAL;
669 if (sscanf(page, "%u", &new_value) != 1)
670 goto out;
671
Stephen Smalleye9c38f92020-01-08 11:24:47 -0500672 if (new_value) {
673 char comm[sizeof(current->comm)];
674
675 memcpy(comm, current->comm, sizeof(comm));
676 pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n",
677 comm, current->pid);
678 }
679
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400680 fsi->state->checkreqprot = new_value ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 length = count;
682out:
Al Viro8365a712015-12-24 00:08:06 -0500683 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return length;
685}
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800686static const struct file_operations sel_checkreqprot_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 .read = sel_read_checkreqprot,
688 .write = sel_write_checkreqprot,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200689 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690};
691
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500692static ssize_t sel_write_validatetrans(struct file *file,
693 const char __user *buf,
694 size_t count, loff_t *ppos)
695{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400696 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
697 struct selinux_state *state = fsi->state;
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500698 char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
699 char *req = NULL;
700 u32 osid, nsid, tsid;
701 u16 tclass;
702 int rc;
703
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500704 rc = avc_has_perm(&selinux_state,
705 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500706 SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500707 if (rc)
708 goto out;
709
710 rc = -ENOMEM;
711 if (count >= PAGE_SIZE)
712 goto out;
713
714 /* No partial writes. */
715 rc = -EINVAL;
716 if (*ppos != 0)
717 goto out;
718
Al Viro0b884d22017-05-13 18:12:07 -0400719 req = memdup_user_nul(buf, count);
720 if (IS_ERR(req)) {
721 rc = PTR_ERR(req);
722 req = NULL;
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500723 goto out;
Al Viro0b884d22017-05-13 18:12:07 -0400724 }
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500725
726 rc = -ENOMEM;
727 oldcon = kzalloc(count + 1, GFP_KERNEL);
728 if (!oldcon)
729 goto out;
730
731 newcon = kzalloc(count + 1, GFP_KERNEL);
732 if (!newcon)
733 goto out;
734
735 taskcon = kzalloc(count + 1, GFP_KERNEL);
736 if (!taskcon)
737 goto out;
738
739 rc = -EINVAL;
740 if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
741 goto out;
742
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400743 rc = security_context_str_to_sid(state, oldcon, &osid, GFP_KERNEL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500744 if (rc)
745 goto out;
746
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400747 rc = security_context_str_to_sid(state, newcon, &nsid, GFP_KERNEL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500748 if (rc)
749 goto out;
750
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400751 rc = security_context_str_to_sid(state, taskcon, &tsid, GFP_KERNEL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500752 if (rc)
753 goto out;
754
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400755 rc = security_validate_transition_user(state, osid, nsid, tsid, tclass);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500756 if (!rc)
757 rc = count;
758out:
759 kfree(req);
760 kfree(oldcon);
761 kfree(newcon);
762 kfree(taskcon);
763 return rc;
764}
765
766static const struct file_operations sel_transition_ops = {
767 .write = sel_write_validatetrans,
768 .llseek = generic_file_llseek,
769};
770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771/*
772 * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
773 */
Eric Paris18729812008-04-17 14:15:45 -0400774static ssize_t sel_write_access(struct file *file, char *buf, size_t size);
775static ssize_t sel_write_create(struct file *file, char *buf, size_t size);
776static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size);
777static ssize_t sel_write_user(struct file *file, char *buf, size_t size);
778static ssize_t sel_write_member(struct file *file, char *buf, size_t size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Eric Biggers631d2b42018-07-17 10:43:56 -0700780static ssize_t (*const write_op[])(struct file *, char *, size_t) = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 [SEL_ACCESS] = sel_write_access,
782 [SEL_CREATE] = sel_write_create,
783 [SEL_RELABEL] = sel_write_relabel,
784 [SEL_USER] = sel_write_user,
785 [SEL_MEMBER] = sel_write_member,
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800786 [SEL_CONTEXT] = sel_write_context,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787};
788
789static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
790{
Al Viro496ad9a2013-01-23 17:07:38 -0500791 ino_t ino = file_inode(file)->i_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 char *data;
793 ssize_t rv;
794
Nicolas Kaiser6e20a642006-01-06 00:11:22 -0800795 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return -EINVAL;
797
798 data = simple_transaction_get(file, buf, size);
799 if (IS_ERR(data))
800 return PTR_ERR(data);
801
Eric Paris18729812008-04-17 14:15:45 -0400802 rv = write_op[ino](file, data, size);
803 if (rv > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 simple_transaction_set(file, rv);
805 rv = size;
806 }
807 return rv;
808}
809
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800810static const struct file_operations transaction_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 .write = selinux_transaction_write,
812 .read = simple_transaction_read,
813 .release = simple_transaction_release,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200814 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815};
816
817/*
818 * payload - write methods
819 * If the method has a response, the response should be put in buf,
820 * and the length returned. Otherwise return 0 or and -error.
821 */
822
Eric Paris18729812008-04-17 14:15:45 -0400823static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400825 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
826 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -0500827 char *scon = NULL, *tcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 u32 ssid, tsid;
829 u16 tclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 struct av_decision avd;
831 ssize_t length;
832
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500833 length = avc_has_perm(&selinux_state,
834 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500835 SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500837 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800840 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (!scon)
Eric Parisb77a4932010-11-23 11:40:08 -0500842 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Eric Parisb77a4932010-11-23 11:40:08 -0500844 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800845 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (!tcon)
847 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
849 length = -EINVAL;
Stephen Smalley19439d02010-01-14 17:28:10 -0500850 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
Eric Parisb77a4932010-11-23 11:40:08 -0500851 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400853 length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500854 if (length)
855 goto out;
856
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400857 length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500858 if (length)
859 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400861 security_compute_av_user(state, ssid, tsid, tclass, &avd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863 length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
KaiGai Kohei8a6f83a2009-04-01 10:07:57 +0900864 "%x %x %x %x %u %x",
Eric Parisf1c63812009-02-12 14:50:54 -0500865 avd.allowed, 0xffffffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 avd.auditallow, avd.auditdeny,
KaiGai Kohei8a6f83a2009-04-01 10:07:57 +0900867 avd.seqno, avd.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868out:
Eric Parisb77a4932010-11-23 11:40:08 -0500869 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 kfree(scon);
871 return length;
872}
873
Eric Paris18729812008-04-17 14:15:45 -0400874static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400876 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
877 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -0500878 char *scon = NULL, *tcon = NULL;
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100879 char *namebuf = NULL, *objname = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 u32 ssid, tsid, newsid;
881 u16 tclass;
882 ssize_t length;
Eric Parisb77a4932010-11-23 11:40:08 -0500883 char *newcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 u32 len;
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100885 int nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500887 length = avc_has_perm(&selinux_state,
888 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500889 SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
890 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500892 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800895 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (!scon)
Eric Parisb77a4932010-11-23 11:40:08 -0500897 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Eric Parisb77a4932010-11-23 11:40:08 -0500899 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800900 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (!tcon)
902 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100904 length = -ENOMEM;
905 namebuf = kzalloc(size + 1, GFP_KERNEL);
906 if (!namebuf)
Eric Parisb77a4932010-11-23 11:40:08 -0500907 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100909 length = -EINVAL;
910 nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
911 if (nargs < 3 || nargs > 4)
912 goto out;
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400913 if (nargs == 4) {
914 /*
915 * If and when the name of new object to be queried contains
916 * either whitespace or multibyte characters, they shall be
917 * encoded based on the percentage-encoding rule.
918 * If not encoded, the sscanf logic picks up only left-half
919 * of the supplied name; splitted by a whitespace unexpectedly.
920 */
921 char *r, *w;
922 int c1, c2;
923
924 r = w = namebuf;
925 do {
926 c1 = *r++;
927 if (c1 == '+')
928 c1 = ' ';
929 else if (c1 == '%') {
Andy Shevchenkoaf7ff2c2011-11-15 15:11:41 -0800930 c1 = hex_to_bin(*r++);
931 if (c1 < 0)
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400932 goto out;
Andy Shevchenkoaf7ff2c2011-11-15 15:11:41 -0800933 c2 = hex_to_bin(*r++);
934 if (c2 < 0)
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400935 goto out;
936 c1 = (c1 << 4) | c2;
937 }
938 *w++ = c1;
939 } while (c1 != '\0');
940
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100941 objname = namebuf;
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400942 }
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100943
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400944 length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500945 if (length)
946 goto out;
947
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400948 length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500949 if (length)
950 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400952 length = security_transition_sid_user(state, ssid, tsid, tclass,
953 objname, &newsid);
Eric Parisb77a4932010-11-23 11:40:08 -0500954 if (length)
955 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400957 length = security_sid_to_context(state, newsid, &newcon, &len);
Eric Parisb77a4932010-11-23 11:40:08 -0500958 if (length)
959 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Eric Parisb77a4932010-11-23 11:40:08 -0500961 length = -ERANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 if (len > SIMPLE_TRANSACTION_LIMIT) {
peter enderborgf8b69a52018-06-12 10:09:06 +0200963 pr_err("SELinux: %s: context size (%u) exceeds "
Eric Paris744ba352008-04-17 11:52:44 -0400964 "payload max\n", __func__, len);
Eric Parisb77a4932010-11-23 11:40:08 -0500965 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 }
967
968 memcpy(buf, newcon, len);
969 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970out:
Eric Parisb77a4932010-11-23 11:40:08 -0500971 kfree(newcon);
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100972 kfree(namebuf);
Eric Parisb77a4932010-11-23 11:40:08 -0500973 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 kfree(scon);
975 return length;
976}
977
Eric Paris18729812008-04-17 14:15:45 -0400978static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Stephen Smalley0619f0f2018-03-20 11:59:11 -0400980 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
981 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -0500982 char *scon = NULL, *tcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 u32 ssid, tsid, newsid;
984 u16 tclass;
985 ssize_t length;
Eric Parisb77a4932010-11-23 11:40:08 -0500986 char *newcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 u32 len;
988
Stephen Smalley6b6bc622018-03-05 11:47:56 -0500989 length = avc_has_perm(&selinux_state,
990 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500991 SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
992 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500994 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800997 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (!scon)
Eric Parisb77a4932010-11-23 11:40:08 -0500999 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Eric Parisb77a4932010-11-23 11:40:08 -05001001 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001002 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (!tcon)
1004 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006 length = -EINVAL;
1007 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
Eric Parisb77a4932010-11-23 11:40:08 -05001008 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001010 length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001011 if (length)
1012 goto out;
1013
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001014 length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001015 if (length)
1016 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001018 length = security_change_sid(state, ssid, tsid, tclass, &newsid);
Eric Parisb77a4932010-11-23 11:40:08 -05001019 if (length)
1020 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001022 length = security_sid_to_context(state, newsid, &newcon, &len);
Eric Parisb77a4932010-11-23 11:40:08 -05001023 if (length)
1024 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Eric Parisb77a4932010-11-23 11:40:08 -05001026 length = -ERANGE;
1027 if (len > SIMPLE_TRANSACTION_LIMIT)
1028 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 memcpy(buf, newcon, len);
1031 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032out:
Eric Parisb77a4932010-11-23 11:40:08 -05001033 kfree(newcon);
1034 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 kfree(scon);
1036 return length;
1037}
1038
Eric Paris18729812008-04-17 14:15:45 -04001039static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001041 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
1042 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -05001043 char *con = NULL, *user = NULL, *ptr;
1044 u32 sid, *sids = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 ssize_t length;
1046 char *newcon;
1047 int i, rc;
1048 u32 len, nsids;
1049
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001050 length = avc_has_perm(&selinux_state,
1051 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001052 SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
1053 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 if (length)
Justin P. Mattock6eab04a2011-04-08 19:49:08 -07001055 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
1057 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001058 con = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 if (!con)
Justin P. Mattock6eab04a2011-04-08 19:49:08 -07001060 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Eric Parisb77a4932010-11-23 11:40:08 -05001062 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001063 user = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 if (!user)
1065 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 length = -EINVAL;
1068 if (sscanf(buf, "%s %s", con, user) != 2)
Eric Parisb77a4932010-11-23 11:40:08 -05001069 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001071 length = security_context_str_to_sid(state, con, &sid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001072 if (length)
1073 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001075 length = security_get_user_sids(state, sid, user, &sids, &nsids);
Eric Parisb77a4932010-11-23 11:40:08 -05001076 if (length)
1077 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079 length = sprintf(buf, "%u", nsids) + 1;
1080 ptr = buf + length;
1081 for (i = 0; i < nsids; i++) {
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001082 rc = security_sid_to_context(state, sids[i], &newcon, &len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if (rc) {
1084 length = rc;
Eric Parisb77a4932010-11-23 11:40:08 -05001085 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 }
1087 if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
1088 kfree(newcon);
1089 length = -ERANGE;
Eric Parisb77a4932010-11-23 11:40:08 -05001090 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092 memcpy(ptr, newcon, len);
1093 kfree(newcon);
1094 ptr += len;
1095 length += len;
1096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097out:
Eric Parisb77a4932010-11-23 11:40:08 -05001098 kfree(sids);
1099 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 kfree(con);
1101 return length;
1102}
1103
Eric Paris18729812008-04-17 14:15:45 -04001104static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001106 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
1107 struct selinux_state *state = fsi->state;
Eric Parisb77a4932010-11-23 11:40:08 -05001108 char *scon = NULL, *tcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 u32 ssid, tsid, newsid;
1110 u16 tclass;
1111 ssize_t length;
Eric Parisb77a4932010-11-23 11:40:08 -05001112 char *newcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 u32 len;
1114
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001115 length = avc_has_perm(&selinux_state,
1116 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001117 SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
1118 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -05001120 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001123 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (!scon)
Justin P. Mattock6eab04a2011-04-08 19:49:08 -07001125 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Eric Parisb77a4932010-11-23 11:40:08 -05001127 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001128 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (!tcon)
1130 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 length = -EINVAL;
1133 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
Eric Parisb77a4932010-11-23 11:40:08 -05001134 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001136 length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001137 if (length)
1138 goto out;
1139
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001140 length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001141 if (length)
1142 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001144 length = security_member_sid(state, ssid, tsid, tclass, &newsid);
Eric Parisb77a4932010-11-23 11:40:08 -05001145 if (length)
1146 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001148 length = security_sid_to_context(state, newsid, &newcon, &len);
Eric Parisb77a4932010-11-23 11:40:08 -05001149 if (length)
1150 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Eric Parisb77a4932010-11-23 11:40:08 -05001152 length = -ERANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (len > SIMPLE_TRANSACTION_LIMIT) {
peter enderborgf8b69a52018-06-12 10:09:06 +02001154 pr_err("SELinux: %s: context size (%u) exceeds "
Eric Paris744ba352008-04-17 11:52:44 -04001155 "payload max\n", __func__, len);
Eric Parisb77a4932010-11-23 11:40:08 -05001156 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 }
1158
1159 memcpy(buf, newcon, len);
1160 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161out:
Eric Parisb77a4932010-11-23 11:40:08 -05001162 kfree(newcon);
1163 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 kfree(scon);
1165 return length;
1166}
1167
1168static struct inode *sel_make_inode(struct super_block *sb, int mode)
1169{
1170 struct inode *ret = new_inode(sb);
1171
1172 if (ret) {
1173 ret->i_mode = mode;
Deepa Dinamani078cd822016-09-14 07:48:04 -07001174 ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176 return ret;
1177}
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179static ssize_t sel_read_bool(struct file *filep, char __user *buf,
1180 size_t count, loff_t *ppos)
1181{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001182 struct selinux_fs_info *fsi = file_inode(filep)->i_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 char *page = NULL;
1184 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 ssize_t ret;
1186 int cur_enforcing;
Al Viro496ad9a2013-01-23 17:07:38 -05001187 unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001188 const char *name = filep->f_path.dentry->d_name.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001190 mutex_lock(&fsi->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
Eric Parisb77a4932010-11-23 11:40:08 -05001192 ret = -EINVAL;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001193 if (index >= fsi->bool_num || strcmp(name,
1194 fsi->bool_pending_names[index]))
Jann Horn0da74122018-06-28 20:39:54 -04001195 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Eric Parisb77a4932010-11-23 11:40:08 -05001197 ret = -ENOMEM;
Eric Paris18729812008-04-17 14:15:45 -04001198 page = (char *)get_zeroed_page(GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001199 if (!page)
Jann Horn0da74122018-06-28 20:39:54 -04001200 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001202 cur_enforcing = security_get_bool_value(fsi->state, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if (cur_enforcing < 0) {
1204 ret = cur_enforcing;
Jann Horn0da74122018-06-28 20:39:54 -04001205 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001208 fsi->bool_pending_values[index]);
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001209 mutex_unlock(&fsi->mutex);
Jann Horn0da74122018-06-28 20:39:54 -04001210 ret = simple_read_from_buffer(buf, count, ppos, page, length);
1211out_free:
Eric Parisb77a4932010-11-23 11:40:08 -05001212 free_page((unsigned long)page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 return ret;
Jann Horn0da74122018-06-28 20:39:54 -04001214
1215out_unlock:
1216 mutex_unlock(&fsi->mutex);
1217 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218}
1219
1220static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
1221 size_t count, loff_t *ppos)
1222{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001223 struct selinux_fs_info *fsi = file_inode(filep)->i_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 char *page = NULL;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001225 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 int new_value;
Al Viro496ad9a2013-01-23 17:07:38 -05001227 unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001228 const char *name = filep->f_path.dentry->d_name.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
Jann Horn0da74122018-06-28 20:39:54 -04001230 if (count >= PAGE_SIZE)
1231 return -ENOMEM;
1232
1233 /* No partial writes. */
1234 if (*ppos != 0)
1235 return -EINVAL;
1236
1237 page = memdup_user_nul(buf, count);
1238 if (IS_ERR(page))
1239 return PTR_ERR(page);
1240
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001241 mutex_lock(&fsi->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001243 length = avc_has_perm(&selinux_state,
1244 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001245 SECCLASS_SECURITY, SECURITY__SETBOOL,
1246 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 if (length)
1248 goto out;
1249
Eric Parisb77a4932010-11-23 11:40:08 -05001250 length = -EINVAL;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001251 if (index >= fsi->bool_num || strcmp(name,
1252 fsi->bool_pending_names[index]))
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001253 goto out;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 length = -EINVAL;
1256 if (sscanf(page, "%d", &new_value) != 1)
1257 goto out;
1258
1259 if (new_value)
1260 new_value = 1;
1261
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001262 fsi->bool_pending_values[index] = new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 length = count;
1264
1265out:
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001266 mutex_unlock(&fsi->mutex);
Al Viro8365a712015-12-24 00:08:06 -05001267 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return length;
1269}
1270
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001271static const struct file_operations sel_bool_ops = {
Eric Paris18729812008-04-17 14:15:45 -04001272 .read = sel_read_bool,
1273 .write = sel_write_bool,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001274 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275};
1276
1277static ssize_t sel_commit_bools_write(struct file *filep,
1278 const char __user *buf,
1279 size_t count, loff_t *ppos)
1280{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001281 struct selinux_fs_info *fsi = file_inode(filep)->i_sb->s_fs_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 char *page = NULL;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001283 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 int new_value;
1285
Jann Horn0da74122018-06-28 20:39:54 -04001286 if (count >= PAGE_SIZE)
1287 return -ENOMEM;
1288
1289 /* No partial writes. */
1290 if (*ppos != 0)
1291 return -EINVAL;
1292
1293 page = memdup_user_nul(buf, count);
1294 if (IS_ERR(page))
1295 return PTR_ERR(page);
1296
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001297 mutex_lock(&fsi->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001299 length = avc_has_perm(&selinux_state,
1300 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001301 SECCLASS_SECURITY, SECURITY__SETBOOL,
1302 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (length)
1304 goto out;
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 length = -EINVAL;
1307 if (sscanf(page, "%d", &new_value) != 1)
1308 goto out;
1309
Eric Parisb77a4932010-11-23 11:40:08 -05001310 length = 0;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001311 if (new_value && fsi->bool_pending_values)
1312 length = security_set_bools(fsi->state, fsi->bool_num,
1313 fsi->bool_pending_values);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
Eric Parisb77a4932010-11-23 11:40:08 -05001315 if (!length)
1316 length = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318out:
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001319 mutex_unlock(&fsi->mutex);
Al Viro8365a712015-12-24 00:08:06 -05001320 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 return length;
1322}
1323
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001324static const struct file_operations sel_commit_bools_ops = {
Eric Paris18729812008-04-17 14:15:45 -04001325 .write = sel_commit_bools_write,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001326 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327};
1328
Christopher J. PeBenito0c92d7c2007-05-23 09:12:07 -04001329static void sel_remove_entries(struct dentry *de)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330{
Al Viroad521842014-12-24 14:56:48 -05001331 d_genocide(de);
1332 shrink_dcache_parent(de);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333}
1334
1335#define BOOL_DIR_NAME "booleans"
1336
Stephen Smalley02a52c52020-08-07 09:29:34 -04001337static int sel_make_bools(struct selinux_fs_info *fsi,
1338 struct selinux_policy *newpolicy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
Ondrej Mosnacek60abd312020-02-03 12:27:20 +01001340 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 ssize_t len;
1342 struct dentry *dentry = NULL;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001343 struct dentry *dir = fsi->bool_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 struct inode *inode = NULL;
1345 struct inode_security_struct *isec;
1346 char **names = NULL, *page;
Ondrej Mosnacek60abd312020-02-03 12:27:20 +01001347 u32 i, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 int *values = NULL;
1349 u32 sid;
1350
1351 /* remove any existing files */
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001352 for (i = 0; i < fsi->bool_num; i++)
1353 kfree(fsi->bool_pending_names[i]);
1354 kfree(fsi->bool_pending_names);
1355 kfree(fsi->bool_pending_values);
1356 fsi->bool_num = 0;
1357 fsi->bool_pending_names = NULL;
1358 fsi->bool_pending_values = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Christopher J. PeBenito0c92d7c2007-05-23 09:12:07 -04001360 sel_remove_entries(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Eric Parisb77a4932010-11-23 11:40:08 -05001362 ret = -ENOMEM;
Eric Paris18729812008-04-17 14:15:45 -04001363 page = (char *)get_zeroed_page(GFP_KERNEL);
1364 if (!page)
Eric Parisb77a4932010-11-23 11:40:08 -05001365 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Stephen Smalley02a52c52020-08-07 09:29:34 -04001367 ret = security_get_bools(newpolicy, &num, &names, &values);
Eric Parisb77a4932010-11-23 11:40:08 -05001368 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 goto out;
1370
1371 for (i = 0; i < num; i++) {
Eric Parisb77a4932010-11-23 11:40:08 -05001372 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 dentry = d_alloc_name(dir, names[i]);
Eric Parisb77a4932010-11-23 11:40:08 -05001374 if (!dentry)
1375 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Eric Parisb77a4932010-11-23 11:40:08 -05001377 ret = -ENOMEM;
1378 inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
nixiaoming7e4237f2018-08-05 17:10:36 +08001379 if (!inode) {
1380 dput(dentry);
Eric Parisb77a4932010-11-23 11:40:08 -05001381 goto out;
nixiaoming7e4237f2018-08-05 17:10:36 +08001382 }
Eric Parisb77a4932010-11-23 11:40:08 -05001383
Eric Parisb77a4932010-11-23 11:40:08 -05001384 ret = -ENAMETOOLONG;
Al Virocc1dad72012-04-02 19:40:47 -04001385 len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
nixiaoming7e4237f2018-08-05 17:10:36 +08001386 if (len >= PAGE_SIZE) {
1387 dput(dentry);
1388 iput(inode);
Eric Parisb77a4932010-11-23 11:40:08 -05001389 goto out;
nixiaoming7e4237f2018-08-05 17:10:36 +08001390 }
Eric Parisb77a4932010-11-23 11:40:08 -05001391
Casey Schaufler80788c22018-09-21 17:19:11 -07001392 isec = selinux_inode(inode);
Stephen Smalley02a52c52020-08-07 09:29:34 -04001393 ret = selinux_policy_genfs_sid(newpolicy, "selinuxfs", page,
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001394 SECCLASS_FILE, &sid);
Gary Tierney4262fb52017-01-09 10:07:31 -05001395 if (ret) {
Gary Tierney900fde02017-01-09 10:07:32 -05001396 pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
1397 page);
1398 sid = SECINITSID_SECURITY;
Gary Tierney4262fb52017-01-09 10:07:31 -05001399 }
1400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 isec->sid = sid;
Andreas Gruenbacher42059112016-11-10 22:18:27 +01001402 isec->initialized = LABEL_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 inode->i_fop = &sel_bool_ops;
James Carterbce34bc2007-04-04 16:18:50 -04001404 inode->i_ino = i|SEL_BOOL_INO_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 d_add(dentry, inode);
1406 }
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001407 fsi->bool_num = num;
1408 fsi->bool_pending_names = names;
1409 fsi->bool_pending_values = values;
Eric Parisb77a4932010-11-23 11:40:08 -05001410
1411 free_page((unsigned long)page);
1412 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413out:
1414 free_page((unsigned long)page);
Eric Parisb77a4932010-11-23 11:40:08 -05001415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 if (names) {
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07001417 for (i = 0; i < num; i++)
1418 kfree(names[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 kfree(names);
1420 }
Davi Arnaut20c19e42005-10-23 12:57:16 -07001421 kfree(values);
Christopher J. PeBenito0c92d7c2007-05-23 09:12:07 -04001422 sel_remove_entries(dir);
Eric Parisb77a4932010-11-23 11:40:08 -05001423
1424 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
1428 size_t count, loff_t *ppos)
1429{
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001430 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
1431 struct selinux_state *state = fsi->state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 char tmpbuf[TMPBUFLEN];
1433 ssize_t length;
1434
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001435 length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
1436 avc_get_cache_threshold(state->avc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1438}
1439
Eric Paris18729812008-04-17 14:15:45 -04001440static ssize_t sel_write_avc_cache_threshold(struct file *file,
1441 const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 size_t count, loff_t *ppos)
1443
1444{
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001445 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
1446 struct selinux_state *state = fsi->state;
Al Viro8365a712015-12-24 00:08:06 -05001447 char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 ssize_t ret;
Heinrich Schuchardt309c5fa2016-06-10 23:14:26 +02001449 unsigned int new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001451 ret = avc_has_perm(&selinux_state,
1452 current_sid(), SECINITSID_SECURITY,
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001453 SECCLASS_SECURITY, SECURITY__SETSECPARAM,
1454 NULL);
Eric Parisb77a4932010-11-23 11:40:08 -05001455 if (ret)
Al Viro8365a712015-12-24 00:08:06 -05001456 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
Eric Parisb77a4932010-11-23 11:40:08 -05001458 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -05001459 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Eric Parisb77a4932010-11-23 11:40:08 -05001461 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -05001462 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -05001463 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -05001464
Al Viro8365a712015-12-24 00:08:06 -05001465 page = memdup_user_nul(buf, count);
1466 if (IS_ERR(page))
1467 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Eric Parisb77a4932010-11-23 11:40:08 -05001469 ret = -EINVAL;
1470 if (sscanf(page, "%u", &new_value) != 1)
1471 goto out;
1472
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001473 avc_set_cache_threshold(state->avc, new_value);
Eric Parisb77a4932010-11-23 11:40:08 -05001474
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 ret = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476out:
Al Viro8365a712015-12-24 00:08:06 -05001477 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 return ret;
1479}
1480
1481static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
1482 size_t count, loff_t *ppos)
1483{
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001484 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
1485 struct selinux_state *state = fsi->state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 char *page;
Eric Parisb77a4932010-11-23 11:40:08 -05001487 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 page = (char *)__get_free_page(GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001490 if (!page)
1491 return -ENOMEM;
1492
Stephen Smalley6b6bc622018-03-05 11:47:56 -05001493 length = avc_get_hash_stats(state->avc, page);
Eric Parisb77a4932010-11-23 11:40:08 -05001494 if (length >= 0)
1495 length = simple_read_from_buffer(buf, count, ppos, page, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 free_page((unsigned long)page);
Eric Parisb77a4932010-11-23 11:40:08 -05001497
1498 return length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499}
1500
Jeff Vander Stoep66f8e2f2019-11-22 10:33:06 +01001501static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf,
1502 size_t count, loff_t *ppos)
1503{
1504 struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
1505 struct selinux_state *state = fsi->state;
1506 char *page;
1507 ssize_t length;
1508
1509 page = (char *)__get_free_page(GFP_KERNEL);
1510 if (!page)
1511 return -ENOMEM;
1512
1513 length = security_sidtab_hash_stats(state, page);
1514 if (length >= 0)
1515 length = simple_read_from_buffer(buf, count, ppos, page,
1516 length);
1517 free_page((unsigned long)page);
1518
1519 return length;
1520}
1521
1522static const struct file_operations sel_sidtab_hash_stats_ops = {
1523 .read = sel_read_sidtab_hash_stats,
1524 .llseek = generic_file_llseek,
1525};
1526
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001527static const struct file_operations sel_avc_cache_threshold_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 .read = sel_read_avc_cache_threshold,
1529 .write = sel_write_avc_cache_threshold,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001530 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531};
1532
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001533static const struct file_operations sel_avc_hash_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 .read = sel_read_avc_hash_stats,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001535 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536};
1537
1538#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
1539static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
1540{
1541 int cpu;
1542
Rusty Russell4f4b6c12009-01-01 10:12:15 +10301543 for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if (!cpu_possible(cpu))
1545 continue;
1546 *idx = cpu + 1;
1547 return &per_cpu(avc_cache_stats, cpu);
1548 }
Vasily Averin8d269a82020-02-01 10:47:47 +03001549 (*idx)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 return NULL;
1551}
1552
1553static void *sel_avc_stats_seq_start(struct seq_file *seq, loff_t *pos)
1554{
1555 loff_t n = *pos - 1;
1556
1557 if (*pos == 0)
1558 return SEQ_START_TOKEN;
1559
1560 return sel_avc_get_stat_idx(&n);
1561}
1562
1563static void *sel_avc_stats_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1564{
1565 return sel_avc_get_stat_idx(pos);
1566}
1567
1568static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
1569{
1570 struct avc_cache_stats *st = v;
1571
Markus Elfring710a0642017-01-15 14:04:53 +01001572 if (v == SEQ_START_TOKEN) {
1573 seq_puts(seq,
1574 "lookups hits misses allocations reclaims frees\n");
1575 } else {
Linus Torvalds257313b2011-05-19 21:22:53 -07001576 unsigned int lookups = st->lookups;
1577 unsigned int misses = st->misses;
1578 unsigned int hits = lookups - misses;
1579 seq_printf(seq, "%u %u %u %u %u %u\n", lookups,
1580 hits, misses, st->allocations,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 st->reclaims, st->frees);
Linus Torvalds257313b2011-05-19 21:22:53 -07001582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return 0;
1584}
1585
1586static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
1587{ }
1588
Jan Engelhardt1996a102008-01-23 00:02:58 +01001589static const struct seq_operations sel_avc_cache_stats_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 .start = sel_avc_stats_seq_start,
1591 .next = sel_avc_stats_seq_next,
1592 .show = sel_avc_stats_seq_show,
1593 .stop = sel_avc_stats_seq_stop,
1594};
1595
1596static int sel_open_avc_cache_stats(struct inode *inode, struct file *file)
1597{
1598 return seq_open(file, &sel_avc_cache_stats_seq_ops);
1599}
1600
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001601static const struct file_operations sel_avc_cache_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 .open = sel_open_avc_cache_stats,
1603 .read = seq_read,
1604 .llseek = seq_lseek,
1605 .release = seq_release,
1606};
1607#endif
1608
1609static int sel_make_avc_files(struct dentry *dir)
1610{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001611 struct super_block *sb = dir->d_sb;
1612 struct selinux_fs_info *fsi = sb->s_fs_info;
Eric Parisb77a4932010-11-23 11:40:08 -05001613 int i;
Eric Biggerscda37122017-03-25 21:15:37 -07001614 static const struct tree_descr files[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 { "cache_threshold",
1616 &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR },
1617 { "hash_stats", &sel_avc_hash_stats_ops, S_IRUGO },
1618#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
1619 { "cache_stats", &sel_avc_cache_stats_ops, S_IRUGO },
1620#endif
1621 };
1622
Nicolas Kaiser6e20a642006-01-06 00:11:22 -08001623 for (i = 0; i < ARRAY_SIZE(files); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 struct inode *inode;
1625 struct dentry *dentry;
1626
1627 dentry = d_alloc_name(dir, files[i].name);
Eric Parisb77a4932010-11-23 11:40:08 -05001628 if (!dentry)
1629 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631 inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
nixiaoming7e4237f2018-08-05 17:10:36 +08001632 if (!inode) {
1633 dput(dentry);
Eric Parisb77a4932010-11-23 11:40:08 -05001634 return -ENOMEM;
nixiaoming7e4237f2018-08-05 17:10:36 +08001635 }
Eric Parisb77a4932010-11-23 11:40:08 -05001636
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 inode->i_fop = files[i].ops;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001638 inode->i_ino = ++fsi->last_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 d_add(dentry, inode);
1640 }
Eric Parisb77a4932010-11-23 11:40:08 -05001641
1642 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643}
1644
Jeff Vander Stoep66f8e2f2019-11-22 10:33:06 +01001645static int sel_make_ss_files(struct dentry *dir)
1646{
1647 struct super_block *sb = dir->d_sb;
1648 struct selinux_fs_info *fsi = sb->s_fs_info;
1649 int i;
1650 static struct tree_descr files[] = {
1651 { "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
1652 };
1653
1654 for (i = 0; i < ARRAY_SIZE(files); i++) {
1655 struct inode *inode;
1656 struct dentry *dentry;
1657
1658 dentry = d_alloc_name(dir, files[i].name);
1659 if (!dentry)
1660 return -ENOMEM;
1661
1662 inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
1663 if (!inode) {
1664 dput(dentry);
1665 return -ENOMEM;
1666 }
1667
1668 inode->i_fop = files[i].ops;
1669 inode->i_ino = ++fsi->last_ino;
1670 d_add(dentry, inode);
1671 }
1672
1673 return 0;
1674}
1675
Eric Paris18729812008-04-17 14:15:45 -04001676static ssize_t sel_read_initcon(struct file *file, char __user *buf,
James Carterf0ee2e42007-04-04 10:11:29 -04001677 size_t count, loff_t *ppos)
1678{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001679 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
James Carterf0ee2e42007-04-04 10:11:29 -04001680 char *con;
1681 u32 sid, len;
1682 ssize_t ret;
1683
Al Viro496ad9a2013-01-23 17:07:38 -05001684 sid = file_inode(file)->i_ino&SEL_INO_MASK;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001685 ret = security_sid_to_context(fsi->state, sid, &con, &len);
Eric Parisb77a4932010-11-23 11:40:08 -05001686 if (ret)
James Carterf0ee2e42007-04-04 10:11:29 -04001687 return ret;
1688
1689 ret = simple_read_from_buffer(buf, count, ppos, con, len);
1690 kfree(con);
1691 return ret;
1692}
1693
1694static const struct file_operations sel_initcon_ops = {
1695 .read = sel_read_initcon,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001696 .llseek = generic_file_llseek,
James Carterf0ee2e42007-04-04 10:11:29 -04001697};
1698
1699static int sel_make_initcon_files(struct dentry *dir)
1700{
Eric Parisb77a4932010-11-23 11:40:08 -05001701 int i;
James Carterf0ee2e42007-04-04 10:11:29 -04001702
1703 for (i = 1; i <= SECINITSID_NUM; i++) {
1704 struct inode *inode;
1705 struct dentry *dentry;
Stephen Smalleye3e0b582020-02-24 11:10:23 -05001706 const char *s = security_get_initial_sid_context(i);
1707
1708 if (!s)
1709 continue;
1710 dentry = d_alloc_name(dir, s);
Eric Parisb77a4932010-11-23 11:40:08 -05001711 if (!dentry)
1712 return -ENOMEM;
James Carterf0ee2e42007-04-04 10:11:29 -04001713
1714 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
nixiaoming7e4237f2018-08-05 17:10:36 +08001715 if (!inode) {
1716 dput(dentry);
Eric Parisb77a4932010-11-23 11:40:08 -05001717 return -ENOMEM;
nixiaoming7e4237f2018-08-05 17:10:36 +08001718 }
Eric Parisb77a4932010-11-23 11:40:08 -05001719
James Carterf0ee2e42007-04-04 10:11:29 -04001720 inode->i_fop = &sel_initcon_ops;
1721 inode->i_ino = i|SEL_INITCON_INO_OFFSET;
1722 d_add(dentry, inode);
1723 }
Eric Parisb77a4932010-11-23 11:40:08 -05001724
1725 return 0;
James Carterf0ee2e42007-04-04 10:11:29 -04001726}
1727
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001728static inline unsigned long sel_class_to_ino(u16 class)
1729{
1730 return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
1731}
1732
1733static inline u16 sel_ino_to_class(unsigned long ino)
1734{
Eric Paris92ae9e82012-04-04 13:46:46 -04001735 return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001736}
1737
1738static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
1739{
1740 return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
1741}
1742
1743static inline u32 sel_ino_to_perm(unsigned long ino)
1744{
1745 return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
1746}
1747
Eric Paris18729812008-04-17 14:15:45 -04001748static ssize_t sel_read_class(struct file *file, char __user *buf,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001749 size_t count, loff_t *ppos)
1750{
Al Viro496ad9a2013-01-23 17:07:38 -05001751 unsigned long ino = file_inode(file)->i_ino;
Al Virocc1dad72012-04-02 19:40:47 -04001752 char res[TMPBUFLEN];
liuyang347e78c872020-01-07 09:39:18 +08001753 ssize_t len = scnprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
Al Virocc1dad72012-04-02 19:40:47 -04001754 return simple_read_from_buffer(buf, count, ppos, res, len);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001755}
1756
1757static const struct file_operations sel_class_ops = {
1758 .read = sel_read_class,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001759 .llseek = generic_file_llseek,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001760};
1761
Eric Paris18729812008-04-17 14:15:45 -04001762static ssize_t sel_read_perm(struct file *file, char __user *buf,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001763 size_t count, loff_t *ppos)
1764{
Al Viro496ad9a2013-01-23 17:07:38 -05001765 unsigned long ino = file_inode(file)->i_ino;
Al Virocc1dad72012-04-02 19:40:47 -04001766 char res[TMPBUFLEN];
liuyang347e78c872020-01-07 09:39:18 +08001767 ssize_t len = scnprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
Al Virocc1dad72012-04-02 19:40:47 -04001768 return simple_read_from_buffer(buf, count, ppos, res, len);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001769}
1770
1771static const struct file_operations sel_perm_ops = {
1772 .read = sel_read_perm,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001773 .llseek = generic_file_llseek,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001774};
1775
Paul Moore3bb56b22008-01-29 08:38:19 -05001776static ssize_t sel_read_policycap(struct file *file, char __user *buf,
1777 size_t count, loff_t *ppos)
1778{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001779 struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
Paul Moore3bb56b22008-01-29 08:38:19 -05001780 int value;
1781 char tmpbuf[TMPBUFLEN];
1782 ssize_t length;
Al Viro496ad9a2013-01-23 17:07:38 -05001783 unsigned long i_ino = file_inode(file)->i_ino;
Paul Moore3bb56b22008-01-29 08:38:19 -05001784
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001785 value = security_policycap_supported(fsi->state, i_ino & SEL_INO_MASK);
Paul Moore3bb56b22008-01-29 08:38:19 -05001786 length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
1787
1788 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1789}
1790
1791static const struct file_operations sel_policycap_ops = {
1792 .read = sel_read_policycap,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001793 .llseek = generic_file_llseek,
Paul Moore3bb56b22008-01-29 08:38:19 -05001794};
1795
Stephen Smalley02a52c52020-08-07 09:29:34 -04001796static int sel_make_perm_files(struct selinux_policy *newpolicy,
1797 char *objclass, int classvalue,
1798 struct dentry *dir)
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001799{
Eric Parisb77a4932010-11-23 11:40:08 -05001800 int i, rc, nperms;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001801 char **perms;
1802
Stephen Smalley02a52c52020-08-07 09:29:34 -04001803 rc = security_get_permissions(newpolicy, objclass, &perms, &nperms);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001804 if (rc)
Eric Parisb77a4932010-11-23 11:40:08 -05001805 return rc;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001806
1807 for (i = 0; i < nperms; i++) {
1808 struct inode *inode;
1809 struct dentry *dentry;
1810
Eric Parisb77a4932010-11-23 11:40:08 -05001811 rc = -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001812 dentry = d_alloc_name(dir, perms[i]);
Eric Parisb77a4932010-11-23 11:40:08 -05001813 if (!dentry)
1814 goto out;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001815
Eric Parisb77a4932010-11-23 11:40:08 -05001816 rc = -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001817 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
nixiaoming7e4237f2018-08-05 17:10:36 +08001818 if (!inode) {
1819 dput(dentry);
Eric Parisb77a4932010-11-23 11:40:08 -05001820 goto out;
nixiaoming7e4237f2018-08-05 17:10:36 +08001821 }
Eric Parisb77a4932010-11-23 11:40:08 -05001822
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001823 inode->i_fop = &sel_perm_ops;
1824 /* i+1 since perm values are 1-indexed */
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001825 inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001826 d_add(dentry, inode);
1827 }
Eric Parisb77a4932010-11-23 11:40:08 -05001828 rc = 0;
1829out:
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001830 for (i = 0; i < nperms; i++)
1831 kfree(perms[i]);
1832 kfree(perms);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001833 return rc;
1834}
1835
Stephen Smalley02a52c52020-08-07 09:29:34 -04001836static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
1837 char *classname, int index,
1838 struct dentry *dir)
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001839{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001840 struct super_block *sb = dir->d_sb;
1841 struct selinux_fs_info *fsi = sb->s_fs_info;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001842 struct dentry *dentry = NULL;
1843 struct inode *inode = NULL;
1844 int rc;
1845
1846 dentry = d_alloc_name(dir, "index");
Eric Parisb77a4932010-11-23 11:40:08 -05001847 if (!dentry)
1848 return -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001849
1850 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
nixiaoming7e4237f2018-08-05 17:10:36 +08001851 if (!inode) {
1852 dput(dentry);
Eric Parisb77a4932010-11-23 11:40:08 -05001853 return -ENOMEM;
nixiaoming7e4237f2018-08-05 17:10:36 +08001854 }
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001855
1856 inode->i_fop = &sel_class_ops;
1857 inode->i_ino = sel_class_to_ino(index);
1858 d_add(dentry, inode);
1859
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001860 dentry = sel_make_dir(dir, "perms", &fsi->last_class_ino);
Al Viroa1c2aa12012-03-18 20:36:59 -04001861 if (IS_ERR(dentry))
1862 return PTR_ERR(dentry);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001863
Stephen Smalley02a52c52020-08-07 09:29:34 -04001864 rc = sel_make_perm_files(newpolicy, classname, index, dentry);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001865
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001866 return rc;
1867}
1868
Stephen Smalley02a52c52020-08-07 09:29:34 -04001869static int sel_make_classes(struct selinux_fs_info *fsi,
1870 struct selinux_policy *newpolicy)
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001871{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001872
Eric Parisb77a4932010-11-23 11:40:08 -05001873 int rc, nclasses, i;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001874 char **classes;
1875
1876 /* delete any existing entries */
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001877 sel_remove_entries(fsi->class_dir);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001878
Stephen Smalley02a52c52020-08-07 09:29:34 -04001879 rc = security_get_classes(newpolicy, &classes, &nclasses);
Eric Parisb77a4932010-11-23 11:40:08 -05001880 if (rc)
1881 return rc;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001882
1883 /* +2 since classes are 1-indexed */
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001884 fsi->last_class_ino = sel_class_to_ino(nclasses + 2);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001885
1886 for (i = 0; i < nclasses; i++) {
1887 struct dentry *class_name_dir;
1888
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001889 class_name_dir = sel_make_dir(fsi->class_dir, classes[i],
1890 &fsi->last_class_ino);
Al Viroa1c2aa12012-03-18 20:36:59 -04001891 if (IS_ERR(class_name_dir)) {
1892 rc = PTR_ERR(class_name_dir);
Eric Parisb77a4932010-11-23 11:40:08 -05001893 goto out;
Al Viroa1c2aa12012-03-18 20:36:59 -04001894 }
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001895
1896 /* i+1 since class values are 1-indexed */
Stephen Smalley02a52c52020-08-07 09:29:34 -04001897 rc = sel_make_class_dir_entries(newpolicy, classes[i], i + 1,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001898 class_name_dir);
1899 if (rc)
Eric Parisb77a4932010-11-23 11:40:08 -05001900 goto out;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001901 }
Eric Parisb77a4932010-11-23 11:40:08 -05001902 rc = 0;
1903out:
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001904 for (i = 0; i < nclasses; i++)
1905 kfree(classes[i]);
1906 kfree(classes);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001907 return rc;
1908}
1909
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001910static int sel_make_policycap(struct selinux_fs_info *fsi)
Paul Moore3bb56b22008-01-29 08:38:19 -05001911{
1912 unsigned int iter;
1913 struct dentry *dentry = NULL;
1914 struct inode *inode = NULL;
1915
Paul Moore3bb56b22008-01-29 08:38:19 -05001916 for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
Stephen Smalley4dc2fce2017-05-18 16:58:31 -04001917 if (iter < ARRAY_SIZE(selinux_policycap_names))
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001918 dentry = d_alloc_name(fsi->policycap_dir,
Stephen Smalley4dc2fce2017-05-18 16:58:31 -04001919 selinux_policycap_names[iter]);
Paul Moore3bb56b22008-01-29 08:38:19 -05001920 else
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001921 dentry = d_alloc_name(fsi->policycap_dir, "unknown");
Paul Moore3bb56b22008-01-29 08:38:19 -05001922
1923 if (dentry == NULL)
1924 return -ENOMEM;
1925
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001926 inode = sel_make_inode(fsi->sb, S_IFREG | 0444);
nixiaoming7e4237f2018-08-05 17:10:36 +08001927 if (inode == NULL) {
1928 dput(dentry);
Paul Moore3bb56b22008-01-29 08:38:19 -05001929 return -ENOMEM;
nixiaoming7e4237f2018-08-05 17:10:36 +08001930 }
Paul Moore3bb56b22008-01-29 08:38:19 -05001931
1932 inode->i_fop = &sel_policycap_ops;
1933 inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
1934 d_add(dentry, inode);
1935 }
1936
1937 return 0;
1938}
1939
Al Viroa1c2aa12012-03-18 20:36:59 -04001940static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
Christopher J. PeBenito0dd4ae52007-05-23 09:12:08 -04001941 unsigned long *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942{
Al Viroa1c2aa12012-03-18 20:36:59 -04001943 struct dentry *dentry = d_alloc_name(dir, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 struct inode *inode;
1945
Al Viroa1c2aa12012-03-18 20:36:59 -04001946 if (!dentry)
1947 return ERR_PTR(-ENOMEM);
1948
1949 inode = sel_make_inode(dir->d_sb, S_IFDIR | S_IRUGO | S_IXUGO);
1950 if (!inode) {
1951 dput(dentry);
1952 return ERR_PTR(-ENOMEM);
1953 }
Eric Parisb77a4932010-11-23 11:40:08 -05001954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 inode->i_op = &simple_dir_inode_operations;
1956 inode->i_fop = &simple_dir_operations;
Christopher J. PeBenito0dd4ae52007-05-23 09:12:08 -04001957 inode->i_ino = ++(*ino);
James Morris40e906f2006-03-22 00:09:16 -08001958 /* directory inodes start off with i_nlink == 2 (for "." entry) */
Dave Hansend8c76e62006-09-30 23:29:04 -07001959 inc_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 d_add(dentry, inode);
James Morrisedb20fb2006-03-22 00:09:20 -08001961 /* bump link count on parent directory, too */
David Howellsce0b16d2015-02-19 10:47:02 +00001962 inc_nlink(d_inode(dir));
Eric Parisb77a4932010-11-23 11:40:08 -05001963
Al Viroa1c2aa12012-03-18 20:36:59 -04001964 return dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965}
1966
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001967#define NULL_FILE_NAME "null"
1968
David Howells920f50b2019-03-25 16:38:30 +00001969static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001971 struct selinux_fs_info *fsi;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 int ret;
1973 struct dentry *dentry;
Al Viroa1c2aa12012-03-18 20:36:59 -04001974 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 struct inode_security_struct *isec;
1976
Eric Biggerscda37122017-03-25 21:15:37 -07001977 static const struct tree_descr selinux_files[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 [SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
1979 [SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
Stephen Smalleyce9982d2005-11-08 21:34:33 -08001980 [SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 [SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
1982 [SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
1983 [SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
1984 [SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
1985 [SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
1986 [SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
1987 [SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
1988 [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
1989 [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
1990 [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
Eric Paris3f120702007-09-21 14:37:10 -04001991 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
1992 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
KaiGai Kohei11904162010-09-14 18:28:39 +09001993 [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
Eric Paris72e8c8592012-02-16 15:08:39 -05001994 [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
Andrew Perepechkof9df6452015-12-24 11:09:41 -05001995 [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
1996 S_IWUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 /* last one */ {""}
1998 };
Stephen Smalley0619f0f2018-03-20 11:59:11 -04001999
2000 ret = selinux_fs_info_create(sb);
2001 if (ret)
2002 goto err;
2003
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
2005 if (ret)
James Morris161ce452006-03-22 00:09:17 -08002006 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002008 fsi = sb->s_fs_info;
2009 fsi->bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &fsi->last_ino);
2010 if (IS_ERR(fsi->bool_dir)) {
2011 ret = PTR_ERR(fsi->bool_dir);
2012 fsi->bool_dir = NULL;
James Morris161ce452006-03-22 00:09:17 -08002013 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04002014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Eric Parisb77a4932010-11-23 11:40:08 -05002016 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
Eric Parisb77a4932010-11-23 11:40:08 -05002018 if (!dentry)
James Morris161ce452006-03-22 00:09:17 -08002019 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
Eric Parisb77a4932010-11-23 11:40:08 -05002021 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
nixiaoming7e4237f2018-08-05 17:10:36 +08002023 if (!inode) {
2024 dput(dentry);
James Morris161ce452006-03-22 00:09:17 -08002025 goto err;
nixiaoming7e4237f2018-08-05 17:10:36 +08002026 }
Eric Parisb77a4932010-11-23 11:40:08 -05002027
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002028 inode->i_ino = ++fsi->last_ino;
Casey Schaufler80788c22018-09-21 17:19:11 -07002029 isec = selinux_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 isec->sid = SECINITSID_DEVNULL;
2031 isec->sclass = SECCLASS_CHR_FILE;
Andreas Gruenbacher42059112016-11-10 22:18:27 +01002032 isec->initialized = LABEL_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033
2034 init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
2035 d_add(dentry, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002037 dentry = sel_make_dir(sb->s_root, "avc", &fsi->last_ino);
Al Viroa1c2aa12012-03-18 20:36:59 -04002038 if (IS_ERR(dentry)) {
2039 ret = PTR_ERR(dentry);
James Morris161ce452006-03-22 00:09:17 -08002040 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04002041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
2043 ret = sel_make_avc_files(dentry);
Jeff Vander Stoep66f8e2f2019-11-22 10:33:06 +01002044
2045 dentry = sel_make_dir(sb->s_root, "ss", &fsi->last_ino);
2046 if (IS_ERR(dentry)) {
2047 ret = PTR_ERR(dentry);
2048 goto err;
2049 }
2050
2051 ret = sel_make_ss_files(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 if (ret)
James Morris161ce452006-03-22 00:09:17 -08002053 goto err;
James Carterf0ee2e42007-04-04 10:11:29 -04002054
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002055 dentry = sel_make_dir(sb->s_root, "initial_contexts", &fsi->last_ino);
Al Viroa1c2aa12012-03-18 20:36:59 -04002056 if (IS_ERR(dentry)) {
2057 ret = PTR_ERR(dentry);
James Carterf0ee2e42007-04-04 10:11:29 -04002058 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04002059 }
James Carterf0ee2e42007-04-04 10:11:29 -04002060
2061 ret = sel_make_initcon_files(dentry);
2062 if (ret)
2063 goto err;
2064
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002065 fsi->class_dir = sel_make_dir(sb->s_root, "class", &fsi->last_ino);
2066 if (IS_ERR(fsi->class_dir)) {
2067 ret = PTR_ERR(fsi->class_dir);
2068 fsi->class_dir = NULL;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04002069 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04002070 }
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04002071
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002072 fsi->policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities",
2073 &fsi->last_ino);
2074 if (IS_ERR(fsi->policycap_dir)) {
2075 ret = PTR_ERR(fsi->policycap_dir);
2076 fsi->policycap_dir = NULL;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04002077 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04002078 }
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002079
Stephen Smalley02a52c52020-08-07 09:29:34 -04002080 ret = sel_make_policycap(fsi);
2081 if (ret) {
2082 pr_err("SELinux: failed to load policy capabilities\n");
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002083 goto err;
Stephen Smalley02a52c52020-08-07 09:29:34 -04002084 }
2085
Eric Parisb77a4932010-11-23 11:40:08 -05002086 return 0;
James Morris161ce452006-03-22 00:09:17 -08002087err:
peter enderborgf8b69a52018-06-12 10:09:06 +02002088 pr_err("SELinux: %s: failed while creating inodes\n",
Eric Paris744ba352008-04-17 11:52:44 -04002089 __func__);
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002090
2091 selinux_fs_info_free(sb);
2092
Eric Parisb77a4932010-11-23 11:40:08 -05002093 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094}
2095
David Howells920f50b2019-03-25 16:38:30 +00002096static int sel_get_tree(struct fs_context *fc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097{
David Howells920f50b2019-03-25 16:38:30 +00002098 return get_tree_single(fc, sel_fill_super);
2099}
2100
2101static const struct fs_context_operations sel_context_ops = {
2102 .get_tree = sel_get_tree,
2103};
2104
2105static int sel_init_fs_context(struct fs_context *fc)
2106{
2107 fc->ops = &sel_context_ops;
2108 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109}
2110
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002111static void sel_kill_sb(struct super_block *sb)
2112{
2113 selinux_fs_info_free(sb);
2114 kill_litter_super(sb);
2115}
2116
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117static struct file_system_type sel_fs_type = {
2118 .name = "selinuxfs",
David Howells920f50b2019-03-25 16:38:30 +00002119 .init_fs_context = sel_init_fs_context,
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002120 .kill_sb = sel_kill_sb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121};
2122
2123struct vfsmount *selinuxfs_mount;
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002124struct path selinux_null;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
2126static int __init init_sel_fs(void)
2127{
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002128 struct qstr null_name = QSTR_INIT(NULL_FILE_NAME,
2129 sizeof(NULL_FILE_NAME)-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 int err;
2131
Stephen Smalley6c5a6822019-12-17 09:15:10 -05002132 if (!selinux_enabled_boot)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 return 0;
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07002134
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -05002135 err = sysfs_create_mount_point(fs_kobj, "selinux");
2136 if (err)
2137 return err;
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07002138
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 err = register_filesystem(&sel_fs_type);
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07002140 if (err) {
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -05002141 sysfs_remove_mount_point(fs_kobj, "selinux");
Eric Parisb77a4932010-11-23 11:40:08 -05002142 return err;
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07002143 }
Eric Parisb77a4932010-11-23 11:40:08 -05002144
Al Viro765927b2012-06-26 21:58:53 +04002145 selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
Eric Parisb77a4932010-11-23 11:40:08 -05002146 if (IS_ERR(selinuxfs_mount)) {
peter enderborgf8b69a52018-06-12 10:09:06 +02002147 pr_err("selinuxfs: could not mount!\n");
Eric Parisb77a4932010-11-23 11:40:08 -05002148 err = PTR_ERR(selinuxfs_mount);
2149 selinuxfs_mount = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 }
Stephen Smalley0619f0f2018-03-20 11:59:11 -04002151 selinux_null.dentry = d_hash_and_lookup(selinux_null.mnt->mnt_root,
2152 &null_name);
2153 if (IS_ERR(selinux_null.dentry)) {
2154 pr_err("selinuxfs: could not lookup null!\n");
2155 err = PTR_ERR(selinux_null.dentry);
2156 selinux_null.dentry = NULL;
2157 }
Eric Parisb77a4932010-11-23 11:40:08 -05002158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return err;
2160}
2161
2162__initcall(init_sel_fs);
2163
2164#ifdef CONFIG_SECURITY_SELINUX_DISABLE
2165void exit_sel_fs(void)
2166{
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -05002167 sysfs_remove_mount_point(fs_kobj, "selinux");
Stephen Smalleyfd40ffc2018-04-09 14:36:05 -04002168 dput(selinux_null.dentry);
Tim Chen423e0ab2011-07-19 09:32:38 -07002169 kern_unmount(selinuxfs_mount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 unregister_filesystem(&sel_fs_type);
2171}
2172#endif