blob: 98492755adbf387a34d82a29b8baadffd9168e2e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* Updated: Karl MacMillan <kmacmillan@tresys.com>
2 *
Eric Paris18729812008-04-17 14:15:45 -04003 * Added conditional policy language extensions
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Paul Moore82c21bf2011-08-01 11:10:33 +00005 * Updated: Hewlett-Packard <paul@paul-moore.com>
Paul Moore3bb56b22008-01-29 08:38:19 -05006 *
Eric Paris18729812008-04-17 14:15:45 -04007 * Added support for the policy capability bitmap
Paul Moore3bb56b22008-01-29 08:38:19 -05008 *
9 * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
11 * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
12 * This program is free software; you can redistribute it and/or modify
Eric Paris18729812008-04-17 14:15:45 -040013 * it under the terms of the GNU General Public License as published by
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 * the Free Software Foundation, version 2.
15 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/kernel.h>
18#include <linux/pagemap.h>
19#include <linux/slab.h>
20#include <linux/vmalloc.h>
21#include <linux/fs.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
Ingo Molnarbb0030792006-03-22 00:09:14 -080044static DEFINE_MUTEX(sel_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46/* global data for booleans */
Eric Paris18729812008-04-17 14:15:45 -040047static struct dentry *bool_dir;
48static int bool_num;
Stephen Smalleyd313f94832007-11-26 11:12:53 -050049static char **bool_pending_names;
Eric Paris18729812008-04-17 14:15:45 -040050static int *bool_pending_values;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -040052/* global data for classes */
Eric Paris18729812008-04-17 14:15:45 -040053static struct dentry *class_dir;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -040054static unsigned long last_class_ino;
55
Eric Pariscee74f42010-10-13 17:50:25 -040056static char policy_opened;
57
Paul Moore3bb56b22008-01-29 08:38:19 -050058/* global data for policy capabilities */
Eric Paris18729812008-04-17 14:15:45 -040059static struct dentry *policycap_dir;
Paul Moore3bb56b22008-01-29 08:38:19 -050060
Linus Torvalds1da177e2005-04-16 15:20:36 -070061enum sel_inos {
62 SEL_ROOT_INO = 2,
63 SEL_LOAD, /* load policy */
64 SEL_ENFORCE, /* get or set enforcing status */
65 SEL_CONTEXT, /* validate context */
66 SEL_ACCESS, /* compute access decision */
67 SEL_CREATE, /* compute create labeling decision */
68 SEL_RELABEL, /* compute relabeling decision */
69 SEL_USER, /* compute reachable user contexts */
70 SEL_POLICYVERS, /* return policy version for this kernel */
71 SEL_COMMIT_BOOLS, /* commit new boolean values */
72 SEL_MLS, /* return if MLS policy is enabled */
73 SEL_DISABLE, /* disable SELinux until next reboot */
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 SEL_MEMBER, /* compute polyinstantiation membership decision */
75 SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
James Morris4e5ab4c2006-06-09 00:33:33 -070076 SEL_COMPAT_NET, /* whether to use old compat network packet controls */
Eric Paris3f120702007-09-21 14:37:10 -040077 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
78 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
KaiGai Kohei11904162010-09-14 18:28:39 +090079 SEL_STATUS, /* export current status using mmap() */
Eric Pariscee74f42010-10-13 17:50:25 -040080 SEL_POLICY, /* allow userspace to read the in kernel policy */
Andrew Perepechkof9df6452015-12-24 11:09:41 -050081 SEL_VALIDATE_TRANS, /* compute validatetrans decision */
James Carter6174eaf2007-04-04 16:18:39 -040082 SEL_INO_NEXT, /* The next inode number to use */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84
James Carter6174eaf2007-04-04 16:18:39 -040085static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
86
Paul Moore3bb56b22008-01-29 08:38:19 -050087#define SEL_INITCON_INO_OFFSET 0x01000000
88#define SEL_BOOL_INO_OFFSET 0x02000000
89#define SEL_CLASS_INO_OFFSET 0x04000000
90#define SEL_POLICYCAP_INO_OFFSET 0x08000000
91#define SEL_INO_MASK 0x00ffffff
James Carterf0ee2e42007-04-04 10:11:29 -040092
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#define TMPBUFLEN 12
94static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
95 size_t count, loff_t *ppos)
96{
97 char tmpbuf[TMPBUFLEN];
98 ssize_t length;
99
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500100 length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
101 is_enforcing(&selinux_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
103}
104
105#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris18729812008-04-17 14:15:45 -0400106static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 size_t count, loff_t *ppos)
108
109{
Eric Parisb77a4932010-11-23 11:40:08 -0500110 char *page = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 ssize_t length;
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500112 int old_value, new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Davi Arnautbfd51622005-10-30 14:59:24 -0800114 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -0500115 return -ENOMEM;
Eric Parisb77a4932010-11-23 11:40:08 -0500116
117 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -0500118 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -0500119 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -0500120
Al Viro8365a712015-12-24 00:08:06 -0500121 page = memdup_user_nul(buf, count);
122 if (IS_ERR(page))
123 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125 length = -EINVAL;
126 if (sscanf(page, "%d", &new_value) != 1)
127 goto out;
128
Stephen Smalleyea49d10ee2016-11-18 09:30:38 -0500129 new_value = !!new_value;
130
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500131 old_value = is_enforcing(&selinux_state);
132
133 if (new_value != old_value) {
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500134 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
135 SECCLASS_SECURITY, SECURITY__SETENFORCE,
136 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 if (length)
138 goto out;
Steve Grubbaf601e42006-01-04 14:08:39 +0000139 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
Eric Paris4746ec52008-01-08 10:06:53 -0500140 "enforcing=%d old_enforcing=%d auid=%u ses=%u",
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500141 new_value, old_value,
Eric W. Biederman581abc02012-08-20 00:09:36 -0700142 from_kuid(&init_user_ns, audit_get_loginuid(current)),
Eric Paris4746ec52008-01-08 10:06:53 -0500143 audit_get_sessionid(current));
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500144 set_enforcing(&selinux_state, new_value);
145 if (new_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 avc_ss_reset(0);
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500147 selnl_notify_setenforce(new_value);
148 selinux_status_update_setenforce(&selinux_state,
149 new_value);
150 if (!new_value)
Daniel Jurgens8f408ab2017-05-19 15:48:53 +0300151 call_lsm_notifier(LSM_POLICY_CHANGE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
153 length = count;
154out:
Al Viro8365a712015-12-24 00:08:06 -0500155 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 return length;
157}
158#else
159#define sel_write_enforce NULL
160#endif
161
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800162static const struct file_operations sel_enforce_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 .read = sel_read_enforce,
164 .write = sel_write_enforce,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200165 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166};
167
Eric Paris3f120702007-09-21 14:37:10 -0400168static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
169 size_t count, loff_t *ppos)
170{
171 char tmpbuf[TMPBUFLEN];
172 ssize_t length;
Al Viro496ad9a2013-01-23 17:07:38 -0500173 ino_t ino = file_inode(filp)->i_ino;
Eric Paris3f120702007-09-21 14:37:10 -0400174 int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500175 security_get_reject_unknown(&selinux_state) :
176 !security_get_allow_unknown(&selinux_state);
Eric Paris3f120702007-09-21 14:37:10 -0400177
178 length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
179 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
180}
181
182static const struct file_operations sel_handle_unknown_ops = {
183 .read = sel_read_handle_unknown,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200184 .llseek = generic_file_llseek,
Eric Paris3f120702007-09-21 14:37:10 -0400185};
186
KaiGai Kohei11904162010-09-14 18:28:39 +0900187static int sel_open_handle_status(struct inode *inode, struct file *filp)
188{
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500189 struct page *status = selinux_kernel_status_page(&selinux_state);
KaiGai Kohei11904162010-09-14 18:28:39 +0900190
191 if (!status)
192 return -ENOMEM;
193
194 filp->private_data = status;
195
196 return 0;
197}
198
199static ssize_t sel_read_handle_status(struct file *filp, char __user *buf,
200 size_t count, loff_t *ppos)
201{
202 struct page *status = filp->private_data;
203
204 BUG_ON(!status);
205
206 return simple_read_from_buffer(buf, count, ppos,
207 page_address(status),
208 sizeof(struct selinux_kernel_status));
209}
210
211static int sel_mmap_handle_status(struct file *filp,
212 struct vm_area_struct *vma)
213{
214 struct page *status = filp->private_data;
215 unsigned long size = vma->vm_end - vma->vm_start;
216
217 BUG_ON(!status);
218
219 /* only allows one page from the head */
220 if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
221 return -EIO;
222 /* disallow writable mapping */
223 if (vma->vm_flags & VM_WRITE)
224 return -EPERM;
225 /* disallow mprotect() turns it into writable */
226 vma->vm_flags &= ~VM_MAYWRITE;
227
228 return remap_pfn_range(vma, vma->vm_start,
229 page_to_pfn(status),
230 size, vma->vm_page_prot);
231}
232
233static const struct file_operations sel_handle_status_ops = {
234 .open = sel_open_handle_status,
235 .read = sel_read_handle_status,
236 .mmap = sel_mmap_handle_status,
237 .llseek = generic_file_llseek,
238};
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris18729812008-04-17 14:15:45 -0400241static ssize_t sel_write_disable(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 size_t count, loff_t *ppos)
243
244{
Al Viro8365a712015-12-24 00:08:06 -0500245 char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 ssize_t length;
247 int new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Davi Arnautbfd51622005-10-30 14:59:24 -0800249 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -0500250 return -ENOMEM;
Eric Parisb77a4932010-11-23 11:40:08 -0500251
252 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -0500253 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -0500254 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -0500255
Al Viro8365a712015-12-24 00:08:06 -0500256 page = memdup_user_nul(buf, count);
257 if (IS_ERR(page))
258 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 length = -EINVAL;
261 if (sscanf(page, "%d", &new_value) != 1)
262 goto out;
263
264 if (new_value) {
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500265 length = selinux_disable(&selinux_state);
Eric Parisb77a4932010-11-23 11:40:08 -0500266 if (length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 goto out;
Steve Grubbaf601e42006-01-04 14:08:39 +0000268 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
Eric Paris4746ec52008-01-08 10:06:53 -0500269 "selinux=0 auid=%u ses=%u",
Eric W. Biederman581abc02012-08-20 00:09:36 -0700270 from_kuid(&init_user_ns, audit_get_loginuid(current)),
Eric Paris4746ec52008-01-08 10:06:53 -0500271 audit_get_sessionid(current));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
273
274 length = count;
275out:
Al Viro8365a712015-12-24 00:08:06 -0500276 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return length;
278}
279#else
280#define sel_write_disable NULL
281#endif
282
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800283static const struct file_operations sel_disable_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 .write = sel_write_disable,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200285 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286};
287
288static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
Eric Paris18729812008-04-17 14:15:45 -0400289 size_t count, loff_t *ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 char tmpbuf[TMPBUFLEN];
292 ssize_t length;
293
294 length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);
295 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
296}
297
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800298static const struct file_operations sel_policyvers_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 .read = sel_read_policyvers,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200300 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301};
302
303/* declaration for sel_write_load */
304static int sel_make_bools(void);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400305static int sel_make_classes(void);
Paul Moore3bb56b22008-01-29 08:38:19 -0500306static int sel_make_policycap(void);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400307
308/* declaration for sel_make_class_dirs */
Al Viroa1c2aa12012-03-18 20:36:59 -0400309static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400310 unsigned long *ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312static ssize_t sel_read_mls(struct file *filp, char __user *buf,
313 size_t count, loff_t *ppos)
314{
315 char tmpbuf[TMPBUFLEN];
316 ssize_t length;
317
Guido Trentalancia0719aaf2010-02-03 16:40:20 +0100318 length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500319 security_mls_enabled(&selinux_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
321}
322
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800323static const struct file_operations sel_mls_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 .read = sel_read_mls,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200325 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326};
327
Eric Pariscee74f42010-10-13 17:50:25 -0400328struct policy_load_memory {
329 size_t len;
330 void *data;
331};
332
333static int sel_open_policy(struct inode *inode, struct file *filp)
334{
335 struct policy_load_memory *plm = NULL;
336 int rc;
337
338 BUG_ON(filp->private_data);
339
340 mutex_lock(&sel_mutex);
341
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500342 rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
343 SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
Eric Pariscee74f42010-10-13 17:50:25 -0400344 if (rc)
345 goto err;
346
347 rc = -EBUSY;
348 if (policy_opened)
349 goto err;
350
351 rc = -ENOMEM;
352 plm = kzalloc(sizeof(*plm), GFP_KERNEL);
353 if (!plm)
354 goto err;
355
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500356 if (i_size_read(inode) != security_policydb_len(&selinux_state)) {
Al Viro59551022016-01-22 15:40:57 -0500357 inode_lock(inode);
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500358 i_size_write(inode, security_policydb_len(&selinux_state));
Al Viro59551022016-01-22 15:40:57 -0500359 inode_unlock(inode);
Eric Pariscee74f42010-10-13 17:50:25 -0400360 }
361
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500362 rc = security_read_policy(&selinux_state, &plm->data, &plm->len);
Eric Pariscee74f42010-10-13 17:50:25 -0400363 if (rc)
364 goto err;
365
366 policy_opened = 1;
367
368 filp->private_data = plm;
369
370 mutex_unlock(&sel_mutex);
371
372 return 0;
373err:
374 mutex_unlock(&sel_mutex);
375
376 if (plm)
377 vfree(plm->data);
378 kfree(plm);
379 return rc;
380}
381
382static int sel_release_policy(struct inode *inode, struct file *filp)
383{
384 struct policy_load_memory *plm = filp->private_data;
385
386 BUG_ON(!plm);
387
388 policy_opened = 0;
389
390 vfree(plm->data);
391 kfree(plm);
392
393 return 0;
394}
395
396static ssize_t sel_read_policy(struct file *filp, char __user *buf,
397 size_t count, loff_t *ppos)
398{
399 struct policy_load_memory *plm = filp->private_data;
400 int ret;
401
402 mutex_lock(&sel_mutex);
403
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500404 ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
405 SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
Eric Pariscee74f42010-10-13 17:50:25 -0400406 if (ret)
407 goto out;
408
409 ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
410out:
411 mutex_unlock(&sel_mutex);
412 return ret;
413}
414
Dave Jiang11bac802017-02-24 14:56:41 -0800415static int sel_mmap_policy_fault(struct vm_fault *vmf)
Eric Paris845ca302010-10-13 17:50:31 -0400416{
Dave Jiang11bac802017-02-24 14:56:41 -0800417 struct policy_load_memory *plm = vmf->vma->vm_file->private_data;
Eric Paris845ca302010-10-13 17:50:31 -0400418 unsigned long offset;
419 struct page *page;
420
421 if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
422 return VM_FAULT_SIGBUS;
423
424 offset = vmf->pgoff << PAGE_SHIFT;
425 if (offset >= roundup(plm->len, PAGE_SIZE))
426 return VM_FAULT_SIGBUS;
427
428 page = vmalloc_to_page(plm->data + offset);
429 get_page(page);
430
431 vmf->page = page;
432
433 return 0;
434}
435
Kirill A. Shutemov7cbea8d2015-09-09 15:39:26 -0700436static const struct vm_operations_struct sel_mmap_policy_ops = {
Eric Paris845ca302010-10-13 17:50:31 -0400437 .fault = sel_mmap_policy_fault,
438 .page_mkwrite = sel_mmap_policy_fault,
439};
440
James Morrisad3fa082011-08-30 10:50:12 +1000441static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
Eric Paris845ca302010-10-13 17:50:31 -0400442{
443 if (vma->vm_flags & VM_SHARED) {
444 /* do not allow mprotect to make mapping writable */
445 vma->vm_flags &= ~VM_MAYWRITE;
446
447 if (vma->vm_flags & VM_WRITE)
448 return -EACCES;
449 }
450
Konstantin Khlebnikov314e51b2012-10-08 16:29:02 -0700451 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
Eric Paris845ca302010-10-13 17:50:31 -0400452 vma->vm_ops = &sel_mmap_policy_ops;
453
454 return 0;
455}
456
Eric Pariscee74f42010-10-13 17:50:25 -0400457static const struct file_operations sel_policy_ops = {
458 .open = sel_open_policy,
459 .read = sel_read_policy,
Eric Paris845ca302010-10-13 17:50:31 -0400460 .mmap = sel_mmap_policy,
Eric Pariscee74f42010-10-13 17:50:25 -0400461 .release = sel_release_policy,
Eric Paris47a93a52012-02-16 15:08:39 -0500462 .llseek = generic_file_llseek,
Eric Pariscee74f42010-10-13 17:50:25 -0400463};
464
Eric Paris18729812008-04-17 14:15:45 -0400465static ssize_t sel_write_load(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 size_t count, loff_t *ppos)
467
468{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 ssize_t length;
470 void *data = NULL;
471
Ingo Molnarbb0030792006-03-22 00:09:14 -0800472 mutex_lock(&sel_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500474 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
475 SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 if (length)
477 goto out;
478
Eric Parisb77a4932010-11-23 11:40:08 -0500479 /* No partial writes. */
480 length = -EINVAL;
481 if (*ppos != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Eric Parisb77a4932010-11-23 11:40:08 -0500484 length = -EFBIG;
485 if (count > 64 * 1024 * 1024)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 goto out;
Eric Parisb77a4932010-11-23 11:40:08 -0500487
488 length = -ENOMEM;
489 data = vmalloc(count);
490 if (!data)
491 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 length = -EFAULT;
494 if (copy_from_user(data, buf, count) != 0)
495 goto out;
496
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500497 length = security_load_policy(&selinux_state, data, count);
Gary Tierney4262fb52017-01-09 10:07:31 -0500498 if (length) {
499 pr_warn_ratelimited("SELinux: failed to load policy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 goto out;
Gary Tierney4262fb52017-01-09 10:07:31 -0500501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Eric Parisb77a4932010-11-23 11:40:08 -0500503 length = sel_make_bools();
Gary Tierney4262fb52017-01-09 10:07:31 -0500504 if (length) {
505 pr_err("SELinux: failed to load policy booleans\n");
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400506 goto out1;
Gary Tierney4262fb52017-01-09 10:07:31 -0500507 }
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400508
Eric Parisb77a4932010-11-23 11:40:08 -0500509 length = sel_make_classes();
Gary Tierney4262fb52017-01-09 10:07:31 -0500510 if (length) {
511 pr_err("SELinux: failed to load policy classes\n");
Paul Moore3bb56b22008-01-29 08:38:19 -0500512 goto out1;
Gary Tierney4262fb52017-01-09 10:07:31 -0500513 }
Paul Moore3bb56b22008-01-29 08:38:19 -0500514
Eric Parisb77a4932010-11-23 11:40:08 -0500515 length = sel_make_policycap();
Gary Tierney4262fb52017-01-09 10:07:31 -0500516 if (length) {
517 pr_err("SELinux: failed to load policy capabilities\n");
Eric Parisb77a4932010-11-23 11:40:08 -0500518 goto out1;
Gary Tierney4262fb52017-01-09 10:07:31 -0500519 }
Eric Parisb77a4932010-11-23 11:40:08 -0500520
521 length = count;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -0400522
523out1:
Steve Grubbaf601e42006-01-04 14:08:39 +0000524 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
Eric Paris4746ec52008-01-08 10:06:53 -0500525 "policy loaded auid=%u ses=%u",
Eric W. Biederman581abc02012-08-20 00:09:36 -0700526 from_kuid(&init_user_ns, audit_get_loginuid(current)),
Eric Paris4746ec52008-01-08 10:06:53 -0500527 audit_get_sessionid(current));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528out:
Ingo Molnarbb0030792006-03-22 00:09:14 -0800529 mutex_unlock(&sel_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 vfree(data);
531 return length;
532}
533
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800534static const struct file_operations sel_load_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 .write = sel_write_load,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200536 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537};
538
Eric Paris18729812008-04-17 14:15:45 -0400539static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
Eric Parisb77a4932010-11-23 11:40:08 -0500541 char *canon = NULL;
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800542 u32 sid, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 ssize_t length;
544
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500545 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
546 SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500548 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500550 length = security_context_to_sid(&selinux_state, buf, size,
551 &sid, GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500552 if (length)
553 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500555 length = security_sid_to_context(&selinux_state, sid, &canon, &len);
Eric Parisb77a4932010-11-23 11:40:08 -0500556 if (length)
557 goto out;
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800558
Eric Parisb77a4932010-11-23 11:40:08 -0500559 length = -ERANGE;
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800560 if (len > SIMPLE_TRANSACTION_LIMIT) {
Eric Paris744ba352008-04-17 11:52:44 -0400561 printk(KERN_ERR "SELinux: %s: context size (%u) exceeds "
562 "payload max\n", __func__, len);
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800563 goto out;
564 }
565
566 memcpy(buf, canon, len);
567 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568out:
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800569 kfree(canon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 return length;
571}
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
574 size_t count, loff_t *ppos)
575{
576 char tmpbuf[TMPBUFLEN];
577 ssize_t length;
578
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500579 length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_state.checkreqprot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
581}
582
Eric Paris18729812008-04-17 14:15:45 -0400583static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 size_t count, loff_t *ppos)
585{
Al Viro8365a712015-12-24 00:08:06 -0500586 char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 ssize_t length;
588 unsigned int new_value;
589
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500590 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
591 SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
592 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (length)
Al Viro8365a712015-12-24 00:08:06 -0500594 return length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Davi Arnautbfd51622005-10-30 14:59:24 -0800596 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -0500597 return -ENOMEM;
Eric Parisb77a4932010-11-23 11:40:08 -0500598
599 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -0500600 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -0500601 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -0500602
Al Viro8365a712015-12-24 00:08:06 -0500603 page = memdup_user_nul(buf, count);
604 if (IS_ERR(page))
605 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 length = -EINVAL;
608 if (sscanf(page, "%u", &new_value) != 1)
609 goto out;
610
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500611 selinux_state.checkreqprot = new_value ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 length = count;
613out:
Al Viro8365a712015-12-24 00:08:06 -0500614 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return length;
616}
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800617static const struct file_operations sel_checkreqprot_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 .read = sel_read_checkreqprot,
619 .write = sel_write_checkreqprot,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200620 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621};
622
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500623static ssize_t sel_write_validatetrans(struct file *file,
624 const char __user *buf,
625 size_t count, loff_t *ppos)
626{
627 char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
628 char *req = NULL;
629 u32 osid, nsid, tsid;
630 u16 tclass;
631 int rc;
632
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500633 rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
634 SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500635 if (rc)
636 goto out;
637
638 rc = -ENOMEM;
639 if (count >= PAGE_SIZE)
640 goto out;
641
642 /* No partial writes. */
643 rc = -EINVAL;
644 if (*ppos != 0)
645 goto out;
646
Al Viro0b884d22017-05-13 18:12:07 -0400647 req = memdup_user_nul(buf, count);
648 if (IS_ERR(req)) {
649 rc = PTR_ERR(req);
650 req = NULL;
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500651 goto out;
Al Viro0b884d22017-05-13 18:12:07 -0400652 }
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500653
654 rc = -ENOMEM;
655 oldcon = kzalloc(count + 1, GFP_KERNEL);
656 if (!oldcon)
657 goto out;
658
659 newcon = kzalloc(count + 1, GFP_KERNEL);
660 if (!newcon)
661 goto out;
662
663 taskcon = kzalloc(count + 1, GFP_KERNEL);
664 if (!taskcon)
665 goto out;
666
667 rc = -EINVAL;
668 if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
669 goto out;
670
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500671 rc = security_context_str_to_sid(&selinux_state, oldcon, &osid,
672 GFP_KERNEL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500673 if (rc)
674 goto out;
675
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500676 rc = security_context_str_to_sid(&selinux_state, newcon, &nsid,
677 GFP_KERNEL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500678 if (rc)
679 goto out;
680
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500681 rc = security_context_str_to_sid(&selinux_state, taskcon, &tsid,
682 GFP_KERNEL);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500683 if (rc)
684 goto out;
685
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500686 rc = security_validate_transition_user(&selinux_state, osid, nsid,
687 tsid, tclass);
Andrew Perepechkof9df6452015-12-24 11:09:41 -0500688 if (!rc)
689 rc = count;
690out:
691 kfree(req);
692 kfree(oldcon);
693 kfree(newcon);
694 kfree(taskcon);
695 return rc;
696}
697
698static const struct file_operations sel_transition_ops = {
699 .write = sel_write_validatetrans,
700 .llseek = generic_file_llseek,
701};
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703/*
704 * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
705 */
Eric Paris18729812008-04-17 14:15:45 -0400706static ssize_t sel_write_access(struct file *file, char *buf, size_t size);
707static ssize_t sel_write_create(struct file *file, char *buf, size_t size);
708static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size);
709static ssize_t sel_write_user(struct file *file, char *buf, size_t size);
710static ssize_t sel_write_member(struct file *file, char *buf, size_t size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712static ssize_t (*write_op[])(struct file *, char *, size_t) = {
713 [SEL_ACCESS] = sel_write_access,
714 [SEL_CREATE] = sel_write_create,
715 [SEL_RELABEL] = sel_write_relabel,
716 [SEL_USER] = sel_write_user,
717 [SEL_MEMBER] = sel_write_member,
Stephen Smalleyce9982d2005-11-08 21:34:33 -0800718 [SEL_CONTEXT] = sel_write_context,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719};
720
721static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
722{
Al Viro496ad9a2013-01-23 17:07:38 -0500723 ino_t ino = file_inode(file)->i_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 char *data;
725 ssize_t rv;
726
Nicolas Kaiser6e20a642006-01-06 00:11:22 -0800727 if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return -EINVAL;
729
730 data = simple_transaction_get(file, buf, size);
731 if (IS_ERR(data))
732 return PTR_ERR(data);
733
Eric Paris18729812008-04-17 14:15:45 -0400734 rv = write_op[ino](file, data, size);
735 if (rv > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 simple_transaction_set(file, rv);
737 rv = size;
738 }
739 return rv;
740}
741
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800742static const struct file_operations transaction_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 .write = selinux_transaction_write,
744 .read = simple_transaction_read,
745 .release = simple_transaction_release,
Arnd Bergmann57a62c22010-07-07 23:40:10 +0200746 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747};
748
749/*
750 * payload - write methods
751 * If the method has a response, the response should be put in buf,
752 * and the length returned. Otherwise return 0 or and -error.
753 */
754
Eric Paris18729812008-04-17 14:15:45 -0400755static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Eric Parisb77a4932010-11-23 11:40:08 -0500757 char *scon = NULL, *tcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 u32 ssid, tsid;
759 u16 tclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 struct av_decision avd;
761 ssize_t length;
762
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500763 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
764 SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500766 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800769 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (!scon)
Eric Parisb77a4932010-11-23 11:40:08 -0500771 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Eric Parisb77a4932010-11-23 11:40:08 -0500773 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800774 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (!tcon)
776 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
778 length = -EINVAL;
Stephen Smalley19439d02010-01-14 17:28:10 -0500779 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
Eric Parisb77a4932010-11-23 11:40:08 -0500780 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500782 length = security_context_str_to_sid(&selinux_state, scon, &ssid,
783 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500784 if (length)
785 goto out;
786
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500787 length = security_context_str_to_sid(&selinux_state, tcon, &tsid,
788 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500789 if (length)
790 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500792 security_compute_av_user(&selinux_state, ssid, tsid, tclass, &avd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
KaiGai Kohei8a6f83a2009-04-01 10:07:57 +0900795 "%x %x %x %x %u %x",
Eric Parisf1c63812009-02-12 14:50:54 -0500796 avd.allowed, 0xffffffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 avd.auditallow, avd.auditdeny,
KaiGai Kohei8a6f83a2009-04-01 10:07:57 +0900798 avd.seqno, avd.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799out:
Eric Parisb77a4932010-11-23 11:40:08 -0500800 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 kfree(scon);
802 return length;
803}
804
Eric Paris18729812008-04-17 14:15:45 -0400805static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
Eric Parisb77a4932010-11-23 11:40:08 -0500807 char *scon = NULL, *tcon = NULL;
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100808 char *namebuf = NULL, *objname = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 u32 ssid, tsid, newsid;
810 u16 tclass;
811 ssize_t length;
Eric Parisb77a4932010-11-23 11:40:08 -0500812 char *newcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 u32 len;
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100814 int nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500816 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
817 SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
818 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500820 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800823 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (!scon)
Eric Parisb77a4932010-11-23 11:40:08 -0500825 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Eric Parisb77a4932010-11-23 11:40:08 -0500827 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800828 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (!tcon)
830 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100832 length = -ENOMEM;
833 namebuf = kzalloc(size + 1, GFP_KERNEL);
834 if (!namebuf)
Eric Parisb77a4932010-11-23 11:40:08 -0500835 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100837 length = -EINVAL;
838 nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
839 if (nargs < 3 || nargs > 4)
840 goto out;
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400841 if (nargs == 4) {
842 /*
843 * If and when the name of new object to be queried contains
844 * either whitespace or multibyte characters, they shall be
845 * encoded based on the percentage-encoding rule.
846 * If not encoded, the sscanf logic picks up only left-half
847 * of the supplied name; splitted by a whitespace unexpectedly.
848 */
849 char *r, *w;
850 int c1, c2;
851
852 r = w = namebuf;
853 do {
854 c1 = *r++;
855 if (c1 == '+')
856 c1 = ' ';
857 else if (c1 == '%') {
Andy Shevchenkoaf7ff2c2011-11-15 15:11:41 -0800858 c1 = hex_to_bin(*r++);
859 if (c1 < 0)
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400860 goto out;
Andy Shevchenkoaf7ff2c2011-11-15 15:11:41 -0800861 c2 = hex_to_bin(*r++);
862 if (c2 < 0)
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400863 goto out;
864 c1 = (c1 << 4) | c2;
865 }
866 *w++ = c1;
867 } while (c1 != '\0');
868
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100869 objname = namebuf;
Kohei Kaigai0f7e4c32011-05-26 14:59:25 -0400870 }
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100871
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500872 length = security_context_str_to_sid(&selinux_state, scon, &ssid,
873 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500874 if (length)
875 goto out;
876
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500877 length = security_context_str_to_sid(&selinux_state, tcon, &tsid,
878 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500879 if (length)
880 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500882 length = security_transition_sid_user(&selinux_state, ssid, tsid,
883 tclass, objname, &newsid);
Eric Parisb77a4932010-11-23 11:40:08 -0500884 if (length)
885 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500887 length = security_sid_to_context(&selinux_state, newsid, &newcon,
888 &len);
Eric Parisb77a4932010-11-23 11:40:08 -0500889 if (length)
890 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Eric Parisb77a4932010-11-23 11:40:08 -0500892 length = -ERANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 if (len > SIMPLE_TRANSACTION_LIMIT) {
Eric Paris744ba352008-04-17 11:52:44 -0400894 printk(KERN_ERR "SELinux: %s: context size (%u) exceeds "
895 "payload max\n", __func__, len);
Eric Parisb77a4932010-11-23 11:40:08 -0500896 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
898
899 memcpy(buf, newcon, len);
900 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901out:
Eric Parisb77a4932010-11-23 11:40:08 -0500902 kfree(newcon);
Kohei Kaigaif50a3ec2011-04-01 15:39:26 +0100903 kfree(namebuf);
Eric Parisb77a4932010-11-23 11:40:08 -0500904 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 kfree(scon);
906 return length;
907}
908
Eric Paris18729812008-04-17 14:15:45 -0400909static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
Eric Parisb77a4932010-11-23 11:40:08 -0500911 char *scon = NULL, *tcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 u32 ssid, tsid, newsid;
913 u16 tclass;
914 ssize_t length;
Eric Parisb77a4932010-11-23 11:40:08 -0500915 char *newcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 u32 len;
917
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500918 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
919 SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
920 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -0500922 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800925 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 if (!scon)
Eric Parisb77a4932010-11-23 11:40:08 -0500927 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Eric Parisb77a4932010-11-23 11:40:08 -0500929 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800930 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if (!tcon)
932 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 length = -EINVAL;
935 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
Eric Parisb77a4932010-11-23 11:40:08 -0500936 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500938 length = security_context_str_to_sid(&selinux_state, scon, &ssid,
939 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500940 if (length)
941 goto out;
942
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500943 length = security_context_str_to_sid(&selinux_state, tcon, &tsid,
944 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -0500945 if (length)
946 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500948 length = security_change_sid(&selinux_state, ssid, tsid, tclass,
949 &newsid);
Eric Parisb77a4932010-11-23 11:40:08 -0500950 if (length)
951 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Stephen Smalleyaa8e7122018-03-01 18:48:02 -0500953 length = security_sid_to_context(&selinux_state, newsid, &newcon,
954 &len);
Eric Parisb77a4932010-11-23 11:40:08 -0500955 if (length)
956 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Eric Parisb77a4932010-11-23 11:40:08 -0500958 length = -ERANGE;
959 if (len > SIMPLE_TRANSACTION_LIMIT)
960 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 memcpy(buf, newcon, len);
963 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964out:
Eric Parisb77a4932010-11-23 11:40:08 -0500965 kfree(newcon);
966 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 kfree(scon);
968 return length;
969}
970
Eric Paris18729812008-04-17 14:15:45 -0400971static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
Eric Parisb77a4932010-11-23 11:40:08 -0500973 char *con = NULL, *user = NULL, *ptr;
974 u32 sid, *sids = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 ssize_t length;
976 char *newcon;
977 int i, rc;
978 u32 len, nsids;
979
Stephen Smalleybe0554c2017-01-09 10:07:31 -0500980 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
981 SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
982 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (length)
Justin P. Mattock6eab04a2011-04-08 19:49:08 -0700984 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800987 con = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (!con)
Justin P. Mattock6eab04a2011-04-08 19:49:08 -0700989 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Eric Parisb77a4932010-11-23 11:40:08 -0500991 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +0800992 user = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 if (!user)
994 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 length = -EINVAL;
997 if (sscanf(buf, "%s %s", con, user) != 2)
Eric Parisb77a4932010-11-23 11:40:08 -0500998 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001000 length = security_context_str_to_sid(&selinux_state, con, &sid,
1001 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001002 if (length)
1003 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001005 length = security_get_user_sids(&selinux_state, sid, user, &sids,
1006 &nsids);
Eric Parisb77a4932010-11-23 11:40:08 -05001007 if (length)
1008 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010 length = sprintf(buf, "%u", nsids) + 1;
1011 ptr = buf + length;
1012 for (i = 0; i < nsids; i++) {
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001013 rc = security_sid_to_context(&selinux_state, sids[i],
1014 &newcon, &len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (rc) {
1016 length = rc;
Eric Parisb77a4932010-11-23 11:40:08 -05001017 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 }
1019 if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
1020 kfree(newcon);
1021 length = -ERANGE;
Eric Parisb77a4932010-11-23 11:40:08 -05001022 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 }
1024 memcpy(ptr, newcon, len);
1025 kfree(newcon);
1026 ptr += len;
1027 length += len;
1028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029out:
Eric Parisb77a4932010-11-23 11:40:08 -05001030 kfree(sids);
1031 kfree(user);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 kfree(con);
1033 return length;
1034}
1035
Eric Paris18729812008-04-17 14:15:45 -04001036static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
Eric Parisb77a4932010-11-23 11:40:08 -05001038 char *scon = NULL, *tcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 u32 ssid, tsid, newsid;
1040 u16 tclass;
1041 ssize_t length;
Eric Parisb77a4932010-11-23 11:40:08 -05001042 char *newcon = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 u32 len;
1044
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001045 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
1046 SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
1047 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 if (length)
Eric Parisb77a4932010-11-23 11:40:08 -05001049 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001052 scon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (!scon)
Justin P. Mattock6eab04a2011-04-08 19:49:08 -07001054 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Eric Parisb77a4932010-11-23 11:40:08 -05001056 length = -ENOMEM;
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001057 tcon = kzalloc(size + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 if (!tcon)
1059 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061 length = -EINVAL;
1062 if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
Eric Parisb77a4932010-11-23 11:40:08 -05001063 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001065 length = security_context_str_to_sid(&selinux_state, scon, &ssid,
1066 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001067 if (length)
1068 goto out;
1069
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001070 length = security_context_str_to_sid(&selinux_state, tcon, &tsid,
1071 GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001072 if (length)
1073 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001075 length = security_member_sid(&selinux_state, ssid, tsid, tclass,
1076 &newsid);
Eric Parisb77a4932010-11-23 11:40:08 -05001077 if (length)
1078 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001080 length = security_sid_to_context(&selinux_state, newsid, &newcon,
1081 &len);
Eric Parisb77a4932010-11-23 11:40:08 -05001082 if (length)
1083 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Eric Parisb77a4932010-11-23 11:40:08 -05001085 length = -ERANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 if (len > SIMPLE_TRANSACTION_LIMIT) {
Eric Paris744ba352008-04-17 11:52:44 -04001087 printk(KERN_ERR "SELinux: %s: context size (%u) exceeds "
1088 "payload max\n", __func__, len);
Eric Parisb77a4932010-11-23 11:40:08 -05001089 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
1091
1092 memcpy(buf, newcon, len);
1093 length = len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094out:
Eric Parisb77a4932010-11-23 11:40:08 -05001095 kfree(newcon);
1096 kfree(tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 kfree(scon);
1098 return length;
1099}
1100
1101static struct inode *sel_make_inode(struct super_block *sb, int mode)
1102{
1103 struct inode *ret = new_inode(sb);
1104
1105 if (ret) {
1106 ret->i_mode = mode;
Deepa Dinamani078cd822016-09-14 07:48:04 -07001107 ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
1109 return ret;
1110}
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112static ssize_t sel_read_bool(struct file *filep, char __user *buf,
1113 size_t count, loff_t *ppos)
1114{
1115 char *page = NULL;
1116 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 ssize_t ret;
1118 int cur_enforcing;
Al Viro496ad9a2013-01-23 17:07:38 -05001119 unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001120 const char *name = filep->f_path.dentry->d_name.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Ingo Molnarbb0030792006-03-22 00:09:14 -08001122 mutex_lock(&sel_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Eric Parisb77a4932010-11-23 11:40:08 -05001124 ret = -EINVAL;
1125 if (index >= bool_num || strcmp(name, bool_pending_names[index]))
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001126 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Eric Parisb77a4932010-11-23 11:40:08 -05001128 ret = -ENOMEM;
Eric Paris18729812008-04-17 14:15:45 -04001129 page = (char *)get_zeroed_page(GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001130 if (!page)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001133 cur_enforcing = security_get_bool_value(&selinux_state, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 if (cur_enforcing < 0) {
1135 ret = cur_enforcing;
1136 goto out;
1137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001139 bool_pending_values[index]);
Stephen Smalley68bdcf22006-03-22 00:09:15 -08001140 ret = simple_read_from_buffer(buf, count, ppos, page, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141out:
Ingo Molnarbb0030792006-03-22 00:09:14 -08001142 mutex_unlock(&sel_mutex);
Eric Parisb77a4932010-11-23 11:40:08 -05001143 free_page((unsigned long)page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return ret;
1145}
1146
1147static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
1148 size_t count, loff_t *ppos)
1149{
1150 char *page = NULL;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001151 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 int new_value;
Al Viro496ad9a2013-01-23 17:07:38 -05001153 unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001154 const char *name = filep->f_path.dentry->d_name.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Ingo Molnarbb0030792006-03-22 00:09:14 -08001156 mutex_lock(&sel_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001158 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
1159 SECCLASS_SECURITY, SECURITY__SETBOOL,
1160 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (length)
1162 goto out;
1163
Eric Parisb77a4932010-11-23 11:40:08 -05001164 length = -EINVAL;
1165 if (index >= bool_num || strcmp(name, bool_pending_names[index]))
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001166 goto out;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001167
Eric Parisb77a4932010-11-23 11:40:08 -05001168 length = -ENOMEM;
1169 if (count >= PAGE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 goto out;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001171
Eric Parisb77a4932010-11-23 11:40:08 -05001172 /* No partial writes. */
1173 length = -EINVAL;
1174 if (*ppos != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 goto out;
Eric Parisb77a4932010-11-23 11:40:08 -05001176
Al Viro8365a712015-12-24 00:08:06 -05001177 page = memdup_user_nul(buf, count);
1178 if (IS_ERR(page)) {
1179 length = PTR_ERR(page);
1180 page = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 goto out;
Al Viro8365a712015-12-24 00:08:06 -05001182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 length = -EINVAL;
1185 if (sscanf(page, "%d", &new_value) != 1)
1186 goto out;
1187
1188 if (new_value)
1189 new_value = 1;
1190
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001191 bool_pending_values[index] = new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 length = count;
1193
1194out:
Ingo Molnarbb0030792006-03-22 00:09:14 -08001195 mutex_unlock(&sel_mutex);
Al Viro8365a712015-12-24 00:08:06 -05001196 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 return length;
1198}
1199
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001200static const struct file_operations sel_bool_ops = {
Eric Paris18729812008-04-17 14:15:45 -04001201 .read = sel_read_bool,
1202 .write = sel_write_bool,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001203 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204};
1205
1206static ssize_t sel_commit_bools_write(struct file *filep,
1207 const char __user *buf,
1208 size_t count, loff_t *ppos)
1209{
1210 char *page = NULL;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001211 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 int new_value;
1213
Ingo Molnarbb0030792006-03-22 00:09:14 -08001214 mutex_lock(&sel_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001216 length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
1217 SECCLASS_SECURITY, SECURITY__SETBOOL,
1218 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 if (length)
1220 goto out;
1221
Eric Parisb77a4932010-11-23 11:40:08 -05001222 length = -ENOMEM;
1223 if (count >= PAGE_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 goto out;
Eric Parisb77a4932010-11-23 11:40:08 -05001225
1226 /* No partial writes. */
1227 length = -EINVAL;
1228 if (*ppos != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 goto out;
Eric Parisb77a4932010-11-23 11:40:08 -05001230
Al Viro8365a712015-12-24 00:08:06 -05001231 page = memdup_user_nul(buf, count);
1232 if (IS_ERR(page)) {
1233 length = PTR_ERR(page);
1234 page = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 goto out;
Al Viro8365a712015-12-24 00:08:06 -05001236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
1238 length = -EINVAL;
1239 if (sscanf(page, "%d", &new_value) != 1)
1240 goto out;
1241
Eric Parisb77a4932010-11-23 11:40:08 -05001242 length = 0;
Eric Paris18729812008-04-17 14:15:45 -04001243 if (new_value && bool_pending_values)
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001244 length = security_set_bools(&selinux_state, bool_num,
1245 bool_pending_values);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Eric Parisb77a4932010-11-23 11:40:08 -05001247 if (!length)
1248 length = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250out:
Ingo Molnarbb0030792006-03-22 00:09:14 -08001251 mutex_unlock(&sel_mutex);
Al Viro8365a712015-12-24 00:08:06 -05001252 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 return length;
1254}
1255
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001256static const struct file_operations sel_commit_bools_ops = {
Eric Paris18729812008-04-17 14:15:45 -04001257 .write = sel_commit_bools_write,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001258 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259};
1260
Christopher J. PeBenito0c92d7c2007-05-23 09:12:07 -04001261static void sel_remove_entries(struct dentry *de)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262{
Al Viroad521842014-12-24 14:56:48 -05001263 d_genocide(de);
1264 shrink_dcache_parent(de);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265}
1266
1267#define BOOL_DIR_NAME "booleans"
1268
1269static int sel_make_bools(void)
1270{
Eric Parisb77a4932010-11-23 11:40:08 -05001271 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 ssize_t len;
1273 struct dentry *dentry = NULL;
1274 struct dentry *dir = bool_dir;
1275 struct inode *inode = NULL;
1276 struct inode_security_struct *isec;
1277 char **names = NULL, *page;
1278 int num;
1279 int *values = NULL;
1280 u32 sid;
1281
1282 /* remove any existing files */
Xiaotian Feng8007f102010-02-09 08:22:24 +11001283 for (i = 0; i < bool_num; i++)
1284 kfree(bool_pending_names[i]);
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001285 kfree(bool_pending_names);
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07001286 kfree(bool_pending_values);
Eric Paris154c50c2012-04-04 13:47:11 -04001287 bool_num = 0;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001288 bool_pending_names = NULL;
Davi Arnaut20c19e42005-10-23 12:57:16 -07001289 bool_pending_values = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Christopher J. PeBenito0c92d7c2007-05-23 09:12:07 -04001291 sel_remove_entries(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Eric Parisb77a4932010-11-23 11:40:08 -05001293 ret = -ENOMEM;
Eric Paris18729812008-04-17 14:15:45 -04001294 page = (char *)get_zeroed_page(GFP_KERNEL);
1295 if (!page)
Eric Parisb77a4932010-11-23 11:40:08 -05001296 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001298 ret = security_get_bools(&selinux_state, &num, &names, &values);
Eric Parisb77a4932010-11-23 11:40:08 -05001299 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 goto out;
1301
1302 for (i = 0; i < num; i++) {
Eric Parisb77a4932010-11-23 11:40:08 -05001303 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 dentry = d_alloc_name(dir, names[i]);
Eric Parisb77a4932010-11-23 11:40:08 -05001305 if (!dentry)
1306 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Eric Parisb77a4932010-11-23 11:40:08 -05001308 ret = -ENOMEM;
1309 inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
1310 if (!inode)
1311 goto out;
1312
Eric Parisb77a4932010-11-23 11:40:08 -05001313 ret = -ENAMETOOLONG;
Al Virocc1dad72012-04-02 19:40:47 -04001314 len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
Eric Parisb77a4932010-11-23 11:40:08 -05001315 if (len >= PAGE_SIZE)
1316 goto out;
1317
Eric Paris18729812008-04-17 14:15:45 -04001318 isec = (struct inode_security_struct *)inode->i_security;
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001319 ret = security_genfs_sid(&selinux_state, "selinuxfs", page,
1320 SECCLASS_FILE, &sid);
Gary Tierney4262fb52017-01-09 10:07:31 -05001321 if (ret) {
Gary Tierney900fde02017-01-09 10:07:32 -05001322 pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
1323 page);
1324 sid = SECINITSID_SECURITY;
Gary Tierney4262fb52017-01-09 10:07:31 -05001325 }
1326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 isec->sid = sid;
Andreas Gruenbacher42059112016-11-10 22:18:27 +01001328 isec->initialized = LABEL_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 inode->i_fop = &sel_bool_ops;
James Carterbce34bc2007-04-04 16:18:50 -04001330 inode->i_ino = i|SEL_BOOL_INO_OFFSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 d_add(dentry, inode);
1332 }
1333 bool_num = num;
Stephen Smalleyd313f94832007-11-26 11:12:53 -05001334 bool_pending_names = names;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 bool_pending_values = values;
Eric Parisb77a4932010-11-23 11:40:08 -05001336
1337 free_page((unsigned long)page);
1338 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339out:
1340 free_page((unsigned long)page);
Eric Parisb77a4932010-11-23 11:40:08 -05001341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (names) {
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07001343 for (i = 0; i < num; i++)
1344 kfree(names[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 kfree(names);
1346 }
Davi Arnaut20c19e42005-10-23 12:57:16 -07001347 kfree(values);
Christopher J. PeBenito0c92d7c2007-05-23 09:12:07 -04001348 sel_remove_entries(dir);
Eric Parisb77a4932010-11-23 11:40:08 -05001349
1350 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351}
1352
1353#define NULL_FILE_NAME "null"
1354
Al Viro765927b2012-06-26 21:58:53 +04001355struct path selinux_null;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
1357static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
1358 size_t count, loff_t *ppos)
1359{
1360 char tmpbuf[TMPBUFLEN];
1361 ssize_t length;
1362
1363 length = scnprintf(tmpbuf, TMPBUFLEN, "%u", avc_cache_threshold);
1364 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1365}
1366
Eric Paris18729812008-04-17 14:15:45 -04001367static ssize_t sel_write_avc_cache_threshold(struct file *file,
1368 const char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 size_t count, loff_t *ppos)
1370
1371{
Al Viro8365a712015-12-24 00:08:06 -05001372 char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 ssize_t ret;
Heinrich Schuchardt309c5fa2016-06-10 23:14:26 +02001374 unsigned int new_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Stephen Smalleybe0554c2017-01-09 10:07:31 -05001376 ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
1377 SECCLASS_SECURITY, SECURITY__SETSECPARAM,
1378 NULL);
Eric Parisb77a4932010-11-23 11:40:08 -05001379 if (ret)
Al Viro8365a712015-12-24 00:08:06 -05001380 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Eric Parisb77a4932010-11-23 11:40:08 -05001382 if (count >= PAGE_SIZE)
Al Viro8365a712015-12-24 00:08:06 -05001383 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Eric Parisb77a4932010-11-23 11:40:08 -05001385 /* No partial writes. */
Eric Parisb77a4932010-11-23 11:40:08 -05001386 if (*ppos != 0)
Al Viro8365a712015-12-24 00:08:06 -05001387 return -EINVAL;
Eric Parisb77a4932010-11-23 11:40:08 -05001388
Al Viro8365a712015-12-24 00:08:06 -05001389 page = memdup_user_nul(buf, count);
1390 if (IS_ERR(page))
1391 return PTR_ERR(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Eric Parisb77a4932010-11-23 11:40:08 -05001393 ret = -EINVAL;
1394 if (sscanf(page, "%u", &new_value) != 1)
1395 goto out;
1396
1397 avc_cache_threshold = new_value;
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 ret = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400out:
Al Viro8365a712015-12-24 00:08:06 -05001401 kfree(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 return ret;
1403}
1404
1405static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
1406 size_t count, loff_t *ppos)
1407{
1408 char *page;
Eric Parisb77a4932010-11-23 11:40:08 -05001409 ssize_t length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 page = (char *)__get_free_page(GFP_KERNEL);
Eric Parisb77a4932010-11-23 11:40:08 -05001412 if (!page)
1413 return -ENOMEM;
1414
1415 length = avc_get_hash_stats(page);
1416 if (length >= 0)
1417 length = simple_read_from_buffer(buf, count, ppos, page, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 free_page((unsigned long)page);
Eric Parisb77a4932010-11-23 11:40:08 -05001419
1420 return length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421}
1422
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001423static const struct file_operations sel_avc_cache_threshold_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 .read = sel_read_avc_cache_threshold,
1425 .write = sel_write_avc_cache_threshold,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001426 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427};
1428
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001429static const struct file_operations sel_avc_hash_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 .read = sel_read_avc_hash_stats,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001431 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432};
1433
1434#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
1435static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
1436{
1437 int cpu;
1438
Rusty Russell4f4b6c12009-01-01 10:12:15 +10301439 for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 if (!cpu_possible(cpu))
1441 continue;
1442 *idx = cpu + 1;
1443 return &per_cpu(avc_cache_stats, cpu);
1444 }
1445 return NULL;
1446}
1447
1448static void *sel_avc_stats_seq_start(struct seq_file *seq, loff_t *pos)
1449{
1450 loff_t n = *pos - 1;
1451
1452 if (*pos == 0)
1453 return SEQ_START_TOKEN;
1454
1455 return sel_avc_get_stat_idx(&n);
1456}
1457
1458static void *sel_avc_stats_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1459{
1460 return sel_avc_get_stat_idx(pos);
1461}
1462
1463static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
1464{
1465 struct avc_cache_stats *st = v;
1466
Markus Elfring710a0642017-01-15 14:04:53 +01001467 if (v == SEQ_START_TOKEN) {
1468 seq_puts(seq,
1469 "lookups hits misses allocations reclaims frees\n");
1470 } else {
Linus Torvalds257313b2011-05-19 21:22:53 -07001471 unsigned int lookups = st->lookups;
1472 unsigned int misses = st->misses;
1473 unsigned int hits = lookups - misses;
1474 seq_printf(seq, "%u %u %u %u %u %u\n", lookups,
1475 hits, misses, st->allocations,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 st->reclaims, st->frees);
Linus Torvalds257313b2011-05-19 21:22:53 -07001477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 return 0;
1479}
1480
1481static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
1482{ }
1483
Jan Engelhardt1996a102008-01-23 00:02:58 +01001484static const struct seq_operations sel_avc_cache_stats_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 .start = sel_avc_stats_seq_start,
1486 .next = sel_avc_stats_seq_next,
1487 .show = sel_avc_stats_seq_show,
1488 .stop = sel_avc_stats_seq_stop,
1489};
1490
1491static int sel_open_avc_cache_stats(struct inode *inode, struct file *file)
1492{
1493 return seq_open(file, &sel_avc_cache_stats_seq_ops);
1494}
1495
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -08001496static const struct file_operations sel_avc_cache_stats_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 .open = sel_open_avc_cache_stats,
1498 .read = seq_read,
1499 .llseek = seq_lseek,
1500 .release = seq_release,
1501};
1502#endif
1503
1504static int sel_make_avc_files(struct dentry *dir)
1505{
Eric Parisb77a4932010-11-23 11:40:08 -05001506 int i;
Eric Biggerscda37122017-03-25 21:15:37 -07001507 static const struct tree_descr files[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 { "cache_threshold",
1509 &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR },
1510 { "hash_stats", &sel_avc_hash_stats_ops, S_IRUGO },
1511#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
1512 { "cache_stats", &sel_avc_cache_stats_ops, S_IRUGO },
1513#endif
1514 };
1515
Nicolas Kaiser6e20a642006-01-06 00:11:22 -08001516 for (i = 0; i < ARRAY_SIZE(files); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 struct inode *inode;
1518 struct dentry *dentry;
1519
1520 dentry = d_alloc_name(dir, files[i].name);
Eric Parisb77a4932010-11-23 11:40:08 -05001521 if (!dentry)
1522 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
1524 inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
Eric Parisb77a4932010-11-23 11:40:08 -05001525 if (!inode)
1526 return -ENOMEM;
1527
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 inode->i_fop = files[i].ops;
James Carter6174eaf2007-04-04 16:18:39 -04001529 inode->i_ino = ++sel_last_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 d_add(dentry, inode);
1531 }
Eric Parisb77a4932010-11-23 11:40:08 -05001532
1533 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534}
1535
Eric Paris18729812008-04-17 14:15:45 -04001536static ssize_t sel_read_initcon(struct file *file, char __user *buf,
James Carterf0ee2e42007-04-04 10:11:29 -04001537 size_t count, loff_t *ppos)
1538{
James Carterf0ee2e42007-04-04 10:11:29 -04001539 char *con;
1540 u32 sid, len;
1541 ssize_t ret;
1542
Al Viro496ad9a2013-01-23 17:07:38 -05001543 sid = file_inode(file)->i_ino&SEL_INO_MASK;
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001544 ret = security_sid_to_context(&selinux_state, sid, &con, &len);
Eric Parisb77a4932010-11-23 11:40:08 -05001545 if (ret)
James Carterf0ee2e42007-04-04 10:11:29 -04001546 return ret;
1547
1548 ret = simple_read_from_buffer(buf, count, ppos, con, len);
1549 kfree(con);
1550 return ret;
1551}
1552
1553static const struct file_operations sel_initcon_ops = {
1554 .read = sel_read_initcon,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001555 .llseek = generic_file_llseek,
James Carterf0ee2e42007-04-04 10:11:29 -04001556};
1557
1558static int sel_make_initcon_files(struct dentry *dir)
1559{
Eric Parisb77a4932010-11-23 11:40:08 -05001560 int i;
James Carterf0ee2e42007-04-04 10:11:29 -04001561
1562 for (i = 1; i <= SECINITSID_NUM; i++) {
1563 struct inode *inode;
1564 struct dentry *dentry;
1565 dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
Eric Parisb77a4932010-11-23 11:40:08 -05001566 if (!dentry)
1567 return -ENOMEM;
James Carterf0ee2e42007-04-04 10:11:29 -04001568
1569 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
Eric Parisb77a4932010-11-23 11:40:08 -05001570 if (!inode)
1571 return -ENOMEM;
1572
James Carterf0ee2e42007-04-04 10:11:29 -04001573 inode->i_fop = &sel_initcon_ops;
1574 inode->i_ino = i|SEL_INITCON_INO_OFFSET;
1575 d_add(dentry, inode);
1576 }
Eric Parisb77a4932010-11-23 11:40:08 -05001577
1578 return 0;
James Carterf0ee2e42007-04-04 10:11:29 -04001579}
1580
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001581static inline unsigned long sel_class_to_ino(u16 class)
1582{
1583 return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
1584}
1585
1586static inline u16 sel_ino_to_class(unsigned long ino)
1587{
Eric Paris92ae9e82012-04-04 13:46:46 -04001588 return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001589}
1590
1591static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
1592{
1593 return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
1594}
1595
1596static inline u32 sel_ino_to_perm(unsigned long ino)
1597{
1598 return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
1599}
1600
Eric Paris18729812008-04-17 14:15:45 -04001601static ssize_t sel_read_class(struct file *file, char __user *buf,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001602 size_t count, loff_t *ppos)
1603{
Al Viro496ad9a2013-01-23 17:07:38 -05001604 unsigned long ino = file_inode(file)->i_ino;
Al Virocc1dad72012-04-02 19:40:47 -04001605 char res[TMPBUFLEN];
1606 ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
1607 return simple_read_from_buffer(buf, count, ppos, res, len);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001608}
1609
1610static const struct file_operations sel_class_ops = {
1611 .read = sel_read_class,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001612 .llseek = generic_file_llseek,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001613};
1614
Eric Paris18729812008-04-17 14:15:45 -04001615static ssize_t sel_read_perm(struct file *file, char __user *buf,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001616 size_t count, loff_t *ppos)
1617{
Al Viro496ad9a2013-01-23 17:07:38 -05001618 unsigned long ino = file_inode(file)->i_ino;
Al Virocc1dad72012-04-02 19:40:47 -04001619 char res[TMPBUFLEN];
1620 ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
1621 return simple_read_from_buffer(buf, count, ppos, res, len);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001622}
1623
1624static const struct file_operations sel_perm_ops = {
1625 .read = sel_read_perm,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001626 .llseek = generic_file_llseek,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001627};
1628
Paul Moore3bb56b22008-01-29 08:38:19 -05001629static ssize_t sel_read_policycap(struct file *file, char __user *buf,
1630 size_t count, loff_t *ppos)
1631{
1632 int value;
1633 char tmpbuf[TMPBUFLEN];
1634 ssize_t length;
Al Viro496ad9a2013-01-23 17:07:38 -05001635 unsigned long i_ino = file_inode(file)->i_ino;
Paul Moore3bb56b22008-01-29 08:38:19 -05001636
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001637 value = security_policycap_supported(&selinux_state,
1638 i_ino & SEL_INO_MASK);
Paul Moore3bb56b22008-01-29 08:38:19 -05001639 length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
1640
1641 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
1642}
1643
1644static const struct file_operations sel_policycap_ops = {
1645 .read = sel_read_policycap,
Arnd Bergmann57a62c22010-07-07 23:40:10 +02001646 .llseek = generic_file_llseek,
Paul Moore3bb56b22008-01-29 08:38:19 -05001647};
1648
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001649static int sel_make_perm_files(char *objclass, int classvalue,
1650 struct dentry *dir)
1651{
Eric Parisb77a4932010-11-23 11:40:08 -05001652 int i, rc, nperms;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001653 char **perms;
1654
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001655 rc = security_get_permissions(&selinux_state, objclass, &perms,
1656 &nperms);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001657 if (rc)
Eric Parisb77a4932010-11-23 11:40:08 -05001658 return rc;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001659
1660 for (i = 0; i < nperms; i++) {
1661 struct inode *inode;
1662 struct dentry *dentry;
1663
Eric Parisb77a4932010-11-23 11:40:08 -05001664 rc = -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001665 dentry = d_alloc_name(dir, perms[i]);
Eric Parisb77a4932010-11-23 11:40:08 -05001666 if (!dentry)
1667 goto out;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001668
Eric Parisb77a4932010-11-23 11:40:08 -05001669 rc = -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001670 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
Eric Parisb77a4932010-11-23 11:40:08 -05001671 if (!inode)
1672 goto out;
1673
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001674 inode->i_fop = &sel_perm_ops;
1675 /* i+1 since perm values are 1-indexed */
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001676 inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001677 d_add(dentry, inode);
1678 }
Eric Parisb77a4932010-11-23 11:40:08 -05001679 rc = 0;
1680out:
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001681 for (i = 0; i < nperms; i++)
1682 kfree(perms[i]);
1683 kfree(perms);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001684 return rc;
1685}
1686
1687static int sel_make_class_dir_entries(char *classname, int index,
1688 struct dentry *dir)
1689{
1690 struct dentry *dentry = NULL;
1691 struct inode *inode = NULL;
1692 int rc;
1693
1694 dentry = d_alloc_name(dir, "index");
Eric Parisb77a4932010-11-23 11:40:08 -05001695 if (!dentry)
1696 return -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001697
1698 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
Eric Parisb77a4932010-11-23 11:40:08 -05001699 if (!inode)
1700 return -ENOMEM;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001701
1702 inode->i_fop = &sel_class_ops;
1703 inode->i_ino = sel_class_to_ino(index);
1704 d_add(dentry, inode);
1705
Al Viroa1c2aa12012-03-18 20:36:59 -04001706 dentry = sel_make_dir(dir, "perms", &last_class_ino);
1707 if (IS_ERR(dentry))
1708 return PTR_ERR(dentry);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001709
1710 rc = sel_make_perm_files(classname, index, dentry);
1711
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001712 return rc;
1713}
1714
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001715static int sel_make_classes(void)
1716{
Eric Parisb77a4932010-11-23 11:40:08 -05001717 int rc, nclasses, i;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001718 char **classes;
1719
1720 /* delete any existing entries */
Al Viroad521842014-12-24 14:56:48 -05001721 sel_remove_entries(class_dir);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001722
Stephen Smalleyaa8e7122018-03-01 18:48:02 -05001723 rc = security_get_classes(&selinux_state, &classes, &nclasses);
Eric Parisb77a4932010-11-23 11:40:08 -05001724 if (rc)
1725 return rc;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001726
1727 /* +2 since classes are 1-indexed */
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001728 last_class_ino = sel_class_to_ino(nclasses + 2);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001729
1730 for (i = 0; i < nclasses; i++) {
1731 struct dentry *class_name_dir;
1732
Al Viroa1c2aa12012-03-18 20:36:59 -04001733 class_name_dir = sel_make_dir(class_dir, classes[i],
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001734 &last_class_ino);
Al Viroa1c2aa12012-03-18 20:36:59 -04001735 if (IS_ERR(class_name_dir)) {
1736 rc = PTR_ERR(class_name_dir);
Eric Parisb77a4932010-11-23 11:40:08 -05001737 goto out;
Al Viroa1c2aa12012-03-18 20:36:59 -04001738 }
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001739
1740 /* i+1 since class values are 1-indexed */
wzt.wzt@gmail.comc1a73682010-04-09 19:30:29 +08001741 rc = sel_make_class_dir_entries(classes[i], i + 1,
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001742 class_name_dir);
1743 if (rc)
Eric Parisb77a4932010-11-23 11:40:08 -05001744 goto out;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001745 }
Eric Parisb77a4932010-11-23 11:40:08 -05001746 rc = 0;
1747out:
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001748 for (i = 0; i < nclasses; i++)
1749 kfree(classes[i]);
1750 kfree(classes);
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001751 return rc;
1752}
1753
Paul Moore3bb56b22008-01-29 08:38:19 -05001754static int sel_make_policycap(void)
1755{
1756 unsigned int iter;
1757 struct dentry *dentry = NULL;
1758 struct inode *inode = NULL;
1759
1760 sel_remove_entries(policycap_dir);
1761
1762 for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
Stephen Smalley4dc2fce2017-05-18 16:58:31 -04001763 if (iter < ARRAY_SIZE(selinux_policycap_names))
Paul Moore3bb56b22008-01-29 08:38:19 -05001764 dentry = d_alloc_name(policycap_dir,
Stephen Smalley4dc2fce2017-05-18 16:58:31 -04001765 selinux_policycap_names[iter]);
Paul Moore3bb56b22008-01-29 08:38:19 -05001766 else
1767 dentry = d_alloc_name(policycap_dir, "unknown");
1768
1769 if (dentry == NULL)
1770 return -ENOMEM;
1771
1772 inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO);
1773 if (inode == NULL)
1774 return -ENOMEM;
1775
1776 inode->i_fop = &sel_policycap_ops;
1777 inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
1778 d_add(dentry, inode);
1779 }
1780
1781 return 0;
1782}
1783
Al Viroa1c2aa12012-03-18 20:36:59 -04001784static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
Christopher J. PeBenito0dd4ae52007-05-23 09:12:08 -04001785 unsigned long *ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786{
Al Viroa1c2aa12012-03-18 20:36:59 -04001787 struct dentry *dentry = d_alloc_name(dir, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 struct inode *inode;
1789
Al Viroa1c2aa12012-03-18 20:36:59 -04001790 if (!dentry)
1791 return ERR_PTR(-ENOMEM);
1792
1793 inode = sel_make_inode(dir->d_sb, S_IFDIR | S_IRUGO | S_IXUGO);
1794 if (!inode) {
1795 dput(dentry);
1796 return ERR_PTR(-ENOMEM);
1797 }
Eric Parisb77a4932010-11-23 11:40:08 -05001798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 inode->i_op = &simple_dir_inode_operations;
1800 inode->i_fop = &simple_dir_operations;
Christopher J. PeBenito0dd4ae52007-05-23 09:12:08 -04001801 inode->i_ino = ++(*ino);
James Morris40e906f2006-03-22 00:09:16 -08001802 /* directory inodes start off with i_nlink == 2 (for "." entry) */
Dave Hansend8c76e62006-09-30 23:29:04 -07001803 inc_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 d_add(dentry, inode);
James Morrisedb20fb2006-03-22 00:09:20 -08001805 /* bump link count on parent directory, too */
David Howellsce0b16d2015-02-19 10:47:02 +00001806 inc_nlink(d_inode(dir));
Eric Parisb77a4932010-11-23 11:40:08 -05001807
Al Viroa1c2aa12012-03-18 20:36:59 -04001808 return dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809}
1810
Eric Paris18729812008-04-17 14:15:45 -04001811static int sel_fill_super(struct super_block *sb, void *data, int silent)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
1813 int ret;
1814 struct dentry *dentry;
Al Viroa1c2aa12012-03-18 20:36:59 -04001815 struct inode *inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 struct inode_security_struct *isec;
1817
Eric Biggerscda37122017-03-25 21:15:37 -07001818 static const struct tree_descr selinux_files[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 [SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
1820 [SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
Stephen Smalleyce9982d2005-11-08 21:34:33 -08001821 [SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 [SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
1823 [SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
1824 [SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
1825 [SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
1826 [SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
1827 [SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
1828 [SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
1829 [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
1830 [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
1831 [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
Eric Paris3f120702007-09-21 14:37:10 -04001832 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
1833 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
KaiGai Kohei11904162010-09-14 18:28:39 +09001834 [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
Eric Paris72e8c8592012-02-16 15:08:39 -05001835 [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
Andrew Perepechkof9df6452015-12-24 11:09:41 -05001836 [SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
1837 S_IWUGO},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 /* last one */ {""}
1839 };
1840 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
1841 if (ret)
James Morris161ce452006-03-22 00:09:17 -08001842 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Al Viroa1c2aa12012-03-18 20:36:59 -04001844 bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &sel_last_ino);
1845 if (IS_ERR(bool_dir)) {
1846 ret = PTR_ERR(bool_dir);
1847 bool_dir = NULL;
James Morris161ce452006-03-22 00:09:17 -08001848 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04001849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
Eric Parisb77a4932010-11-23 11:40:08 -05001851 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
Eric Parisb77a4932010-11-23 11:40:08 -05001853 if (!dentry)
James Morris161ce452006-03-22 00:09:17 -08001854 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
Eric Parisb77a4932010-11-23 11:40:08 -05001856 ret = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
Eric Parisb77a4932010-11-23 11:40:08 -05001858 if (!inode)
James Morris161ce452006-03-22 00:09:17 -08001859 goto err;
Eric Parisb77a4932010-11-23 11:40:08 -05001860
James Carter6174eaf2007-04-04 16:18:39 -04001861 inode->i_ino = ++sel_last_ino;
Eric Paris18729812008-04-17 14:15:45 -04001862 isec = (struct inode_security_struct *)inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 isec->sid = SECINITSID_DEVNULL;
1864 isec->sclass = SECCLASS_CHR_FILE;
Andreas Gruenbacher42059112016-11-10 22:18:27 +01001865 isec->initialized = LABEL_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867 init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
1868 d_add(dentry, inode);
Al Viro765927b2012-06-26 21:58:53 +04001869 selinux_null.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Al Viroa1c2aa12012-03-18 20:36:59 -04001871 dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
1872 if (IS_ERR(dentry)) {
1873 ret = PTR_ERR(dentry);
James Morris161ce452006-03-22 00:09:17 -08001874 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04001875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
1877 ret = sel_make_avc_files(dentry);
1878 if (ret)
James Morris161ce452006-03-22 00:09:17 -08001879 goto err;
James Carterf0ee2e42007-04-04 10:11:29 -04001880
Al Viroa1c2aa12012-03-18 20:36:59 -04001881 dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino);
1882 if (IS_ERR(dentry)) {
1883 ret = PTR_ERR(dentry);
James Carterf0ee2e42007-04-04 10:11:29 -04001884 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04001885 }
James Carterf0ee2e42007-04-04 10:11:29 -04001886
1887 ret = sel_make_initcon_files(dentry);
1888 if (ret)
1889 goto err;
1890
Al Viroa1c2aa12012-03-18 20:36:59 -04001891 class_dir = sel_make_dir(sb->s_root, "class", &sel_last_ino);
1892 if (IS_ERR(class_dir)) {
1893 ret = PTR_ERR(class_dir);
1894 class_dir = NULL;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001895 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04001896 }
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001897
Al Viroa1c2aa12012-03-18 20:36:59 -04001898 policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities", &sel_last_ino);
1899 if (IS_ERR(policycap_dir)) {
1900 ret = PTR_ERR(policycap_dir);
1901 policycap_dir = NULL;
Christopher J. PeBenitoe47c8fc52007-05-23 09:12:09 -04001902 goto err;
Al Viroa1c2aa12012-03-18 20:36:59 -04001903 }
Eric Parisb77a4932010-11-23 11:40:08 -05001904 return 0;
James Morris161ce452006-03-22 00:09:17 -08001905err:
Eric Paris744ba352008-04-17 11:52:44 -04001906 printk(KERN_ERR "SELinux: %s: failed while creating inodes\n",
1907 __func__);
Eric Parisb77a4932010-11-23 11:40:08 -05001908 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909}
1910
Al Virofc14f2f2010-07-25 01:48:30 +04001911static struct dentry *sel_mount(struct file_system_type *fs_type,
1912 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913{
Al Virofc14f2f2010-07-25 01:48:30 +04001914 return mount_single(fs_type, flags, data, sel_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915}
1916
1917static struct file_system_type sel_fs_type = {
1918 .name = "selinuxfs",
Al Virofc14f2f2010-07-25 01:48:30 +04001919 .mount = sel_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 .kill_sb = kill_litter_super,
1921};
1922
1923struct vfsmount *selinuxfs_mount;
1924
1925static int __init init_sel_fs(void)
1926{
1927 int err;
1928
1929 if (!selinux_enabled)
1930 return 0;
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07001931
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -05001932 err = sysfs_create_mount_point(fs_kobj, "selinux");
1933 if (err)
1934 return err;
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07001935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 err = register_filesystem(&sel_fs_type);
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07001937 if (err) {
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -05001938 sysfs_remove_mount_point(fs_kobj, "selinux");
Eric Parisb77a4932010-11-23 11:40:08 -05001939 return err;
Greg Kroah-Hartman7a627e32011-05-10 15:34:16 -07001940 }
Eric Parisb77a4932010-11-23 11:40:08 -05001941
Al Viro765927b2012-06-26 21:58:53 +04001942 selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
Eric Parisb77a4932010-11-23 11:40:08 -05001943 if (IS_ERR(selinuxfs_mount)) {
1944 printk(KERN_ERR "selinuxfs: could not mount!\n");
1945 err = PTR_ERR(selinuxfs_mount);
1946 selinuxfs_mount = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 }
Eric Parisb77a4932010-11-23 11:40:08 -05001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return err;
1950}
1951
1952__initcall(init_sel_fs);
1953
1954#ifdef CONFIG_SECURITY_SELINUX_DISABLE
1955void exit_sel_fs(void)
1956{
Eric W. Biedermanf9bb4882015-05-13 17:35:41 -05001957 sysfs_remove_mount_point(fs_kobj, "selinux");
Tim Chen423e0ab2011-07-19 09:32:38 -07001958 kern_unmount(selinuxfs_mount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 unregister_filesystem(&sel_fs_type);
1960}
1961#endif