blob: 5b3db436814db5d6548ecbf9f2e0c91b697a0737 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NSA Security-Enhanced Linux (SELinux) security module
3 *
4 * This file contains the SELinux hook function implementations.
5 *
6 * Authors: Stephen Smalley, <sds@epoch.ncsc.mil>
Eric Paris828dfe12008-04-17 13:17:49 -04007 * Chris Vance, <cvance@nai.com>
8 * Wayne Salamon, <wsalamon@nai.com>
9 * James Morris <jmorris@redhat.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * Copyright (C) 2001,2002 Networks Associates Technology, Inc.
Eric Paris2069f452008-07-04 09:47:13 +100012 * Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
13 * Eric Paris <eparis@redhat.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
Eric Paris828dfe12008-04-17 13:17:49 -040015 * <dgoeddel@trustedcs.com>
Paul Mooreed6d76e2009-08-28 18:12:49 -040016 * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
Paul Moore82c21bf2011-08-01 11:10:33 +000017 * Paul Moore <paul@paul-moore.com>
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +090018 * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
Eric Paris828dfe12008-04-17 13:17:49 -040019 * Yuichi Nakamura <ynakam@hitachisoft.jp>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2,
Eric Paris828dfe12008-04-17 13:17:49 -040023 * as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
Eric Paris0b24dcb2011-02-25 15:39:20 -050027#include <linux/kd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/kernel.h>
Roland McGrath0d094ef2008-07-25 19:45:49 -070029#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
31#include <linux/sched.h>
32#include <linux/security.h>
33#include <linux/xattr.h>
34#include <linux/capability.h>
35#include <linux/unistd.h>
36#include <linux/mm.h>
37#include <linux/mman.h>
38#include <linux/slab.h>
39#include <linux/pagemap.h>
Eric Paris0b24dcb2011-02-25 15:39:20 -050040#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/swap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/spinlock.h>
43#include <linux/syscalls.h>
Eric Paris2a7dba32011-02-01 11:05:39 -050044#include <linux/dcache.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/file.h>
Al Viro9f3acc32008-04-24 07:44:08 -040046#include <linux/fdtable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/namei.h>
48#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/netfilter_ipv4.h>
50#include <linux/netfilter_ipv6.h>
51#include <linux/tty.h>
52#include <net/icmp.h>
Stephen Hemminger227b60f2007-10-10 17:30:46 -070053#include <net/ip.h> /* for local_port_range[] */
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
Paul Moore1c5d9d12013-12-04 16:10:45 -050055#include <net/inet_connection_sock.h>
Paul Moore220deb92008-01-29 08:38:23 -050056#include <net/net_namespace.h>
Paul Moored621d352008-01-29 08:43:36 -050057#include <net/netlabel.h>
Eric Parisf5269712008-05-14 11:27:45 -040058#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <asm/ioctls.h>
Arun Sharma60063492011-07-26 16:09:06 -070060#include <linux/atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/bitops.h>
62#include <linux/interrupt.h>
63#include <linux/netdevice.h> /* for network interface checks */
64#include <linux/netlink.h>
65#include <linux/tcp.h>
66#include <linux/udp.h>
James Morris2ee92d42006-11-13 16:09:01 -080067#include <linux/dccp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <linux/quota.h>
69#include <linux/un.h> /* for Unix socket types */
70#include <net/af_unix.h> /* for Unix socket types */
71#include <linux/parser.h>
72#include <linux/nfs_mount.h>
73#include <net/ipv6.h>
74#include <linux/hugetlb.h>
75#include <linux/personality.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#include <linux/audit.h>
Eric Paris6931dfc2005-06-30 02:58:51 -070077#include <linux/string.h>
Catherine Zhang877ce7c2006-06-29 12:27:47 -070078#include <linux/selinux.h>
Eric Paris23970742006-09-25 23:32:01 -070079#include <linux/mutex.h>
Frank Mayharf06febc2008-09-12 09:54:39 -070080#include <linux/posix-timers.h>
Kees Cook00234592010-02-03 15:36:43 -080081#include <linux/syslog.h>
Serge E. Hallyn34867402011-03-23 16:43:17 -070082#include <linux/user_namespace.h>
Paul Gortmaker44fc7ea2011-05-26 20:52:10 -040083#include <linux/export.h>
Al Viro40401532012-02-13 03:58:52 +000084#include <linux/msg.h>
85#include <linux/shm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87#include "avc.h"
88#include "objsec.h"
89#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050090#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040091#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080092#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050093#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020094#include "audit.h"
James Morris7b98a582011-08-30 12:52:32 +100095#include "avc_ss.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
David P. Quigley11689d42009-01-16 09:22:03 -050097#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050098
James Morris20510f22007-10-16 23:31:32 -070099extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Paul Moored621d352008-01-29 08:43:36 -0500101/* SECMARK reference count */
James Morris56a4ca92011-08-17 11:08:43 +1000102static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
Paul Moored621d352008-01-29 08:43:36 -0500103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400105int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107static int __init enforcing_setup(char *str)
108{
Eric Parisf5269712008-05-14 11:27:45 -0400109 unsigned long enforcing;
110 if (!strict_strtoul(str, 0, &enforcing))
111 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 return 1;
113}
114__setup("enforcing=", enforcing_setup);
115#endif
116
117#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
118int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
119
120static int __init selinux_enabled_setup(char *str)
121{
Eric Parisf5269712008-05-14 11:27:45 -0400122 unsigned long enabled;
123 if (!strict_strtoul(str, 0, &enabled))
124 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 return 1;
126}
127__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400128#else
129int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130#endif
131
Christoph Lametere18b8902006-12-06 20:33:20 -0800132static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800133
Paul Moored621d352008-01-29 08:43:36 -0500134/**
135 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
136 *
137 * Description:
138 * This function checks the SECMARK reference counter to see if any SECMARK
139 * targets are currently configured, if the reference counter is greater than
140 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
141 * enabled, false (0) if SECMARK is disabled.
142 *
143 */
144static int selinux_secmark_enabled(void)
145{
146 return (atomic_read(&selinux_secmark_refcount) > 0);
147}
148
David Howellsd84f4f92008-11-14 10:39:23 +1100149/*
150 * initialise the security for the init task
151 */
152static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
David Howells3b11a1d2008-11-14 10:39:26 +1100154 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 struct task_security_struct *tsec;
156
James Morris89d155e2005-10-30 14:59:21 -0800157 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100159 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
David Howellsd84f4f92008-11-14 10:39:23 +1100161 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100162 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
David Howells275bb412008-11-14 10:39:19 +1100165/*
David Howells88e67f32008-11-14 10:39:21 +1100166 * get the security ID of a set of credentials
167 */
168static inline u32 cred_sid(const struct cred *cred)
169{
170 const struct task_security_struct *tsec;
171
172 tsec = cred->security;
173 return tsec->sid;
174}
175
176/*
David Howells3b11a1d2008-11-14 10:39:26 +1100177 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100178 */
179static inline u32 task_sid(const struct task_struct *task)
180{
David Howells275bb412008-11-14 10:39:19 +1100181 u32 sid;
182
183 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100184 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100185 rcu_read_unlock();
186 return sid;
187}
188
189/*
David Howells3b11a1d2008-11-14 10:39:26 +1100190 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100191 */
192static inline u32 current_sid(void)
193{
Paul Moore5fb49872010-04-22 14:46:19 -0400194 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +1100195
196 return tsec->sid;
197}
198
David Howells88e67f32008-11-14 10:39:21 +1100199/* Allocate and free functions for each kind of security blob. */
200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static int inode_alloc_security(struct inode *inode)
202{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100204 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Josef Bacika02fe132008-04-04 09:35:05 +1100206 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (!isec)
208 return -ENOMEM;
209
Eric Paris23970742006-09-25 23:32:01 -0700210 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 isec->inode = inode;
213 isec->sid = SECINITSID_UNLABELED;
214 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100215 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 inode->i_security = isec;
217
218 return 0;
219}
220
Steven Rostedt9e74d932014-01-09 21:46:34 -0500221static void inode_free_rcu(struct rcu_head *head)
222{
223 struct inode_security_struct *isec;
224
225 isec = container_of(head, struct inode_security_struct, rcu);
226 kmem_cache_free(sel_inode_cache, isec);
227}
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229static void inode_free_security(struct inode *inode)
230{
231 struct inode_security_struct *isec = inode->i_security;
232 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 spin_lock(&sbsec->isec_lock);
235 if (!list_empty(&isec->list))
236 list_del_init(&isec->list);
237 spin_unlock(&sbsec->isec_lock);
238
Steven Rostedt9e74d932014-01-09 21:46:34 -0500239 /*
240 * The inode may still be referenced in a path walk and
241 * a call to selinux_inode_permission() can be made
242 * after inode_free_security() is called. Ideally, the VFS
243 * wouldn't do this, but fixing that is a much harder
244 * job. For now, simply free the i_security via RCU, and
245 * leave the current inode->i_security pointer intact.
246 * The inode will be freed after the RCU grace period too.
247 */
248 call_rcu(&isec->rcu, inode_free_rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249}
250
251static int file_alloc_security(struct file *file)
252{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100254 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800256 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (!fsec)
258 return -ENOMEM;
259
David Howells275bb412008-11-14 10:39:19 +1100260 fsec->sid = sid;
261 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 file->f_security = fsec;
263
264 return 0;
265}
266
267static void file_free_security(struct file *file)
268{
269 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 file->f_security = NULL;
271 kfree(fsec);
272}
273
274static int superblock_alloc_security(struct super_block *sb)
275{
276 struct superblock_security_struct *sbsec;
277
James Morris89d155e2005-10-30 14:59:21 -0800278 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 if (!sbsec)
280 return -ENOMEM;
281
Eric Parisbc7e9822006-09-25 23:32:02 -0700282 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 INIT_LIST_HEAD(&sbsec->isec_head);
284 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 sbsec->sb = sb;
286 sbsec->sid = SECINITSID_UNLABELED;
287 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700288 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 sb->s_security = sbsec;
290
291 return 0;
292}
293
294static void superblock_free_security(struct super_block *sb)
295{
296 struct superblock_security_struct *sbsec = sb->s_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 sb->s_security = NULL;
298 kfree(sbsec);
299}
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301/* The file system's label must be initialized prior to use. */
302
Stephen Hemminger634a5392010-03-04 21:59:03 -0800303static const char *labeling_behaviors[6] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 "uses xattr",
305 "uses transition SIDs",
306 "uses task SIDs",
307 "uses genfs_contexts",
308 "not configured for labeling",
309 "uses mountpoint labeling",
310};
311
312static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
313
314static inline int inode_doinit(struct inode *inode)
315{
316 return inode_doinit_with_dentry(inode, NULL);
317}
318
319enum {
Eric Paris31e87932007-09-19 17:19:12 -0400320 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 Opt_context = 1,
322 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500323 Opt_defcontext = 3,
324 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500325 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326};
327
Steven Whitehousea447c092008-10-13 10:46:57 +0100328static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400329 {Opt_context, CONTEXT_STR "%s"},
330 {Opt_fscontext, FSCONTEXT_STR "%s"},
331 {Opt_defcontext, DEFCONTEXT_STR "%s"},
332 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500333 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400334 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335};
336
337#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
338
Eric Parisc312feb2006-07-10 04:43:53 -0700339static int may_context_mount_sb_relabel(u32 sid,
340 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100341 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700342{
David Howells275bb412008-11-14 10:39:19 +1100343 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700344 int rc;
345
346 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
347 FILESYSTEM__RELABELFROM, NULL);
348 if (rc)
349 return rc;
350
351 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
352 FILESYSTEM__RELABELTO, NULL);
353 return rc;
354}
355
Eric Paris08089252006-07-10 04:43:55 -0700356static int may_context_mount_inode_relabel(u32 sid,
357 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100358 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700359{
David Howells275bb412008-11-14 10:39:19 +1100360 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700361 int rc;
362 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
363 FILESYSTEM__RELABELFROM, NULL);
364 if (rc)
365 return rc;
366
367 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
368 FILESYSTEM__ASSOCIATE, NULL);
369 return rc;
370}
371
Eric Parisc9180a52007-11-30 13:00:35 -0500372static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 struct superblock_security_struct *sbsec = sb->s_security;
375 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500376 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 int rc = 0;
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
380 /* Make sure that the xattr handler exists and that no
381 error other than -ENODATA is returned by getxattr on
382 the root directory. -ENODATA is ok, as this may be
383 the first boot of the SELinux kernel before we have
384 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500385 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
387 "xattr support\n", sb->s_id, sb->s_type->name);
388 rc = -EOPNOTSUPP;
389 goto out;
390 }
Eric Parisc9180a52007-11-30 13:00:35 -0500391 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 if (rc < 0 && rc != -ENODATA) {
393 if (rc == -EOPNOTSUPP)
394 printk(KERN_WARNING "SELinux: (dev %s, type "
395 "%s) has no security xattr handler\n",
396 sb->s_id, sb->s_type->name);
397 else
398 printk(KERN_WARNING "SELinux: (dev %s, type "
399 "%s) getxattr errno %d\n", sb->s_id,
400 sb->s_type->name, -rc);
401 goto out;
402 }
403 }
404
David P. Quigley11689d42009-01-16 09:22:03 -0500405 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Eric Parisc9180a52007-11-30 13:00:35 -0500407 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500408 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500410 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500411 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 sb->s_id, sb->s_type->name,
413 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
David P. Quigley11689d42009-01-16 09:22:03 -0500415 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
416 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
417 sbsec->behavior == SECURITY_FS_USE_NONE ||
418 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
419 sbsec->flags &= ~SE_SBLABELSUPP;
420
David P. Quigleyddd29ec2009-09-09 14:25:37 -0400421 /* Special handling for sysfs. Is genfs but also has setxattr handler*/
422 if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
423 sbsec->flags |= SE_SBLABELSUPP;
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500426 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 /* Initialize any other inodes associated with the superblock, e.g.
429 inodes created prior to initial policy load or inodes created
430 during get_sb by a pseudo filesystem that directly
431 populates itself. */
432 spin_lock(&sbsec->isec_lock);
433next_inode:
434 if (!list_empty(&sbsec->isec_head)) {
435 struct inode_security_struct *isec =
436 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500437 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 struct inode *inode = isec->inode;
439 spin_unlock(&sbsec->isec_lock);
440 inode = igrab(inode);
441 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500442 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 inode_doinit(inode);
444 iput(inode);
445 }
446 spin_lock(&sbsec->isec_lock);
447 list_del_init(&isec->list);
448 goto next_inode;
449 }
450 spin_unlock(&sbsec->isec_lock);
451out:
Eric Parisc9180a52007-11-30 13:00:35 -0500452 return rc;
453}
454
455/*
456 * This function should allow an FS to ask what it's mount security
457 * options were so it can use those later for submounts, displaying
458 * mount options, or whatever.
459 */
460static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500461 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500462{
463 int rc = 0, i;
464 struct superblock_security_struct *sbsec = sb->s_security;
465 char *context = NULL;
466 u32 len;
467 char tmp;
468
Eric Parise0007522008-03-05 10:31:54 -0500469 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500470
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500471 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500472 return -EINVAL;
473
474 if (!ss_initialized)
475 return -EINVAL;
476
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500477 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500478 /* count the number of mount options for this sb */
479 for (i = 0; i < 8; i++) {
480 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500481 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500482 tmp >>= 1;
483 }
David P. Quigley11689d42009-01-16 09:22:03 -0500484 /* Check if the Label support flag is set */
485 if (sbsec->flags & SE_SBLABELSUPP)
486 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500487
Eric Parise0007522008-03-05 10:31:54 -0500488 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
489 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500490 rc = -ENOMEM;
491 goto out_free;
492 }
493
Eric Parise0007522008-03-05 10:31:54 -0500494 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
495 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500496 rc = -ENOMEM;
497 goto out_free;
498 }
499
500 i = 0;
501 if (sbsec->flags & FSCONTEXT_MNT) {
502 rc = security_sid_to_context(sbsec->sid, &context, &len);
503 if (rc)
504 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500505 opts->mnt_opts[i] = context;
506 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500507 }
508 if (sbsec->flags & CONTEXT_MNT) {
509 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
510 if (rc)
511 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500512 opts->mnt_opts[i] = context;
513 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500514 }
515 if (sbsec->flags & DEFCONTEXT_MNT) {
516 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
517 if (rc)
518 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500519 opts->mnt_opts[i] = context;
520 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500521 }
522 if (sbsec->flags & ROOTCONTEXT_MNT) {
523 struct inode *root = sbsec->sb->s_root->d_inode;
524 struct inode_security_struct *isec = root->i_security;
525
526 rc = security_sid_to_context(isec->sid, &context, &len);
527 if (rc)
528 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500529 opts->mnt_opts[i] = context;
530 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500531 }
David P. Quigley11689d42009-01-16 09:22:03 -0500532 if (sbsec->flags & SE_SBLABELSUPP) {
533 opts->mnt_opts[i] = NULL;
534 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
535 }
Eric Parisc9180a52007-11-30 13:00:35 -0500536
Eric Parise0007522008-03-05 10:31:54 -0500537 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500538
539 return 0;
540
541out_free:
Eric Parise0007522008-03-05 10:31:54 -0500542 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500543 return rc;
544}
545
546static int bad_option(struct superblock_security_struct *sbsec, char flag,
547 u32 old_sid, u32 new_sid)
548{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500549 char mnt_flags = sbsec->flags & SE_MNTMASK;
550
Eric Parisc9180a52007-11-30 13:00:35 -0500551 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500552 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500553 if (!(sbsec->flags & flag) ||
554 (old_sid != new_sid))
555 return 1;
556
557 /* check if we were passed the same options twice,
558 * aka someone passed context=a,context=b
559 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500560 if (!(sbsec->flags & SE_SBINITIALIZED))
561 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500562 return 1;
563 return 0;
564}
Eric Parise0007522008-03-05 10:31:54 -0500565
Eric Parisc9180a52007-11-30 13:00:35 -0500566/*
567 * Allow filesystems with binary mount data to explicitly set mount point
568 * labeling information.
569 */
Eric Parise0007522008-03-05 10:31:54 -0500570static int selinux_set_mnt_opts(struct super_block *sb,
571 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500572{
David Howells275bb412008-11-14 10:39:19 +1100573 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500574 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500575 struct superblock_security_struct *sbsec = sb->s_security;
576 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000577 struct inode *inode = sbsec->sb->s_root->d_inode;
578 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500579 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
580 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500581 char **mount_options = opts->mnt_opts;
582 int *flags = opts->mnt_opts_flags;
583 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500584
585 mutex_lock(&sbsec->lock);
586
587 if (!ss_initialized) {
588 if (!num_opts) {
589 /* Defer initialization until selinux_complete_init,
590 after the initial policy is loaded and the security
591 server is ready to handle calls. */
Eric Parisc9180a52007-11-30 13:00:35 -0500592 goto out;
593 }
594 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400595 printk(KERN_WARNING "SELinux: Unable to set superblock options "
596 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500597 goto out;
598 }
599
600 /*
Eric Parise0007522008-03-05 10:31:54 -0500601 * Binary mount data FS will come through this function twice. Once
602 * from an explicit call and once from the generic calls from the vfs.
603 * Since the generic VFS calls will not contain any security mount data
604 * we need to skip the double mount verification.
605 *
606 * This does open a hole in which we will not notice if the first
607 * mount using this sb set explict options and a second mount using
608 * this sb does not set any security options. (The first options
609 * will be used for both mounts)
610 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500611 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500612 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400613 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500614
615 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500616 * parse the mount options, check if they are valid sids.
617 * also check if someone is trying to mount the same sb more
618 * than once with different security options.
619 */
620 for (i = 0; i < num_opts; i++) {
621 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500622
623 if (flags[i] == SE_SBLABELSUPP)
624 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500625 rc = security_context_to_sid(mount_options[i],
626 strlen(mount_options[i]), &sid);
627 if (rc) {
628 printk(KERN_WARNING "SELinux: security_context_to_sid"
629 "(%s) failed for (dev %s, type %s) errno=%d\n",
630 mount_options[i], sb->s_id, name, rc);
631 goto out;
632 }
633 switch (flags[i]) {
634 case FSCONTEXT_MNT:
635 fscontext_sid = sid;
636
637 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
638 fscontext_sid))
639 goto out_double_mount;
640
641 sbsec->flags |= FSCONTEXT_MNT;
642 break;
643 case CONTEXT_MNT:
644 context_sid = sid;
645
646 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
647 context_sid))
648 goto out_double_mount;
649
650 sbsec->flags |= CONTEXT_MNT;
651 break;
652 case ROOTCONTEXT_MNT:
653 rootcontext_sid = sid;
654
655 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
656 rootcontext_sid))
657 goto out_double_mount;
658
659 sbsec->flags |= ROOTCONTEXT_MNT;
660
661 break;
662 case DEFCONTEXT_MNT:
663 defcontext_sid = sid;
664
665 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
666 defcontext_sid))
667 goto out_double_mount;
668
669 sbsec->flags |= DEFCONTEXT_MNT;
670
671 break;
672 default:
673 rc = -EINVAL;
674 goto out;
675 }
676 }
677
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500678 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500679 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500680 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500681 goto out_double_mount;
682 rc = 0;
683 goto out;
684 }
685
James Morris089be432008-07-15 18:32:49 +1000686 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500687 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500688
689 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500690 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500691 if (rc) {
692 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000693 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500694 goto out;
695 }
696
697 /* sets the context of the superblock for the fs being mounted. */
698 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100699 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500700 if (rc)
701 goto out;
702
703 sbsec->sid = fscontext_sid;
704 }
705
706 /*
707 * Switch to using mount point labeling behavior.
708 * sets the label used on all file below the mountpoint, and will set
709 * the superblock context if not already set.
710 */
711 if (context_sid) {
712 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100713 rc = may_context_mount_sb_relabel(context_sid, sbsec,
714 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500715 if (rc)
716 goto out;
717 sbsec->sid = context_sid;
718 } else {
David Howells275bb412008-11-14 10:39:19 +1100719 rc = may_context_mount_inode_relabel(context_sid, sbsec,
720 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500721 if (rc)
722 goto out;
723 }
724 if (!rootcontext_sid)
725 rootcontext_sid = context_sid;
726
727 sbsec->mntpoint_sid = context_sid;
728 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
729 }
730
731 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100732 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
733 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500734 if (rc)
735 goto out;
736
737 root_isec->sid = rootcontext_sid;
738 root_isec->initialized = 1;
739 }
740
741 if (defcontext_sid) {
742 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
743 rc = -EINVAL;
744 printk(KERN_WARNING "SELinux: defcontext option is "
745 "invalid for this filesystem type\n");
746 goto out;
747 }
748
749 if (defcontext_sid != sbsec->def_sid) {
750 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100751 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500752 if (rc)
753 goto out;
754 }
755
756 sbsec->def_sid = defcontext_sid;
757 }
758
759 rc = sb_finish_set_opts(sb);
760out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700761 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500763out_double_mount:
764 rc = -EINVAL;
765 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
766 "security settings for (dev %s, type %s)\n", sb->s_id, name);
767 goto out;
768}
769
770static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
771 struct super_block *newsb)
772{
773 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
774 struct superblock_security_struct *newsbsec = newsb->s_security;
775
776 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
777 int set_context = (oldsbsec->flags & CONTEXT_MNT);
778 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
779
Eric Paris0f5e6422008-04-21 16:24:11 -0400780 /*
781 * if the parent was able to be mounted it clearly had no special lsm
Al Viroe8c26252010-03-23 06:36:54 -0400782 * mount options. thus we can safely deal with this superblock later
Eric Paris0f5e6422008-04-21 16:24:11 -0400783 */
Al Viroe8c26252010-03-23 06:36:54 -0400784 if (!ss_initialized)
Eric Paris0f5e6422008-04-21 16:24:11 -0400785 return;
Eric Parisc9180a52007-11-30 13:00:35 -0500786
Eric Parisc9180a52007-11-30 13:00:35 -0500787 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500788 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500789
Eric Paris5a552612008-04-09 14:08:35 -0400790 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500791 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400792 return;
793
Eric Parisc9180a52007-11-30 13:00:35 -0500794 mutex_lock(&newsbsec->lock);
795
796 newsbsec->flags = oldsbsec->flags;
797
798 newsbsec->sid = oldsbsec->sid;
799 newsbsec->def_sid = oldsbsec->def_sid;
800 newsbsec->behavior = oldsbsec->behavior;
801
802 if (set_context) {
803 u32 sid = oldsbsec->mntpoint_sid;
804
805 if (!set_fscontext)
806 newsbsec->sid = sid;
807 if (!set_rootcontext) {
808 struct inode *newinode = newsb->s_root->d_inode;
809 struct inode_security_struct *newisec = newinode->i_security;
810 newisec->sid = sid;
811 }
812 newsbsec->mntpoint_sid = sid;
813 }
814 if (set_rootcontext) {
815 const struct inode *oldinode = oldsb->s_root->d_inode;
816 const struct inode_security_struct *oldisec = oldinode->i_security;
817 struct inode *newinode = newsb->s_root->d_inode;
818 struct inode_security_struct *newisec = newinode->i_security;
819
820 newisec->sid = oldisec->sid;
821 }
822
823 sb_finish_set_opts(newsb);
824 mutex_unlock(&newsbsec->lock);
825}
826
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200827static int selinux_parse_opts_str(char *options,
828 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500829{
Eric Parise0007522008-03-05 10:31:54 -0500830 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500831 char *context = NULL, *defcontext = NULL;
832 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500833 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500834
Eric Parise0007522008-03-05 10:31:54 -0500835 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500836
837 /* Standard string-based options. */
838 while ((p = strsep(&options, "|")) != NULL) {
839 int token;
840 substring_t args[MAX_OPT_ARGS];
841
842 if (!*p)
843 continue;
844
845 token = match_token(p, tokens, args);
846
847 switch (token) {
848 case Opt_context:
849 if (context || defcontext) {
850 rc = -EINVAL;
851 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
852 goto out_err;
853 }
854 context = match_strdup(&args[0]);
855 if (!context) {
856 rc = -ENOMEM;
857 goto out_err;
858 }
859 break;
860
861 case Opt_fscontext:
862 if (fscontext) {
863 rc = -EINVAL;
864 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
865 goto out_err;
866 }
867 fscontext = match_strdup(&args[0]);
868 if (!fscontext) {
869 rc = -ENOMEM;
870 goto out_err;
871 }
872 break;
873
874 case Opt_rootcontext:
875 if (rootcontext) {
876 rc = -EINVAL;
877 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
878 goto out_err;
879 }
880 rootcontext = match_strdup(&args[0]);
881 if (!rootcontext) {
882 rc = -ENOMEM;
883 goto out_err;
884 }
885 break;
886
887 case Opt_defcontext:
888 if (context || defcontext) {
889 rc = -EINVAL;
890 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
891 goto out_err;
892 }
893 defcontext = match_strdup(&args[0]);
894 if (!defcontext) {
895 rc = -ENOMEM;
896 goto out_err;
897 }
898 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500899 case Opt_labelsupport:
900 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500901 default:
902 rc = -EINVAL;
903 printk(KERN_WARNING "SELinux: unknown mount option\n");
904 goto out_err;
905
906 }
907 }
908
Eric Parise0007522008-03-05 10:31:54 -0500909 rc = -ENOMEM;
910 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
911 if (!opts->mnt_opts)
912 goto out_err;
913
914 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
915 if (!opts->mnt_opts_flags) {
916 kfree(opts->mnt_opts);
917 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500918 }
919
Eric Parise0007522008-03-05 10:31:54 -0500920 if (fscontext) {
921 opts->mnt_opts[num_mnt_opts] = fscontext;
922 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
923 }
924 if (context) {
925 opts->mnt_opts[num_mnt_opts] = context;
926 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
927 }
928 if (rootcontext) {
929 opts->mnt_opts[num_mnt_opts] = rootcontext;
930 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
931 }
932 if (defcontext) {
933 opts->mnt_opts[num_mnt_opts] = defcontext;
934 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
935 }
936
937 opts->num_mnt_opts = num_mnt_opts;
938 return 0;
939
Eric Parisc9180a52007-11-30 13:00:35 -0500940out_err:
941 kfree(context);
942 kfree(defcontext);
943 kfree(fscontext);
944 kfree(rootcontext);
945 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946}
Eric Parise0007522008-03-05 10:31:54 -0500947/*
948 * string mount options parsing and call set the sbsec
949 */
950static int superblock_doinit(struct super_block *sb, void *data)
951{
952 int rc = 0;
953 char *options = data;
954 struct security_mnt_opts opts;
955
956 security_init_mnt_opts(&opts);
957
958 if (!data)
959 goto out;
960
961 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
962
963 rc = selinux_parse_opts_str(options, &opts);
964 if (rc)
965 goto out_err;
966
967out:
968 rc = selinux_set_mnt_opts(sb, &opts);
969
970out_err:
971 security_free_mnt_opts(&opts);
972 return rc;
973}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Adrian Bunk3583a712008-07-22 20:21:23 +0300975static void selinux_write_opts(struct seq_file *m,
976 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000977{
978 int i;
979 char *prefix;
980
981 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -0500982 char *has_comma;
983
984 if (opts->mnt_opts[i])
985 has_comma = strchr(opts->mnt_opts[i], ',');
986 else
987 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +1000988
989 switch (opts->mnt_opts_flags[i]) {
990 case CONTEXT_MNT:
991 prefix = CONTEXT_STR;
992 break;
993 case FSCONTEXT_MNT:
994 prefix = FSCONTEXT_STR;
995 break;
996 case ROOTCONTEXT_MNT:
997 prefix = ROOTCONTEXT_STR;
998 break;
999 case DEFCONTEXT_MNT:
1000 prefix = DEFCONTEXT_STR;
1001 break;
David P. Quigley11689d42009-01-16 09:22:03 -05001002 case SE_SBLABELSUPP:
1003 seq_putc(m, ',');
1004 seq_puts(m, LABELSUPP_STR);
1005 continue;
Eric Paris2069f452008-07-04 09:47:13 +10001006 default:
1007 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001008 return;
Eric Paris2069f452008-07-04 09:47:13 +10001009 };
1010 /* we need a comma before each option */
1011 seq_putc(m, ',');
1012 seq_puts(m, prefix);
1013 if (has_comma)
1014 seq_putc(m, '\"');
1015 seq_puts(m, opts->mnt_opts[i]);
1016 if (has_comma)
1017 seq_putc(m, '\"');
1018 }
1019}
1020
1021static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1022{
1023 struct security_mnt_opts opts;
1024 int rc;
1025
1026 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001027 if (rc) {
1028 /* before policy load we may get EINVAL, don't show anything */
1029 if (rc == -EINVAL)
1030 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001031 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001032 }
Eric Paris2069f452008-07-04 09:47:13 +10001033
1034 selinux_write_opts(m, &opts);
1035
1036 security_free_mnt_opts(&opts);
1037
1038 return rc;
1039}
1040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041static inline u16 inode_mode_to_security_class(umode_t mode)
1042{
1043 switch (mode & S_IFMT) {
1044 case S_IFSOCK:
1045 return SECCLASS_SOCK_FILE;
1046 case S_IFLNK:
1047 return SECCLASS_LNK_FILE;
1048 case S_IFREG:
1049 return SECCLASS_FILE;
1050 case S_IFBLK:
1051 return SECCLASS_BLK_FILE;
1052 case S_IFDIR:
1053 return SECCLASS_DIR;
1054 case S_IFCHR:
1055 return SECCLASS_CHR_FILE;
1056 case S_IFIFO:
1057 return SECCLASS_FIFO_FILE;
1058
1059 }
1060
1061 return SECCLASS_FILE;
1062}
1063
James Morris13402582005-09-30 14:24:34 -04001064static inline int default_protocol_stream(int protocol)
1065{
1066 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1067}
1068
1069static inline int default_protocol_dgram(int protocol)
1070{
1071 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1072}
1073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1075{
1076 switch (family) {
1077 case PF_UNIX:
1078 switch (type) {
1079 case SOCK_STREAM:
1080 case SOCK_SEQPACKET:
1081 return SECCLASS_UNIX_STREAM_SOCKET;
1082 case SOCK_DGRAM:
1083 return SECCLASS_UNIX_DGRAM_SOCKET;
1084 }
1085 break;
1086 case PF_INET:
1087 case PF_INET6:
1088 switch (type) {
1089 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001090 if (default_protocol_stream(protocol))
1091 return SECCLASS_TCP_SOCKET;
1092 else
1093 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001095 if (default_protocol_dgram(protocol))
1096 return SECCLASS_UDP_SOCKET;
1097 else
1098 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001099 case SOCK_DCCP:
1100 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001101 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return SECCLASS_RAWIP_SOCKET;
1103 }
1104 break;
1105 case PF_NETLINK:
1106 switch (protocol) {
1107 case NETLINK_ROUTE:
1108 return SECCLASS_NETLINK_ROUTE_SOCKET;
1109 case NETLINK_FIREWALL:
1110 return SECCLASS_NETLINK_FIREWALL_SOCKET;
Pavel Emelyanov7f1fb602011-12-06 07:56:43 +00001111 case NETLINK_SOCK_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1113 case NETLINK_NFLOG:
1114 return SECCLASS_NETLINK_NFLOG_SOCKET;
1115 case NETLINK_XFRM:
1116 return SECCLASS_NETLINK_XFRM_SOCKET;
1117 case NETLINK_SELINUX:
1118 return SECCLASS_NETLINK_SELINUX_SOCKET;
1119 case NETLINK_AUDIT:
1120 return SECCLASS_NETLINK_AUDIT_SOCKET;
1121 case NETLINK_IP6_FW:
1122 return SECCLASS_NETLINK_IP6FW_SOCKET;
1123 case NETLINK_DNRTMSG:
1124 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001125 case NETLINK_KOBJECT_UEVENT:
1126 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 default:
1128 return SECCLASS_NETLINK_SOCKET;
1129 }
1130 case PF_PACKET:
1131 return SECCLASS_PACKET_SOCKET;
1132 case PF_KEY:
1133 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001134 case PF_APPLETALK:
1135 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
1137
1138 return SECCLASS_SOCKET;
1139}
1140
1141#ifdef CONFIG_PROC_FS
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001142static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 u16 tclass,
1144 u32 *sid)
1145{
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001146 int rc;
1147 char *buffer, *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Eric Paris828dfe12008-04-17 13:17:49 -04001149 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (!buffer)
1151 return -ENOMEM;
1152
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001153 path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
1154 if (IS_ERR(path))
1155 rc = PTR_ERR(path);
1156 else {
1157 /* each process gets a /proc/PID/ entry. Strip off the
1158 * PID part to get a valid selinux labeling.
1159 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
1160 while (path[1] >= '0' && path[1] <= '9') {
1161 path[1] = '/';
1162 path++;
1163 }
1164 rc = security_genfs_sid("proc", path, tclass, sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 free_page((unsigned long)buffer);
1167 return rc;
1168}
1169#else
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001170static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 u16 tclass,
1172 u32 *sid)
1173{
1174 return -EINVAL;
1175}
1176#endif
1177
1178/* The inode's security attributes must be initialized before first use. */
1179static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1180{
1181 struct superblock_security_struct *sbsec = NULL;
1182 struct inode_security_struct *isec = inode->i_security;
1183 u32 sid;
1184 struct dentry *dentry;
1185#define INITCONTEXTLEN 255
1186 char *context = NULL;
1187 unsigned len = 0;
1188 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 if (isec->initialized)
1191 goto out;
1192
Eric Paris23970742006-09-25 23:32:01 -07001193 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001195 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001198 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 /* Defer initialization until selinux_complete_init,
1200 after the initial policy is loaded and the security
1201 server is ready to handle calls. */
1202 spin_lock(&sbsec->isec_lock);
1203 if (list_empty(&isec->list))
1204 list_add(&isec->list, &sbsec->isec_head);
1205 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001206 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 }
1208
1209 switch (sbsec->behavior) {
1210 case SECURITY_FS_USE_XATTR:
1211 if (!inode->i_op->getxattr) {
1212 isec->sid = sbsec->def_sid;
1213 break;
1214 }
1215
1216 /* Need a dentry, since the xattr API requires one.
1217 Life would be simpler if we could just pass the inode. */
1218 if (opt_dentry) {
1219 /* Called from d_instantiate or d_splice_alias. */
1220 dentry = dget(opt_dentry);
1221 } else {
1222 /* Called from selinux_complete_init, try to find a dentry. */
1223 dentry = d_find_alias(inode);
1224 }
1225 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001226 /*
1227 * this is can be hit on boot when a file is accessed
1228 * before the policy is loaded. When we load policy we
1229 * may find inodes that have no dentry on the
1230 * sbsec->isec_head list. No reason to complain as these
1231 * will get fixed up the next time we go through
1232 * inode_doinit with a dentry, before these inodes could
1233 * be used again by userspace.
1234 */
Eric Paris23970742006-09-25 23:32:01 -07001235 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 }
1237
1238 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001239 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (!context) {
1241 rc = -ENOMEM;
1242 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001243 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001245 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1247 context, len);
1248 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001249 kfree(context);
1250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 /* Need a larger buffer. Query for the right size. */
1252 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1253 NULL, 0);
1254 if (rc < 0) {
1255 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001256 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001259 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 if (!context) {
1261 rc = -ENOMEM;
1262 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001263 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001265 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 rc = inode->i_op->getxattr(dentry,
1267 XATTR_NAME_SELINUX,
1268 context, len);
1269 }
1270 dput(dentry);
1271 if (rc < 0) {
1272 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001273 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001274 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 -rc, inode->i_sb->s_id, inode->i_ino);
1276 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001277 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 }
1279 /* Map ENODATA to the default file SID */
1280 sid = sbsec->def_sid;
1281 rc = 0;
1282 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001283 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001284 sbsec->def_sid,
1285 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001287 char *dev = inode->i_sb->s_id;
1288 unsigned long ino = inode->i_ino;
1289
1290 if (rc == -EINVAL) {
1291 if (printk_ratelimit())
1292 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1293 "context=%s. This indicates you may need to relabel the inode or the "
1294 "filesystem in question.\n", ino, dev, context);
1295 } else {
1296 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1297 "returned %d for dev=%s ino=%ld\n",
1298 __func__, context, -rc, dev, ino);
1299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 kfree(context);
1301 /* Leave with the unlabeled SID */
1302 rc = 0;
1303 break;
1304 }
1305 }
1306 kfree(context);
1307 isec->sid = sid;
1308 break;
1309 case SECURITY_FS_USE_TASK:
1310 isec->sid = isec->task_sid;
1311 break;
1312 case SECURITY_FS_USE_TRANS:
1313 /* Default to the fs SID. */
1314 isec->sid = sbsec->sid;
1315
1316 /* Try to obtain a transition SID. */
1317 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Eric Paris652bb9b2011-02-01 11:05:40 -05001318 rc = security_transition_sid(isec->task_sid, sbsec->sid,
1319 isec->sclass, NULL, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001321 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 isec->sid = sid;
1323 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001324 case SECURITY_FS_USE_MNTPOINT:
1325 isec->sid = sbsec->mntpoint_sid;
1326 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001328 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 isec->sid = sbsec->sid;
1330
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001331 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001332 if (opt_dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001334 rc = selinux_proc_get_sid(opt_dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 isec->sclass,
1336 &sid);
1337 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001338 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 isec->sid = sid;
1340 }
1341 }
1342 break;
1343 }
1344
1345 isec->initialized = 1;
1346
Eric Paris23970742006-09-25 23:32:01 -07001347out_unlock:
1348 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349out:
1350 if (isec->sclass == SECCLASS_FILE)
1351 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 return rc;
1353}
1354
1355/* Convert a Linux signal to an access vector. */
1356static inline u32 signal_to_av(int sig)
1357{
1358 u32 perm = 0;
1359
1360 switch (sig) {
1361 case SIGCHLD:
1362 /* Commonly granted from child to parent. */
1363 perm = PROCESS__SIGCHLD;
1364 break;
1365 case SIGKILL:
1366 /* Cannot be caught or ignored */
1367 perm = PROCESS__SIGKILL;
1368 break;
1369 case SIGSTOP:
1370 /* Cannot be caught or ignored */
1371 perm = PROCESS__SIGSTOP;
1372 break;
1373 default:
1374 /* All other signals. */
1375 perm = PROCESS__SIGNAL;
1376 break;
1377 }
1378
1379 return perm;
1380}
1381
David Howells275bb412008-11-14 10:39:19 +11001382/*
David Howellsd84f4f92008-11-14 10:39:23 +11001383 * Check permission between a pair of credentials
1384 * fork check, ptrace check, etc.
1385 */
1386static int cred_has_perm(const struct cred *actor,
1387 const struct cred *target,
1388 u32 perms)
1389{
1390 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1391
1392 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1393}
1394
1395/*
David Howells88e67f32008-11-14 10:39:21 +11001396 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001397 * fork check, ptrace check, etc.
1398 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001399 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001400 */
1401static int task_has_perm(const struct task_struct *tsk1,
1402 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 u32 perms)
1404{
David Howells275bb412008-11-14 10:39:19 +11001405 const struct task_security_struct *__tsec1, *__tsec2;
1406 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
David Howells275bb412008-11-14 10:39:19 +11001408 rcu_read_lock();
1409 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1410 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1411 rcu_read_unlock();
1412 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413}
1414
David Howells3b11a1d2008-11-14 10:39:26 +11001415/*
1416 * Check permission between current and another task, e.g. signal checks,
1417 * fork check, ptrace check, etc.
1418 * current is the actor and tsk2 is the target
1419 * - this uses current's subjective creds
1420 */
1421static int current_has_perm(const struct task_struct *tsk,
1422 u32 perms)
1423{
1424 u32 sid, tsid;
1425
1426 sid = current_sid();
1427 tsid = task_sid(tsk);
1428 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1429}
1430
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001431#if CAP_LAST_CAP > 63
1432#error Fix SELinux to handle capabilities > 63.
1433#endif
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435/* Check whether a task is allowed to use a capability. */
Eric Paris6a9de492012-01-03 12:25:14 -05001436static int cred_has_capability(const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001437 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438{
Thomas Liu2bf49692009-07-14 12:14:09 -04001439 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001440 struct selinux_audit_data sad = {0,};
Eric Paris06112162008-11-11 22:02:50 +11001441 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001442 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001443 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001444 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001445 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
Thomas Liu2bf49692009-07-14 12:14:09 -04001447 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001448 ad.selinux_audit_data = &sad;
Eric Paris6a9de492012-01-03 12:25:14 -05001449 ad.tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 ad.u.cap = cap;
1451
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001452 switch (CAP_TO_INDEX(cap)) {
1453 case 0:
1454 sclass = SECCLASS_CAPABILITY;
1455 break;
1456 case 1:
1457 sclass = SECCLASS_CAPABILITY2;
1458 break;
1459 default:
1460 printk(KERN_ERR
1461 "SELinux: out of range capability %d\n", cap);
1462 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001463 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001464 }
Eric Paris06112162008-11-11 22:02:50 +11001465
David Howells275bb412008-11-14 10:39:19 +11001466 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001467 if (audit == SECURITY_CAP_AUDIT) {
1468 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1469 if (rc2)
1470 return rc2;
1471 }
Eric Paris06112162008-11-11 22:02:50 +11001472 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473}
1474
1475/* Check whether a task is allowed to use a system operation. */
1476static int task_has_system(struct task_struct *tsk,
1477 u32 perms)
1478{
David Howells275bb412008-11-14 10:39:19 +11001479 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
David Howells275bb412008-11-14 10:39:19 +11001481 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 SECCLASS_SYSTEM, perms, NULL);
1483}
1484
1485/* Check whether a task has a particular permission to an inode.
1486 The 'adp' parameter is optional and allows other audit
1487 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001488static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 struct inode *inode,
1490 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001491 struct common_audit_data *adp,
1492 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001495 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
David Howellse0e81732009-09-02 09:13:40 +01001497 validate_creds(cred);
1498
Eric Paris828dfe12008-04-17 13:17:49 -04001499 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001500 return 0;
1501
David Howells88e67f32008-11-14 10:39:21 +11001502 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 isec = inode->i_security;
1504
Eric Paris9ade0cf2011-04-25 16:26:29 -04001505 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506}
1507
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001508static int inode_has_perm_noadp(const struct cred *cred,
1509 struct inode *inode,
1510 u32 perms,
1511 unsigned flags)
1512{
1513 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001514 struct selinux_audit_data sad = {0,};
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001515
1516 COMMON_AUDIT_DATA_INIT(&ad, INODE);
1517 ad.u.inode = inode;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001518 ad.selinux_audit_data = &sad;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001519 return inode_has_perm(cred, inode, perms, &ad, flags);
1520}
1521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522/* Same as inode_has_perm, but pass explicit audit data containing
1523 the dentry to help the auditing code to more easily generate the
1524 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001525static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 struct dentry *dentry,
1527 u32 av)
1528{
1529 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001530 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001531 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001532
Eric Paris2875fa02011-04-28 16:04:24 -04001533 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1534 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001535 ad.selinux_audit_data = &sad;
Eric Paris2875fa02011-04-28 16:04:24 -04001536 return inode_has_perm(cred, inode, av, &ad, 0);
1537}
1538
1539/* Same as inode_has_perm, but pass explicit audit data containing
1540 the path to help the auditing code to more easily generate the
1541 pathname if needed. */
1542static inline int path_has_perm(const struct cred *cred,
1543 struct path *path,
1544 u32 av)
1545{
1546 struct inode *inode = path->dentry->d_inode;
1547 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001548 struct selinux_audit_data sad = {0,};
Eric Paris2875fa02011-04-28 16:04:24 -04001549
Eric Parisf48b7392011-04-25 12:54:27 -04001550 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001551 ad.u.path = *path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001552 ad.selinux_audit_data = &sad;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001553 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554}
1555
1556/* Check whether a task can use an open file descriptor to
1557 access an inode in a given way. Check access to the
1558 descriptor itself, and then use dentry_has_perm to
1559 check a particular permission to the file.
1560 Access to the descriptor is implicitly granted if it
1561 has the same SID as the process. If av is zero, then
1562 access to the file is not checked, e.g. for cases
1563 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001564static int file_has_perm(const struct cred *cred,
1565 struct file *file,
1566 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001569 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001570 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001571 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001572 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 int rc;
1574
Eric Parisf48b7392011-04-25 12:54:27 -04001575 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1576 ad.u.path = file->f_path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001577 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
David Howells275bb412008-11-14 10:39:19 +11001579 if (sid != fsec->sid) {
1580 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 SECCLASS_FD,
1582 FD__USE,
1583 &ad);
1584 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001585 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 }
1587
1588 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001589 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001591 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
David Howells88e67f32008-11-14 10:39:21 +11001593out:
1594 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595}
1596
1597/* Check whether a task can create a file. */
1598static int may_create(struct inode *dir,
1599 struct dentry *dentry,
1600 u16 tclass)
1601{
Paul Moore5fb49872010-04-22 14:46:19 -04001602 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 struct inode_security_struct *dsec;
1604 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001605 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001606 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001607 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 int rc;
1609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 dsec = dir->i_security;
1611 sbsec = dir->i_sb->s_security;
1612
David Howells275bb412008-11-14 10:39:19 +11001613 sid = tsec->sid;
1614 newsid = tsec->create_sid;
1615
Eric Parisa2694342011-04-25 13:10:27 -04001616 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1617 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001618 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
David Howells275bb412008-11-14 10:39:19 +11001620 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 DIR__ADD_NAME | DIR__SEARCH,
1622 &ad);
1623 if (rc)
1624 return rc;
1625
David P. Quigleycd895962009-01-16 09:22:04 -05001626 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001627 rc = security_transition_sid(sid, dsec->sid, tclass,
1628 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (rc)
1630 return rc;
1631 }
1632
David Howells275bb412008-11-14 10:39:19 +11001633 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 if (rc)
1635 return rc;
1636
1637 return avc_has_perm(newsid, sbsec->sid,
1638 SECCLASS_FILESYSTEM,
1639 FILESYSTEM__ASSOCIATE, &ad);
1640}
1641
Michael LeMay4eb582c2006-06-26 00:24:57 -07001642/* Check whether a task can create a key. */
1643static int may_create_key(u32 ksid,
1644 struct task_struct *ctx)
1645{
David Howells275bb412008-11-14 10:39:19 +11001646 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001647
David Howells275bb412008-11-14 10:39:19 +11001648 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001649}
1650
Eric Paris828dfe12008-04-17 13:17:49 -04001651#define MAY_LINK 0
1652#define MAY_UNLINK 1
1653#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655/* Check whether a task can link, unlink, or rmdir a file/directory. */
1656static int may_link(struct inode *dir,
1657 struct dentry *dentry,
1658 int kind)
1659
1660{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001662 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001663 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001664 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 u32 av;
1666 int rc;
1667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 dsec = dir->i_security;
1669 isec = dentry->d_inode->i_security;
1670
Eric Parisa2694342011-04-25 13:10:27 -04001671 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1672 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001673 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 av = DIR__SEARCH;
1676 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001677 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 if (rc)
1679 return rc;
1680
1681 switch (kind) {
1682 case MAY_LINK:
1683 av = FILE__LINK;
1684 break;
1685 case MAY_UNLINK:
1686 av = FILE__UNLINK;
1687 break;
1688 case MAY_RMDIR:
1689 av = DIR__RMDIR;
1690 break;
1691 default:
Eric Paris744ba352008-04-17 11:52:44 -04001692 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1693 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 return 0;
1695 }
1696
David Howells275bb412008-11-14 10:39:19 +11001697 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 return rc;
1699}
1700
1701static inline int may_rename(struct inode *old_dir,
1702 struct dentry *old_dentry,
1703 struct inode *new_dir,
1704 struct dentry *new_dentry)
1705{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001707 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001708 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001709 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 u32 av;
1711 int old_is_dir, new_is_dir;
1712 int rc;
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 old_dsec = old_dir->i_security;
1715 old_isec = old_dentry->d_inode->i_security;
1716 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1717 new_dsec = new_dir->i_security;
1718
Eric Parisa2694342011-04-25 13:10:27 -04001719 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001720 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
Eric Parisa2694342011-04-25 13:10:27 -04001722 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001723 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1725 if (rc)
1726 return rc;
David Howells275bb412008-11-14 10:39:19 +11001727 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 old_isec->sclass, FILE__RENAME, &ad);
1729 if (rc)
1730 return rc;
1731 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001732 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 old_isec->sclass, DIR__REPARENT, &ad);
1734 if (rc)
1735 return rc;
1736 }
1737
Eric Parisa2694342011-04-25 13:10:27 -04001738 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 av = DIR__ADD_NAME | DIR__SEARCH;
1740 if (new_dentry->d_inode)
1741 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001742 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if (rc)
1744 return rc;
1745 if (new_dentry->d_inode) {
1746 new_isec = new_dentry->d_inode->i_security;
1747 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001748 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 new_isec->sclass,
1750 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1751 if (rc)
1752 return rc;
1753 }
1754
1755 return 0;
1756}
1757
1758/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001759static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 struct super_block *sb,
1761 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001762 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001765 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001768 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769}
1770
1771/* Convert a Linux mode and permission mask to an access vector. */
1772static inline u32 file_mask_to_av(int mode, int mask)
1773{
1774 u32 av = 0;
1775
Al Virodba19c62011-07-25 20:49:29 -04001776 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 if (mask & MAY_EXEC)
1778 av |= FILE__EXECUTE;
1779 if (mask & MAY_READ)
1780 av |= FILE__READ;
1781
1782 if (mask & MAY_APPEND)
1783 av |= FILE__APPEND;
1784 else if (mask & MAY_WRITE)
1785 av |= FILE__WRITE;
1786
1787 } else {
1788 if (mask & MAY_EXEC)
1789 av |= DIR__SEARCH;
1790 if (mask & MAY_WRITE)
1791 av |= DIR__WRITE;
1792 if (mask & MAY_READ)
1793 av |= DIR__READ;
1794 }
1795
1796 return av;
1797}
1798
1799/* Convert a Linux file to an access vector. */
1800static inline u32 file_to_av(struct file *file)
1801{
1802 u32 av = 0;
1803
1804 if (file->f_mode & FMODE_READ)
1805 av |= FILE__READ;
1806 if (file->f_mode & FMODE_WRITE) {
1807 if (file->f_flags & O_APPEND)
1808 av |= FILE__APPEND;
1809 else
1810 av |= FILE__WRITE;
1811 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001812 if (!av) {
1813 /*
1814 * Special file opened with flags 3 for ioctl-only use.
1815 */
1816 av = FILE__IOCTL;
1817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
1819 return av;
1820}
1821
Eric Paris8b6a5a32008-10-29 17:06:46 -04001822/*
1823 * Convert a file to an access vector and include the correct open
1824 * open permission.
1825 */
1826static inline u32 open_file_to_av(struct file *file)
1827{
1828 u32 av = file_to_av(file);
1829
Eric Paris49b7b8d2010-07-23 11:44:09 -04001830 if (selinux_policycap_openperm)
1831 av |= FILE__OPEN;
1832
Eric Paris8b6a5a32008-10-29 17:06:46 -04001833 return av;
1834}
1835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836/* Hook functions begin here. */
1837
Ingo Molnar9e488582009-05-07 19:26:19 +10001838static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001839 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 int rc;
1842
Ingo Molnar9e488582009-05-07 19:26:19 +10001843 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 if (rc)
1845 return rc;
1846
Eric Paris69f594a2012-01-03 12:25:15 -05001847 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001848 u32 sid = current_sid();
1849 u32 csid = task_sid(child);
1850 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001851 }
1852
David Howells3b11a1d2008-11-14 10:39:26 +11001853 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001854}
1855
1856static int selinux_ptrace_traceme(struct task_struct *parent)
1857{
1858 int rc;
1859
Eric Paris200ac532009-02-12 15:01:04 -05001860 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001861 if (rc)
1862 return rc;
1863
1864 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865}
1866
1867static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001868 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869{
1870 int error;
1871
David Howells3b11a1d2008-11-14 10:39:26 +11001872 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (error)
1874 return error;
1875
Eric Paris200ac532009-02-12 15:01:04 -05001876 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877}
1878
David Howellsd84f4f92008-11-14 10:39:23 +11001879static int selinux_capset(struct cred *new, const struct cred *old,
1880 const kernel_cap_t *effective,
1881 const kernel_cap_t *inheritable,
1882 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883{
1884 int error;
1885
Eric Paris200ac532009-02-12 15:01:04 -05001886 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001887 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (error)
1889 return error;
1890
David Howellsd84f4f92008-11-14 10:39:23 +11001891 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892}
1893
James Morris5626d3e2009-01-30 10:05:06 +11001894/*
1895 * (This comment used to live with the selinux_task_setuid hook,
1896 * which was removed).
1897 *
1898 * Since setuid only affects the current process, and since the SELinux
1899 * controls are not based on the Linux identity attributes, SELinux does not
1900 * need to control this operation. However, SELinux does control the use of
1901 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1902 */
1903
Eric Paris6a9de492012-01-03 12:25:14 -05001904static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1905 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906{
1907 int rc;
1908
Eric Paris6a9de492012-01-03 12:25:14 -05001909 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (rc)
1911 return rc;
1912
Eric Paris6a9de492012-01-03 12:25:14 -05001913 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914}
1915
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1917{
David Howells88e67f32008-11-14 10:39:21 +11001918 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 int rc = 0;
1920
1921 if (!sb)
1922 return 0;
1923
1924 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001925 case Q_SYNC:
1926 case Q_QUOTAON:
1927 case Q_QUOTAOFF:
1928 case Q_SETINFO:
1929 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001930 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001931 break;
1932 case Q_GETFMT:
1933 case Q_GETINFO:
1934 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001935 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001936 break;
1937 default:
1938 rc = 0; /* let the kernel handle invalid cmds */
1939 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941 return rc;
1942}
1943
1944static int selinux_quota_on(struct dentry *dentry)
1945{
David Howells88e67f32008-11-14 10:39:21 +11001946 const struct cred *cred = current_cred();
1947
Eric Paris2875fa02011-04-28 16:04:24 -04001948 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949}
1950
Eric Paris12b30522010-11-15 18:36:29 -05001951static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952{
1953 int rc;
1954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08001956 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
1957 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001958 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1959 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001960 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
1961 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
1962 /* Set level of messages printed to console */
1963 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04001964 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1965 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001966 case SYSLOG_ACTION_CLOSE: /* Close log */
1967 case SYSLOG_ACTION_OPEN: /* Open log */
1968 case SYSLOG_ACTION_READ: /* Read from log */
1969 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
1970 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001971 default:
1972 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1973 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 }
1975 return rc;
1976}
1977
1978/*
1979 * Check that a process has enough memory to allocate a new virtual
1980 * mapping. 0 means there is enough memory for the allocation to
1981 * succeed and -ENOMEM implies there is not.
1982 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 * Do not audit the selinux permission check, as this is applied to all
1984 * processes that allocate mappings.
1985 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001986static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987{
1988 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
Eric Paris6a9de492012-01-03 12:25:14 -05001990 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00001991 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 if (rc == 0)
1993 cap_sys_admin = 1;
1994
Alan Cox34b4e4a2007-08-22 14:01:28 -07001995 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996}
1997
1998/* binprm security operations */
1999
David Howellsa6f76f22008-11-14 10:39:24 +11002000static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
David Howellsa6f76f22008-11-14 10:39:24 +11002002 const struct task_security_struct *old_tsec;
2003 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002005 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002006 struct selinux_audit_data sad = {0,};
David Howellsa6f76f22008-11-14 10:39:24 +11002007 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 int rc;
2009
Eric Paris200ac532009-02-12 15:01:04 -05002010 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if (rc)
2012 return rc;
2013
David Howellsa6f76f22008-11-14 10:39:24 +11002014 /* SELinux context only depends on initial program or script and not
2015 * the script interpreter */
2016 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 return 0;
2018
David Howellsa6f76f22008-11-14 10:39:24 +11002019 old_tsec = current_security();
2020 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 isec = inode->i_security;
2022
2023 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002024 new_tsec->sid = old_tsec->sid;
2025 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Michael LeMay28eba5b2006-06-27 02:53:42 -07002027 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002028 new_tsec->create_sid = 0;
2029 new_tsec->keycreate_sid = 0;
2030 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031
David Howellsa6f76f22008-11-14 10:39:24 +11002032 if (old_tsec->exec_sid) {
2033 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002035 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 } else {
2037 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002038 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002039 SECCLASS_PROCESS, NULL,
2040 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 if (rc)
2042 return rc;
2043 }
2044
Eric Parisf48b7392011-04-25 12:54:27 -04002045 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002046 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002047 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048
Josef Sipek3d5ff522006-12-08 02:37:38 -08002049 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002050 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
David Howellsa6f76f22008-11-14 10:39:24 +11002052 if (new_tsec->sid == old_tsec->sid) {
2053 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2055 if (rc)
2056 return rc;
2057 } else {
2058 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002059 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2061 if (rc)
2062 return rc;
2063
David Howellsa6f76f22008-11-14 10:39:24 +11002064 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2066 if (rc)
2067 return rc;
2068
David Howellsa6f76f22008-11-14 10:39:24 +11002069 /* Check for shared state */
2070 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2071 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2072 SECCLASS_PROCESS, PROCESS__SHARE,
2073 NULL);
2074 if (rc)
2075 return -EPERM;
2076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
David Howellsa6f76f22008-11-14 10:39:24 +11002078 /* Make sure that anyone attempting to ptrace over a task that
2079 * changes its SID has the appropriate permit */
2080 if (bprm->unsafe &
2081 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2082 struct task_struct *tracer;
2083 struct task_security_struct *sec;
2084 u32 ptsid = 0;
2085
2086 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002087 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002088 if (likely(tracer != NULL)) {
2089 sec = __task_cred(tracer)->security;
2090 ptsid = sec->sid;
2091 }
2092 rcu_read_unlock();
2093
2094 if (ptsid != 0) {
2095 rc = avc_has_perm(ptsid, new_tsec->sid,
2096 SECCLASS_PROCESS,
2097 PROCESS__PTRACE, NULL);
2098 if (rc)
2099 return -EPERM;
2100 }
2101 }
2102
2103 /* Clear any possibly unsafe personality bits on exec: */
2104 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 }
2106
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 return 0;
2108}
2109
Eric Paris828dfe12008-04-17 13:17:49 -04002110static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111{
Paul Moore5fb49872010-04-22 14:46:19 -04002112 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002113 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 int atsecure = 0;
2115
David Howells275bb412008-11-14 10:39:19 +11002116 sid = tsec->sid;
2117 osid = tsec->osid;
2118
2119 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 /* Enable secure mode for SIDs transitions unless
2121 the noatsecure permission is granted between
2122 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002123 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002124 SECCLASS_PROCESS,
2125 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 }
2127
Eric Paris200ac532009-02-12 15:01:04 -05002128 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129}
2130
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002132static inline void flush_unauthorized_files(const struct cred *cred,
2133 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134{
Thomas Liu2bf49692009-07-14 12:14:09 -04002135 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002136 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002138 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002139 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002141 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002143 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002145 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002146 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002147 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002148 struct inode *inode;
2149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 /* Revalidate access to controlling tty.
2151 Use inode_has_perm on the tty inode directly rather
2152 than using file_has_perm, as this particular open
2153 file may belong to another process and we are only
2154 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002155 file_priv = list_first_entry(&tty->tty_files,
2156 struct tty_file_private, list);
2157 file = file_priv->file;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002158 inode = file->f_path.dentry->d_inode;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07002159 if (inode_has_perm_noadp(cred, inode,
2160 FILE__READ | FILE__WRITE, 0)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002161 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 }
2163 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002164 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002165 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002167 /* Reset controlling tty. */
2168 if (drop_tty)
2169 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
2171 /* Revalidate access to inherited open files. */
2172
Eric Parisf48b7392011-04-25 12:54:27 -04002173 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002174 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176 spin_lock(&files->file_lock);
2177 for (;;) {
2178 unsigned long set, i;
2179 int fd;
2180
2181 j++;
Josh Boyer27cd8f52012-07-25 10:40:34 -04002182 i = j * BITS_PER_LONG;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002183 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002184 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 break;
David Howells1fd36ad2012-02-16 17:49:54 +00002186 set = fdt->open_fds[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 if (!set)
2188 continue;
2189 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002190 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 if (set & 1) {
2192 file = fget(i);
2193 if (!file)
2194 continue;
David Howells88e67f32008-11-14 10:39:21 +11002195 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 file,
2197 file_to_av(file))) {
2198 sys_close(i);
2199 fd = get_unused_fd();
2200 if (fd != i) {
2201 if (fd >= 0)
2202 put_unused_fd(fd);
2203 fput(file);
2204 continue;
2205 }
2206 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002207 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 } else {
David Howells745ca242008-11-14 10:39:22 +11002209 devnull = dentry_open(
2210 dget(selinux_null),
2211 mntget(selinuxfs_mount),
2212 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002213 if (IS_ERR(devnull)) {
2214 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 put_unused_fd(fd);
2216 fput(file);
2217 continue;
2218 }
2219 }
2220 fd_install(fd, devnull);
2221 }
2222 fput(file);
2223 }
2224 }
2225 spin_lock(&files->file_lock);
2226
2227 }
2228 spin_unlock(&files->file_lock);
2229}
2230
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231/*
David Howellsa6f76f22008-11-14 10:39:24 +11002232 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 */
David Howellsa6f76f22008-11-14 10:39:24 +11002234static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235{
David Howellsa6f76f22008-11-14 10:39:24 +11002236 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 int rc, i;
2239
David Howellsa6f76f22008-11-14 10:39:24 +11002240 new_tsec = bprm->cred->security;
2241 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 return;
2243
2244 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002245 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
David Howellsa6f76f22008-11-14 10:39:24 +11002247 /* Always clear parent death signal on SID transitions. */
2248 current->pdeath_signal = 0;
2249
2250 /* Check whether the new SID can inherit resource limits from the old
2251 * SID. If not, reset all soft limits to the lower of the current
2252 * task's hard limit and the init task's soft limit.
2253 *
2254 * Note that the setting of hard limits (even to lower them) can be
2255 * controlled by the setrlimit check. The inclusion of the init task's
2256 * soft limit into the computation is to avoid resetting soft limits
2257 * higher than the default soft limit for cases where the default is
2258 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2259 */
2260 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2261 PROCESS__RLIMITINH, NULL);
2262 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002263 /* protect against do_prlimit() */
2264 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002265 for (i = 0; i < RLIM_NLIMITS; i++) {
2266 rlim = current->signal->rlim + i;
2267 initrlim = init_task.signal->rlim + i;
2268 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2269 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002270 task_unlock(current);
2271 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002272 }
2273}
2274
2275/*
2276 * Clean up the process immediately after the installation of new credentials
2277 * due to exec
2278 */
2279static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2280{
2281 const struct task_security_struct *tsec = current_security();
2282 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002283 u32 osid, sid;
2284 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002285
David Howellsa6f76f22008-11-14 10:39:24 +11002286 osid = tsec->osid;
2287 sid = tsec->sid;
2288
2289 if (sid == osid)
2290 return;
2291
2292 /* Check whether the new SID can inherit signal state from the old SID.
2293 * If not, clear itimers to avoid subsequent signal generation and
2294 * flush and unblock signals.
2295 *
2296 * This must occur _after_ the task SID has been updated so that any
2297 * kill done after the flush will be checked against the new SID.
2298 */
2299 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 if (rc) {
2301 memset(&itimer, 0, sizeof itimer);
2302 for (i = 0; i < 3; i++)
2303 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002305 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2306 __flush_signals(current);
2307 flush_signal_handlers(current, 1);
2308 sigemptyset(&current->blocked);
2309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 spin_unlock_irq(&current->sighand->siglock);
2311 }
2312
David Howellsa6f76f22008-11-14 10:39:24 +11002313 /* Wake up the parent if it is waiting so that it can recheck
2314 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002315 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002316 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002317 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318}
2319
2320/* superblock security operations */
2321
2322static int selinux_sb_alloc_security(struct super_block *sb)
2323{
2324 return superblock_alloc_security(sb);
2325}
2326
2327static void selinux_sb_free_security(struct super_block *sb)
2328{
2329 superblock_free_security(sb);
2330}
2331
2332static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2333{
2334 if (plen > olen)
2335 return 0;
2336
2337 return !memcmp(prefix, option, plen);
2338}
2339
2340static inline int selinux_option(char *option, int len)
2341{
Eric Paris832cbd92008-04-01 13:24:09 -04002342 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2343 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2344 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002345 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2346 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347}
2348
2349static inline void take_option(char **to, char *from, int *first, int len)
2350{
2351 if (!*first) {
2352 **to = ',';
2353 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002354 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 *first = 0;
2356 memcpy(*to, from, len);
2357 *to += len;
2358}
2359
Eric Paris828dfe12008-04-17 13:17:49 -04002360static inline void take_selinux_option(char **to, char *from, int *first,
2361 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002362{
2363 int current_size = 0;
2364
2365 if (!*first) {
2366 **to = '|';
2367 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002368 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002369 *first = 0;
2370
2371 while (current_size < len) {
2372 if (*from != '"') {
2373 **to = *from;
2374 *to += 1;
2375 }
2376 from += 1;
2377 current_size += 1;
2378 }
2379}
2380
Eric Parise0007522008-03-05 10:31:54 -05002381static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382{
2383 int fnosec, fsec, rc = 0;
2384 char *in_save, *in_curr, *in_end;
2385 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002386 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
2388 in_curr = orig;
2389 sec_curr = copy;
2390
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2392 if (!nosec) {
2393 rc = -ENOMEM;
2394 goto out;
2395 }
2396
2397 nosec_save = nosec;
2398 fnosec = fsec = 1;
2399 in_save = in_end = orig;
2400
2401 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002402 if (*in_end == '"')
2403 open_quote = !open_quote;
2404 if ((*in_end == ',' && open_quote == 0) ||
2405 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 int len = in_end - in_curr;
2407
2408 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002409 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 else
2411 take_option(&nosec, in_curr, &fnosec, len);
2412
2413 in_curr = in_end + 1;
2414 }
2415 } while (*in_end++);
2416
Eric Paris6931dfc2005-06-30 02:58:51 -07002417 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002418 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419out:
2420 return rc;
2421}
2422
Eric Paris026eb162011-03-03 16:09:14 -05002423static int selinux_sb_remount(struct super_block *sb, void *data)
2424{
2425 int rc, i, *flags;
2426 struct security_mnt_opts opts;
2427 char *secdata, **mount_options;
2428 struct superblock_security_struct *sbsec = sb->s_security;
2429
2430 if (!(sbsec->flags & SE_SBINITIALIZED))
2431 return 0;
2432
2433 if (!data)
2434 return 0;
2435
2436 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2437 return 0;
2438
2439 security_init_mnt_opts(&opts);
2440 secdata = alloc_secdata();
2441 if (!secdata)
2442 return -ENOMEM;
2443 rc = selinux_sb_copy_data(data, secdata);
2444 if (rc)
2445 goto out_free_secdata;
2446
2447 rc = selinux_parse_opts_str(secdata, &opts);
2448 if (rc)
2449 goto out_free_secdata;
2450
2451 mount_options = opts.mnt_opts;
2452 flags = opts.mnt_opts_flags;
2453
2454 for (i = 0; i < opts.num_mnt_opts; i++) {
2455 u32 sid;
2456 size_t len;
2457
2458 if (flags[i] == SE_SBLABELSUPP)
2459 continue;
2460 len = strlen(mount_options[i]);
2461 rc = security_context_to_sid(mount_options[i], len, &sid);
2462 if (rc) {
2463 printk(KERN_WARNING "SELinux: security_context_to_sid"
2464 "(%s) failed for (dev %s, type %s) errno=%d\n",
2465 mount_options[i], sb->s_id, sb->s_type->name, rc);
2466 goto out_free_opts;
2467 }
2468 rc = -EINVAL;
2469 switch (flags[i]) {
2470 case FSCONTEXT_MNT:
2471 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2472 goto out_bad_option;
2473 break;
2474 case CONTEXT_MNT:
2475 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2476 goto out_bad_option;
2477 break;
2478 case ROOTCONTEXT_MNT: {
2479 struct inode_security_struct *root_isec;
2480 root_isec = sb->s_root->d_inode->i_security;
2481
2482 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2483 goto out_bad_option;
2484 break;
2485 }
2486 case DEFCONTEXT_MNT:
2487 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2488 goto out_bad_option;
2489 break;
2490 default:
2491 goto out_free_opts;
2492 }
2493 }
2494
2495 rc = 0;
2496out_free_opts:
2497 security_free_mnt_opts(&opts);
2498out_free_secdata:
2499 free_secdata(secdata);
2500 return rc;
2501out_bad_option:
2502 printk(KERN_WARNING "SELinux: unable to change security options "
2503 "during remount (dev %s, type=%s)\n", sb->s_id,
2504 sb->s_type->name);
2505 goto out_free_opts;
2506}
2507
James Morris12204e22008-12-19 10:44:42 +11002508static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509{
David Howells88e67f32008-11-14 10:39:21 +11002510 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002511 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002512 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 int rc;
2514
2515 rc = superblock_doinit(sb, data);
2516 if (rc)
2517 return rc;
2518
James Morris74192242008-12-19 11:41:10 +11002519 /* Allow all mounts performed by the kernel */
2520 if (flags & MS_KERNMOUNT)
2521 return 0;
2522
Eric Parisa2694342011-04-25 13:10:27 -04002523 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002524 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002525 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002526 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527}
2528
David Howells726c3342006-06-23 02:02:58 -07002529static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530{
David Howells88e67f32008-11-14 10:39:21 +11002531 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002532 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002533 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Eric Parisa2694342011-04-25 13:10:27 -04002535 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002536 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002537 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002538 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539}
2540
Eric Paris828dfe12008-04-17 13:17:49 -04002541static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002542 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002543 char *type,
2544 unsigned long flags,
2545 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546{
David Howells88e67f32008-11-14 10:39:21 +11002547 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002550 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002551 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 else
Eric Paris2875fa02011-04-28 16:04:24 -04002553 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554}
2555
2556static int selinux_umount(struct vfsmount *mnt, int flags)
2557{
David Howells88e67f32008-11-14 10:39:21 +11002558 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
David Howells88e67f32008-11-14 10:39:21 +11002560 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002561 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562}
2563
2564/* inode security operations */
2565
2566static int selinux_inode_alloc_security(struct inode *inode)
2567{
2568 return inode_alloc_security(inode);
2569}
2570
2571static void selinux_inode_free_security(struct inode *inode)
2572{
2573 inode_free_security(inode);
2574}
2575
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002576static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002577 const struct qstr *qstr, char **name,
2578 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002579{
Paul Moore5fb49872010-04-22 14:46:19 -04002580 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002581 struct inode_security_struct *dsec;
2582 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002583 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002584 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002585 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002586
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002587 dsec = dir->i_security;
2588 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002589
David Howells275bb412008-11-14 10:39:19 +11002590 sid = tsec->sid;
2591 newsid = tsec->create_sid;
2592
Eric Paris415103f2010-12-02 16:13:40 -05002593 if ((sbsec->flags & SE_SBINITIALIZED) &&
2594 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2595 newsid = sbsec->mntpoint_sid;
2596 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002597 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002598 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002599 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002600 if (rc) {
2601 printk(KERN_WARNING "%s: "
2602 "security_transition_sid failed, rc=%d (dev=%s "
2603 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002604 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002605 -rc, inode->i_sb->s_id, inode->i_ino);
2606 return rc;
2607 }
2608 }
2609
Eric Paris296fddf2006-09-25 23:32:00 -07002610 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002611 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002612 struct inode_security_struct *isec = inode->i_security;
2613 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2614 isec->sid = newsid;
2615 isec->initialized = 1;
2616 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002617
David P. Quigleycd895962009-01-16 09:22:04 -05002618 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002619 return -EOPNOTSUPP;
2620
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002621 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002622 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002623 if (!namep)
2624 return -ENOMEM;
2625 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002626 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002627
2628 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002629 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002630 if (rc) {
2631 kfree(namep);
2632 return rc;
2633 }
2634 *value = context;
2635 *len = clen;
2636 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002637
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002638 return 0;
2639}
2640
Al Viro4acdaf22011-07-26 01:42:34 -04002641static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642{
2643 return may_create(dir, dentry, SECCLASS_FILE);
2644}
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2647{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return may_link(dir, old_dentry, MAY_LINK);
2649}
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2652{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 return may_link(dir, dentry, MAY_UNLINK);
2654}
2655
2656static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2657{
2658 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2659}
2660
Al Viro18bb1db2011-07-26 01:41:39 -04002661static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
2663 return may_create(dir, dentry, SECCLASS_DIR);
2664}
2665
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2667{
2668 return may_link(dir, dentry, MAY_RMDIR);
2669}
2670
Al Viro1a67aaf2011-07-26 01:52:52 -04002671static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2674}
2675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002677 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678{
2679 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2680}
2681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682static int selinux_inode_readlink(struct dentry *dentry)
2683{
David Howells88e67f32008-11-14 10:39:21 +11002684 const struct cred *cred = current_cred();
2685
Eric Paris2875fa02011-04-28 16:04:24 -04002686 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687}
2688
2689static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2690{
David Howells88e67f32008-11-14 10:39:21 +11002691 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Eric Paris2875fa02011-04-28 16:04:24 -04002693 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694}
2695
Al Viroe74f71e2011-06-20 19:38:15 -04002696static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
David Howells88e67f32008-11-14 10:39:21 +11002698 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002699 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002700 struct selinux_audit_data sad = {0,};
Eric Parisb782e0a2010-07-23 11:44:03 -04002701 u32 perms;
2702 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002703 unsigned flags = mask & MAY_NOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Eric Parisb782e0a2010-07-23 11:44:03 -04002705 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002706 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2707
Eric Parisb782e0a2010-07-23 11:44:03 -04002708 /* No permission to check. Existence test. */
2709 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
Eric Parisf48b7392011-04-25 12:54:27 -04002712 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002713 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002714 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002715
2716 if (from_access)
Eric Paris3b3b0e42012-04-03 09:37:02 -07002717 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
Eric Parisb782e0a2010-07-23 11:44:03 -04002718
2719 perms = file_mask_to_av(inode->i_mode, mask);
2720
Eric Paris9ade0cf2011-04-25 16:26:29 -04002721 return inode_has_perm(cred, inode, perms, &ad, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722}
2723
2724static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2725{
David Howells88e67f32008-11-14 10:39:21 +11002726 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002727 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002729 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2730 if (ia_valid & ATTR_FORCE) {
2731 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2732 ATTR_FORCE);
2733 if (!ia_valid)
2734 return 0;
2735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002737 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2738 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002739 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
Eric Paris2875fa02011-04-28 16:04:24 -04002741 return dentry_has_perm(cred, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742}
2743
2744static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2745{
David Howells88e67f32008-11-14 10:39:21 +11002746 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002747 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002748
Eric Paris2875fa02011-04-28 16:04:24 -04002749 path.dentry = dentry;
2750 path.mnt = mnt;
2751
2752 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753}
2754
David Howells8f0cfa52008-04-29 00:59:41 -07002755static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002756{
David Howells88e67f32008-11-14 10:39:21 +11002757 const struct cred *cred = current_cred();
2758
Serge E. Hallynb5376772007-10-16 23:31:36 -07002759 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2760 sizeof XATTR_SECURITY_PREFIX - 1)) {
2761 if (!strcmp(name, XATTR_NAME_CAPS)) {
2762 if (!capable(CAP_SETFCAP))
2763 return -EPERM;
2764 } else if (!capable(CAP_SYS_ADMIN)) {
2765 /* A different attribute in the security namespace.
2766 Restrict to administrator. */
2767 return -EPERM;
2768 }
2769 }
2770
2771 /* Not an attribute we recognize, so just check the
2772 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002773 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002774}
2775
David Howells8f0cfa52008-04-29 00:59:41 -07002776static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2777 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 struct inode *inode = dentry->d_inode;
2780 struct inode_security_struct *isec = inode->i_security;
2781 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002782 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002783 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11002784 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 int rc = 0;
2786
Serge E. Hallynb5376772007-10-16 23:31:36 -07002787 if (strcmp(name, XATTR_NAME_SELINUX))
2788 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002791 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 return -EOPNOTSUPP;
2793
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002794 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 return -EPERM;
2796
Eric Parisa2694342011-04-25 13:10:27 -04002797 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002798 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002799 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
David Howells275bb412008-11-14 10:39:19 +11002801 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 FILE__RELABELFROM, &ad);
2803 if (rc)
2804 return rc;
2805
2806 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002807 if (rc == -EINVAL) {
2808 if (!capable(CAP_MAC_ADMIN))
2809 return rc;
2810 rc = security_context_to_sid_force(value, size, &newsid);
2811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 if (rc)
2813 return rc;
2814
David Howells275bb412008-11-14 10:39:19 +11002815 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 FILE__RELABELTO, &ad);
2817 if (rc)
2818 return rc;
2819
David Howells275bb412008-11-14 10:39:19 +11002820 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002821 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 if (rc)
2823 return rc;
2824
2825 return avc_has_perm(newsid,
2826 sbsec->sid,
2827 SECCLASS_FILESYSTEM,
2828 FILESYSTEM__ASSOCIATE,
2829 &ad);
2830}
2831
David Howells8f0cfa52008-04-29 00:59:41 -07002832static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002833 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002834 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835{
2836 struct inode *inode = dentry->d_inode;
2837 struct inode_security_struct *isec = inode->i_security;
2838 u32 newsid;
2839 int rc;
2840
2841 if (strcmp(name, XATTR_NAME_SELINUX)) {
2842 /* Not an attribute we recognize, so nothing to do. */
2843 return;
2844 }
2845
Stephen Smalley12b29f32008-05-07 13:03:20 -04002846 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002848 printk(KERN_ERR "SELinux: unable to map context to SID"
2849 "for (%s, %lu), rc=%d\n",
2850 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 return;
2852 }
2853
2854 isec->sid = newsid;
2855 return;
2856}
2857
David Howells8f0cfa52008-04-29 00:59:41 -07002858static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859{
David Howells88e67f32008-11-14 10:39:21 +11002860 const struct cred *cred = current_cred();
2861
Eric Paris2875fa02011-04-28 16:04:24 -04002862 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863}
2864
Eric Paris828dfe12008-04-17 13:17:49 -04002865static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866{
David Howells88e67f32008-11-14 10:39:21 +11002867 const struct cred *cred = current_cred();
2868
Eric Paris2875fa02011-04-28 16:04:24 -04002869 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870}
2871
David Howells8f0cfa52008-04-29 00:59:41 -07002872static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002874 if (strcmp(name, XATTR_NAME_SELINUX))
2875 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
2877 /* No one is allowed to remove a SELinux security label.
2878 You can change the label, but all data must be labeled. */
2879 return -EACCES;
2880}
2881
James Morrisd381d8a2005-10-30 14:59:22 -08002882/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002883 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002884 *
2885 * Permission check is handled by selinux_inode_getxattr hook.
2886 */
David P. Quigley42492592008-02-04 22:29:39 -08002887static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888{
David P. Quigley42492592008-02-04 22:29:39 -08002889 u32 size;
2890 int error;
2891 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002894 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2895 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002897 /*
2898 * If the caller has CAP_MAC_ADMIN, then get the raw context
2899 * value even if it is not defined by current policy; otherwise,
2900 * use the in-core value under current policy.
2901 * Use the non-auditing forms of the permission checks since
2902 * getxattr may be called by unprivileged processes commonly
2903 * and lack of permission just means that we fall back to the
2904 * in-core context value, not a denial.
2905 */
Eric Paris6a9de492012-01-03 12:25:14 -05002906 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002907 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002908 if (!error)
2909 error = security_sid_to_context_force(isec->sid, &context,
2910 &size);
2911 else
2912 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002913 if (error)
2914 return error;
2915 error = size;
2916 if (alloc) {
2917 *buffer = context;
2918 goto out_nofree;
2919 }
2920 kfree(context);
2921out_nofree:
2922 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923}
2924
2925static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002926 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927{
2928 struct inode_security_struct *isec = inode->i_security;
2929 u32 newsid;
2930 int rc;
2931
2932 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2933 return -EOPNOTSUPP;
2934
2935 if (!value || !size)
2936 return -EACCES;
2937
Eric Paris828dfe12008-04-17 13:17:49 -04002938 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 if (rc)
2940 return rc;
2941
2942 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002943 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 return 0;
2945}
2946
2947static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2948{
2949 const int len = sizeof(XATTR_NAME_SELINUX);
2950 if (buffer && len <= buffer_size)
2951 memcpy(buffer, XATTR_NAME_SELINUX, len);
2952 return len;
2953}
2954
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002955static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2956{
2957 struct inode_security_struct *isec = inode->i_security;
2958 *secid = isec->sid;
2959}
2960
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961/* file security operations */
2962
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002963static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964{
David Howells88e67f32008-11-14 10:39:21 +11002965 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002966 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2969 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2970 mask |= MAY_APPEND;
2971
Paul Moore389fb802009-03-27 17:10:34 -04002972 return file_has_perm(cred, file,
2973 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974}
2975
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002976static int selinux_file_permission(struct file *file, int mask)
2977{
Stephen Smalley20dda182009-06-22 14:54:53 -04002978 struct inode *inode = file->f_path.dentry->d_inode;
2979 struct file_security_struct *fsec = file->f_security;
2980 struct inode_security_struct *isec = inode->i_security;
2981 u32 sid = current_sid();
2982
Paul Moore389fb802009-03-27 17:10:34 -04002983 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002984 /* No permission to check. Existence test. */
2985 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002986
Stephen Smalley20dda182009-06-22 14:54:53 -04002987 if (sid == fsec->sid && fsec->isid == isec->sid &&
2988 fsec->pseqno == avc_policy_seqno())
2989 /* No change since dentry_open check. */
2990 return 0;
2991
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002992 return selinux_revalidate_file_permission(file, mask);
2993}
2994
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995static int selinux_file_alloc_security(struct file *file)
2996{
2997 return file_alloc_security(file);
2998}
2999
3000static void selinux_file_free_security(struct file *file)
3001{
3002 file_free_security(file);
3003}
3004
3005static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3006 unsigned long arg)
3007{
David Howells88e67f32008-11-14 10:39:21 +11003008 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05003009 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
Eric Paris0b24dcb2011-02-25 15:39:20 -05003011 switch (cmd) {
3012 case FIONREAD:
3013 /* fall through */
3014 case FIBMAP:
3015 /* fall through */
3016 case FIGETBSZ:
3017 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003018 case FS_IOC_GETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003019 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003020 case FS_IOC_GETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003021 error = file_has_perm(cred, file, FILE__GETATTR);
3022 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Al Viro2f99c362012-03-23 16:04:05 -04003024 case FS_IOC_SETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003025 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003026 case FS_IOC_SETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003027 error = file_has_perm(cred, file, FILE__SETATTR);
3028 break;
3029
3030 /* sys_ioctl() checks */
3031 case FIONBIO:
3032 /* fall through */
3033 case FIOASYNC:
3034 error = file_has_perm(cred, file, 0);
3035 break;
3036
3037 case KDSKBENT:
3038 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05003039 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3040 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003041 break;
3042
3043 /* default case assumes that the command will go
3044 * to the file's ioctl() function.
3045 */
3046 default:
3047 error = file_has_perm(cred, file, FILE__IOCTL);
3048 }
3049 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050}
3051
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003052static int default_noexec;
3053
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3055{
David Howells88e67f32008-11-14 10:39:21 +11003056 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003057 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003058
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003059 if (default_noexec &&
3060 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 /*
3062 * We are making executable an anonymous mapping or a
3063 * private file mapping that will also be writable.
3064 * This has an additional check.
3065 */
David Howellsd84f4f92008-11-14 10:39:23 +11003066 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003068 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
3071 if (file) {
3072 /* read access is always possible with a mapping */
3073 u32 av = FILE__READ;
3074
3075 /* write access only matters if the mapping is shared */
3076 if (shared && (prot & PROT_WRITE))
3077 av |= FILE__WRITE;
3078
3079 if (prot & PROT_EXEC)
3080 av |= FILE__EXECUTE;
3081
David Howells88e67f32008-11-14 10:39:21 +11003082 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 }
David Howellsd84f4f92008-11-14 10:39:23 +11003084
3085error:
3086 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087}
3088
3089static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003090 unsigned long prot, unsigned long flags,
3091 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092{
Eric Parised032182007-06-28 15:55:21 -04003093 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003094 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Eric Paris84336d1a2009-07-31 12:54:05 -04003096 /*
3097 * notice that we are intentionally putting the SELinux check before
3098 * the secondary cap_file_mmap check. This is such a likely attempt
3099 * at bad behaviour/exploit that we always want to get the AVC, even
3100 * if DAC would have also denied the operation.
3101 */
Eric Parisa2551df2009-07-31 12:54:11 -04003102 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003103 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3104 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003105 if (rc)
3106 return rc;
3107 }
3108
3109 /* do DAC check on address space usage */
3110 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003111 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 return rc;
3113
3114 if (selinux_checkreqprot)
3115 prot = reqprot;
3116
3117 return file_map_prot_check(file, prot,
3118 (flags & MAP_TYPE) == MAP_SHARED);
3119}
3120
3121static int selinux_file_mprotect(struct vm_area_struct *vma,
3122 unsigned long reqprot,
3123 unsigned long prot)
3124{
David Howells88e67f32008-11-14 10:39:21 +11003125 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
3127 if (selinux_checkreqprot)
3128 prot = reqprot;
3129
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003130 if (default_noexec &&
3131 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003132 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003133 if (vma->vm_start >= vma->vm_mm->start_brk &&
3134 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003135 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003136 } else if (!vma->vm_file &&
3137 vma->vm_start <= vma->vm_mm->start_stack &&
3138 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003139 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003140 } else if (vma->vm_file && vma->anon_vma) {
3141 /*
3142 * We are making executable a file mapping that has
3143 * had some COW done. Since pages might have been
3144 * written, check ability to execute the possibly
3145 * modified content. This typically should only
3146 * occur for text relocations.
3147 */
David Howellsd84f4f92008-11-14 10:39:23 +11003148 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003149 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003150 if (rc)
3151 return rc;
3152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
3154 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3155}
3156
3157static int selinux_file_lock(struct file *file, unsigned int cmd)
3158{
David Howells88e67f32008-11-14 10:39:21 +11003159 const struct cred *cred = current_cred();
3160
3161 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162}
3163
3164static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3165 unsigned long arg)
3166{
David Howells88e67f32008-11-14 10:39:21 +11003167 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 int err = 0;
3169
3170 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003171 case F_SETFL:
3172 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3173 err = -EINVAL;
3174 break;
3175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
Eric Paris828dfe12008-04-17 13:17:49 -04003177 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003178 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003180 }
3181 /* fall through */
3182 case F_SETOWN:
3183 case F_SETSIG:
3184 case F_GETFL:
3185 case F_GETOWN:
3186 case F_GETSIG:
3187 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003188 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003189 break;
3190 case F_GETLK:
3191 case F_SETLK:
3192 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003194 case F_GETLK64:
3195 case F_SETLK64:
3196 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003198 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3199 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003201 }
David Howells88e67f32008-11-14 10:39:21 +11003202 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003203 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 }
3205
3206 return err;
3207}
3208
3209static int selinux_file_set_fowner(struct file *file)
3210{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 struct file_security_struct *fsec;
3212
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003214 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216 return 0;
3217}
3218
3219static int selinux_file_send_sigiotask(struct task_struct *tsk,
3220 struct fown_struct *fown, int signum)
3221{
Eric Paris828dfe12008-04-17 13:17:49 -04003222 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003223 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 struct file_security_struct *fsec;
3226
3227 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003228 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 fsec = file->f_security;
3231
3232 if (!signum)
3233 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3234 else
3235 perm = signal_to_av(signum);
3236
David Howells275bb412008-11-14 10:39:19 +11003237 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 SECCLASS_PROCESS, perm, NULL);
3239}
3240
3241static int selinux_file_receive(struct file *file)
3242{
David Howells88e67f32008-11-14 10:39:21 +11003243 const struct cred *cred = current_cred();
3244
3245 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246}
3247
David Howells745ca242008-11-14 10:39:22 +11003248static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003249{
3250 struct file_security_struct *fsec;
3251 struct inode *inode;
3252 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003253
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003254 inode = file->f_path.dentry->d_inode;
3255 fsec = file->f_security;
3256 isec = inode->i_security;
3257 /*
3258 * Save inode label and policy sequence number
3259 * at open-time so that selinux_file_permission
3260 * can determine whether revalidation is necessary.
3261 * Task label is already saved in the file security
3262 * struct as its SID.
3263 */
3264 fsec->isid = isec->sid;
3265 fsec->pseqno = avc_policy_seqno();
3266 /*
3267 * Since the inode label or policy seqno may have changed
3268 * between the selinux_inode_permission check and the saving
3269 * of state above, recheck that access is still permitted.
3270 * Otherwise, access might never be revalidated against the
3271 * new inode label or new policy.
3272 * This check is not redundant - do not remove.
3273 */
Linus Torvalds95f4efb2011-06-08 15:11:56 -07003274 return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003275}
3276
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277/* task security operations */
3278
3279static int selinux_task_create(unsigned long clone_flags)
3280{
David Howells3b11a1d2008-11-14 10:39:26 +11003281 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282}
3283
David Howellsf1752ee2008-11-14 10:39:17 +11003284/*
David Howellsee18d642009-09-02 09:14:21 +01003285 * allocate the SELinux part of blank credentials
3286 */
3287static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3288{
3289 struct task_security_struct *tsec;
3290
3291 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3292 if (!tsec)
3293 return -ENOMEM;
3294
3295 cred->security = tsec;
3296 return 0;
3297}
3298
3299/*
David Howellsf1752ee2008-11-14 10:39:17 +11003300 * detach and free the LSM part of a set of credentials
3301 */
3302static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
David Howellsf1752ee2008-11-14 10:39:17 +11003304 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003305
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003306 /*
3307 * cred->security == NULL if security_cred_alloc_blank() or
3308 * security_prepare_creds() returned an error.
3309 */
3310 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003311 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003312 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313}
3314
David Howellsd84f4f92008-11-14 10:39:23 +11003315/*
3316 * prepare a new set of credentials for modification
3317 */
3318static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3319 gfp_t gfp)
3320{
3321 const struct task_security_struct *old_tsec;
3322 struct task_security_struct *tsec;
3323
3324 old_tsec = old->security;
3325
3326 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3327 if (!tsec)
3328 return -ENOMEM;
3329
3330 new->security = tsec;
3331 return 0;
3332}
3333
3334/*
David Howellsee18d642009-09-02 09:14:21 +01003335 * transfer the SELinux data to a blank set of creds
3336 */
3337static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3338{
3339 const struct task_security_struct *old_tsec = old->security;
3340 struct task_security_struct *tsec = new->security;
3341
3342 *tsec = *old_tsec;
3343}
3344
3345/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003346 * set the security data for a kernel service
3347 * - all the creation contexts are set to unlabelled
3348 */
3349static int selinux_kernel_act_as(struct cred *new, u32 secid)
3350{
3351 struct task_security_struct *tsec = new->security;
3352 u32 sid = current_sid();
3353 int ret;
3354
3355 ret = avc_has_perm(sid, secid,
3356 SECCLASS_KERNEL_SERVICE,
3357 KERNEL_SERVICE__USE_AS_OVERRIDE,
3358 NULL);
3359 if (ret == 0) {
3360 tsec->sid = secid;
3361 tsec->create_sid = 0;
3362 tsec->keycreate_sid = 0;
3363 tsec->sockcreate_sid = 0;
3364 }
3365 return ret;
3366}
3367
3368/*
3369 * set the file creation context in a security record to the same as the
3370 * objective context of the specified inode
3371 */
3372static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3373{
3374 struct inode_security_struct *isec = inode->i_security;
3375 struct task_security_struct *tsec = new->security;
3376 u32 sid = current_sid();
3377 int ret;
3378
3379 ret = avc_has_perm(sid, isec->sid,
3380 SECCLASS_KERNEL_SERVICE,
3381 KERNEL_SERVICE__CREATE_FILES_AS,
3382 NULL);
3383
3384 if (ret == 0)
3385 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003386 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003387}
3388
Eric Parisdd8dbf22009-11-03 16:35:32 +11003389static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003390{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003391 u32 sid;
3392 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003393 struct selinux_audit_data sad = {0,};
Eric Parisdd8dbf22009-11-03 16:35:32 +11003394
3395 sid = task_sid(current);
3396
3397 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003398 ad.selinux_audit_data = &sad;
Eric Parisdd8dbf22009-11-03 16:35:32 +11003399 ad.u.kmod_name = kmod_name;
3400
3401 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3402 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003403}
3404
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3406{
David Howells3b11a1d2008-11-14 10:39:26 +11003407 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408}
3409
3410static int selinux_task_getpgid(struct task_struct *p)
3411{
David Howells3b11a1d2008-11-14 10:39:26 +11003412 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413}
3414
3415static int selinux_task_getsid(struct task_struct *p)
3416{
David Howells3b11a1d2008-11-14 10:39:26 +11003417 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418}
3419
David Quigleyf9008e42006-06-30 01:55:46 -07003420static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3421{
David Howells275bb412008-11-14 10:39:19 +11003422 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003423}
3424
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425static int selinux_task_setnice(struct task_struct *p, int nice)
3426{
3427 int rc;
3428
Eric Paris200ac532009-02-12 15:01:04 -05003429 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 if (rc)
3431 return rc;
3432
David Howells3b11a1d2008-11-14 10:39:26 +11003433 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434}
3435
James Morris03e68062006-06-23 02:03:58 -07003436static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3437{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003438 int rc;
3439
Eric Paris200ac532009-02-12 15:01:04 -05003440 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003441 if (rc)
3442 return rc;
3443
David Howells3b11a1d2008-11-14 10:39:26 +11003444 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003445}
3446
David Quigleya1836a42006-06-30 01:55:49 -07003447static int selinux_task_getioprio(struct task_struct *p)
3448{
David Howells3b11a1d2008-11-14 10:39:26 +11003449 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003450}
3451
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003452static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3453 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003455 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
3457 /* Control the ability to change the hard limit (whether
3458 lowering or raising it), so that the hard limit can
3459 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003460 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003462 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
3464 return 0;
3465}
3466
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003467static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003469 int rc;
3470
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003471 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003472 if (rc)
3473 return rc;
3474
David Howells3b11a1d2008-11-14 10:39:26 +11003475 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476}
3477
3478static int selinux_task_getscheduler(struct task_struct *p)
3479{
David Howells3b11a1d2008-11-14 10:39:26 +11003480 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481}
3482
David Quigley35601542006-06-23 02:04:01 -07003483static int selinux_task_movememory(struct task_struct *p)
3484{
David Howells3b11a1d2008-11-14 10:39:26 +11003485 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003486}
3487
David Quigleyf9008e42006-06-30 01:55:46 -07003488static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3489 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490{
3491 u32 perm;
3492 int rc;
3493
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 if (!sig)
3495 perm = PROCESS__SIGNULL; /* null signal; existence test */
3496 else
3497 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003498 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003499 rc = avc_has_perm(secid, task_sid(p),
3500 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003501 else
David Howells3b11a1d2008-11-14 10:39:26 +11003502 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003503 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504}
3505
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506static int selinux_task_wait(struct task_struct *p)
3507{
Eric Paris8a535142007-10-22 16:10:31 -04003508 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509}
3510
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511static void selinux_task_to_inode(struct task_struct *p,
3512 struct inode *inode)
3513{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003515 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
David Howells275bb412008-11-14 10:39:19 +11003517 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519}
3520
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003522static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003523 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524{
3525 int offset, ihlen, ret = -EINVAL;
3526 struct iphdr _iph, *ih;
3527
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003528 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3530 if (ih == NULL)
3531 goto out;
3532
3533 ihlen = ih->ihl * 4;
3534 if (ihlen < sizeof(_iph))
3535 goto out;
3536
Eric Paris48c62af2012-04-02 13:15:44 -04003537 ad->u.net->v4info.saddr = ih->saddr;
3538 ad->u.net->v4info.daddr = ih->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 ret = 0;
3540
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003541 if (proto)
3542 *proto = ih->protocol;
3543
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003545 case IPPROTO_TCP: {
3546 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547
Eric Paris828dfe12008-04-17 13:17:49 -04003548 if (ntohs(ih->frag_off) & IP_OFFSET)
3549 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
3551 offset += ihlen;
3552 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3553 if (th == NULL)
3554 break;
3555
Eric Paris48c62af2012-04-02 13:15:44 -04003556 ad->u.net->sport = th->source;
3557 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
Eric Paris828dfe12008-04-17 13:17:49 -04003561 case IPPROTO_UDP: {
3562 struct udphdr _udph, *uh;
3563
3564 if (ntohs(ih->frag_off) & IP_OFFSET)
3565 break;
3566
3567 offset += ihlen;
3568 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3569 if (uh == NULL)
3570 break;
3571
Eric Paris48c62af2012-04-02 13:15:44 -04003572 ad->u.net->sport = uh->source;
3573 ad->u.net->dport = uh->dest;
Eric Paris828dfe12008-04-17 13:17:49 -04003574 break;
3575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
James Morris2ee92d42006-11-13 16:09:01 -08003577 case IPPROTO_DCCP: {
3578 struct dccp_hdr _dccph, *dh;
3579
3580 if (ntohs(ih->frag_off) & IP_OFFSET)
3581 break;
3582
3583 offset += ihlen;
3584 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3585 if (dh == NULL)
3586 break;
3587
Eric Paris48c62af2012-04-02 13:15:44 -04003588 ad->u.net->sport = dh->dccph_sport;
3589 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003590 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003591 }
James Morris2ee92d42006-11-13 16:09:01 -08003592
Eric Paris828dfe12008-04-17 13:17:49 -04003593 default:
3594 break;
3595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596out:
3597 return ret;
3598}
3599
3600#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3601
3602/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003603static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003604 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
3606 u8 nexthdr;
3607 int ret = -EINVAL, offset;
3608 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003609 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003611 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3613 if (ip6 == NULL)
3614 goto out;
3615
Eric Paris48c62af2012-04-02 13:15:44 -04003616 ad->u.net->v6info.saddr = ip6->saddr;
3617 ad->u.net->v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 ret = 0;
3619
3620 nexthdr = ip6->nexthdr;
3621 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003622 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 if (offset < 0)
3624 goto out;
3625
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003626 if (proto)
3627 *proto = nexthdr;
3628
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 switch (nexthdr) {
3630 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003631 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
3633 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3634 if (th == NULL)
3635 break;
3636
Eric Paris48c62af2012-04-02 13:15:44 -04003637 ad->u.net->sport = th->source;
3638 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 break;
3640 }
3641
3642 case IPPROTO_UDP: {
3643 struct udphdr _udph, *uh;
3644
3645 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3646 if (uh == NULL)
3647 break;
3648
Eric Paris48c62af2012-04-02 13:15:44 -04003649 ad->u.net->sport = uh->source;
3650 ad->u.net->dport = uh->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 break;
3652 }
3653
James Morris2ee92d42006-11-13 16:09:01 -08003654 case IPPROTO_DCCP: {
3655 struct dccp_hdr _dccph, *dh;
3656
3657 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3658 if (dh == NULL)
3659 break;
3660
Eric Paris48c62af2012-04-02 13:15:44 -04003661 ad->u.net->sport = dh->dccph_sport;
3662 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003663 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003664 }
James Morris2ee92d42006-11-13 16:09:01 -08003665
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 /* includes fragments */
3667 default:
3668 break;
3669 }
3670out:
3671 return ret;
3672}
3673
3674#endif /* IPV6 */
3675
Thomas Liu2bf49692009-07-14 12:14:09 -04003676static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003677 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678{
David Howellscf9481e2008-07-27 21:31:07 +10003679 char *addrp;
3680 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Eric Paris48c62af2012-04-02 13:15:44 -04003682 switch (ad->u.net->family) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003684 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003685 if (ret)
3686 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003687 addrp = (char *)(src ? &ad->u.net->v4info.saddr :
3688 &ad->u.net->v4info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003689 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
3691#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3692 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003693 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003694 if (ret)
3695 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003696 addrp = (char *)(src ? &ad->u.net->v6info.saddr :
3697 &ad->u.net->v6info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003698 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699#endif /* IPV6 */
3700 default:
David Howellscf9481e2008-07-27 21:31:07 +10003701 addrp = NULL;
3702 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 }
3704
David Howellscf9481e2008-07-27 21:31:07 +10003705parse_error:
3706 printk(KERN_WARNING
3707 "SELinux: failure in selinux_parse_skb(),"
3708 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003710
3711okay:
3712 if (_addrp)
3713 *_addrp = addrp;
3714 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715}
3716
Paul Moore4f6a9932007-03-01 14:35:22 -05003717/**
Paul Moore220deb92008-01-29 08:38:23 -05003718 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003719 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003720 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003721 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003722 *
3723 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003724 * Check the various different forms of network peer labeling and determine
3725 * the peer label/SID for the packet; most of the magic actually occurs in
3726 * the security server function security_net_peersid_cmp(). The function
3727 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3728 * or -EACCES if @sid is invalid due to inconsistencies with the different
3729 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003730 *
3731 */
Paul Moore220deb92008-01-29 08:38:23 -05003732static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003733{
Paul Moore71f1cb02008-01-29 08:51:16 -05003734 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003735 u32 xfrm_sid;
3736 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003737 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003738
Paul Moore73ec9552013-12-10 14:57:54 -05003739 selinux_xfrm_skb_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003740 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003741
Paul Moore71f1cb02008-01-29 08:51:16 -05003742 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3743 if (unlikely(err)) {
3744 printk(KERN_WARNING
3745 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3746 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003747 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003748 }
Paul Moore220deb92008-01-29 08:38:23 -05003749
3750 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003751}
3752
Paul Moore2ea04e52013-12-04 16:10:51 -05003753/**
3754 * selinux_conn_sid - Determine the child socket label for a connection
3755 * @sk_sid: the parent socket's SID
3756 * @skb_sid: the packet's SID
3757 * @conn_sid: the resulting connection SID
3758 *
3759 * If @skb_sid is valid then the user:role:type information from @sk_sid is
3760 * combined with the MLS information from @skb_sid in order to create
3761 * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
3762 * of @sk_sid. Returns zero on success, negative values on failure.
3763 *
3764 */
3765static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
3766{
3767 int err = 0;
3768
3769 if (skb_sid != SECSID_NULL)
3770 err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid);
3771 else
3772 *conn_sid = sk_sid;
3773
3774 return err;
3775}
3776
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003778
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003779static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3780 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003781{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003782 if (tsec->sockcreate_sid > SECSID_NULL) {
3783 *socksid = tsec->sockcreate_sid;
3784 return 0;
3785 }
3786
3787 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3788 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003789}
3790
Paul Moore253bfae2010-04-22 14:46:19 -04003791static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792{
Paul Moore253bfae2010-04-22 14:46:19 -04003793 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003794 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003795 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003796 struct lsm_network_audit net = {0,};
Paul Moore253bfae2010-04-22 14:46:19 -04003797 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Paul Moore253bfae2010-04-22 14:46:19 -04003799 if (sksec->sid == SECINITSID_KERNEL)
3800 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801
Thomas Liu2bf49692009-07-14 12:14:09 -04003802 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003803 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003804 ad.u.net = &net;
3805 ad.u.net->sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
Paul Moore253bfae2010-04-22 14:46:19 -04003807 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808}
3809
3810static int selinux_socket_create(int family, int type,
3811 int protocol, int kern)
3812{
Paul Moore5fb49872010-04-22 14:46:19 -04003813 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003814 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003815 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003816 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
3818 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003819 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
David Howells275bb412008-11-14 10:39:19 +11003821 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003822 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3823 if (rc)
3824 return rc;
3825
Paul Moored4f2d972010-04-22 14:46:18 -04003826 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827}
3828
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003829static int selinux_socket_post_create(struct socket *sock, int family,
3830 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831{
Paul Moore5fb49872010-04-22 14:46:19 -04003832 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003833 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003834 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003835 int err = 0;
3836
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003837 isec->sclass = socket_type_to_security_class(family, type, protocol);
3838
David Howells275bb412008-11-14 10:39:19 +11003839 if (kern)
3840 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003841 else {
3842 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3843 if (err)
3844 return err;
3845 }
David Howells275bb412008-11-14 10:39:19 +11003846
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 isec->initialized = 1;
3848
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003849 if (sock->sk) {
3850 sksec = sock->sk->sk_security;
3851 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003852 sksec->sclass = isec->sclass;
Paul Moore389fb802009-03-27 17:10:34 -04003853 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003854 }
3855
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003856 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857}
3858
3859/* Range of port numbers used to automatically bind.
3860 Need to determine whether we should perform a name_bind
3861 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862
3863static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3864{
Paul Moore253bfae2010-04-22 14:46:19 -04003865 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 u16 family;
3867 int err;
3868
Paul Moore253bfae2010-04-22 14:46:19 -04003869 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 if (err)
3871 goto out;
3872
3873 /*
3874 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003875 * Multiple address binding for SCTP is not supported yet: we just
3876 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 */
Paul Moore253bfae2010-04-22 14:46:19 -04003878 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 if (family == PF_INET || family == PF_INET6) {
3880 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003881 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003882 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003883 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003884 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 struct sockaddr_in *addr4 = NULL;
3886 struct sockaddr_in6 *addr6 = NULL;
3887 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003888 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 if (family == PF_INET) {
3891 addr4 = (struct sockaddr_in *)address;
3892 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 addrp = (char *)&addr4->sin_addr.s_addr;
3894 } else {
3895 addr6 = (struct sockaddr_in6 *)address;
3896 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 addrp = (char *)&addr6->sin6_addr.s6_addr;
3898 }
3899
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003900 if (snum) {
3901 int low, high;
3902
3903 inet_get_local_port_range(&low, &high);
3904
3905 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003906 err = sel_netport_sid(sk->sk_protocol,
3907 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003908 if (err)
3909 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003910 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003911 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003912 ad.u.net = &net;
3913 ad.u.net->sport = htons(snum);
3914 ad.u.net->family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003915 err = avc_has_perm(sksec->sid, sid,
3916 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003917 SOCKET__NAME_BIND, &ad);
3918 if (err)
3919 goto out;
3920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 }
Eric Paris828dfe12008-04-17 13:17:49 -04003922
Paul Moore253bfae2010-04-22 14:46:19 -04003923 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003924 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 node_perm = TCP_SOCKET__NODE_BIND;
3926 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003927
James Morris13402582005-09-30 14:24:34 -04003928 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 node_perm = UDP_SOCKET__NODE_BIND;
3930 break;
James Morris2ee92d42006-11-13 16:09:01 -08003931
3932 case SECCLASS_DCCP_SOCKET:
3933 node_perm = DCCP_SOCKET__NODE_BIND;
3934 break;
3935
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 default:
3937 node_perm = RAWIP_SOCKET__NODE_BIND;
3938 break;
3939 }
Eric Paris828dfe12008-04-17 13:17:49 -04003940
Paul Moore224dfbd2008-01-29 08:38:13 -05003941 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 if (err)
3943 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003944
Thomas Liu2bf49692009-07-14 12:14:09 -04003945 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003946 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003947 ad.u.net = &net;
3948 ad.u.net->sport = htons(snum);
3949 ad.u.net->family = family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950
3951 if (family == PF_INET)
Eric Paris48c62af2012-04-02 13:15:44 -04003952 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 else
Eric Paris48c62af2012-04-02 13:15:44 -04003954 ad.u.net->v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955
Paul Moore253bfae2010-04-22 14:46:19 -04003956 err = avc_has_perm(sksec->sid, sid,
3957 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 if (err)
3959 goto out;
3960 }
3961out:
3962 return err;
3963}
3964
3965static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3966{
Paul Moore014ab192008-10-10 10:16:33 -04003967 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003968 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 int err;
3970
Paul Moore253bfae2010-04-22 14:46:19 -04003971 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 if (err)
3973 return err;
3974
3975 /*
James Morris2ee92d42006-11-13 16:09:01 -08003976 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 */
Paul Moore253bfae2010-04-22 14:46:19 -04003978 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
3979 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003980 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003981 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003982 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 struct sockaddr_in *addr4 = NULL;
3984 struct sockaddr_in6 *addr6 = NULL;
3985 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003986 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987
3988 if (sk->sk_family == PF_INET) {
3989 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003990 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 return -EINVAL;
3992 snum = ntohs(addr4->sin_port);
3993 } else {
3994 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003995 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return -EINVAL;
3997 snum = ntohs(addr6->sin6_port);
3998 }
3999
Paul Moore3e112172008-04-10 10:48:14 -04004000 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 if (err)
4002 goto out;
4003
Paul Moore253bfae2010-04-22 14:46:19 -04004004 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08004005 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
4006
Thomas Liu2bf49692009-07-14 12:14:09 -04004007 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004008 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004009 ad.u.net = &net;
4010 ad.u.net->dport = htons(snum);
4011 ad.u.net->family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04004012 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 if (err)
4014 goto out;
4015 }
4016
Paul Moore014ab192008-10-10 10:16:33 -04004017 err = selinux_netlbl_socket_connect(sk, address);
4018
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019out:
4020 return err;
4021}
4022
4023static int selinux_socket_listen(struct socket *sock, int backlog)
4024{
Paul Moore253bfae2010-04-22 14:46:19 -04004025 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026}
4027
4028static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
4029{
4030 int err;
4031 struct inode_security_struct *isec;
4032 struct inode_security_struct *newisec;
4033
Paul Moore253bfae2010-04-22 14:46:19 -04004034 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 if (err)
4036 return err;
4037
4038 newisec = SOCK_INODE(newsock)->i_security;
4039
4040 isec = SOCK_INODE(sock)->i_security;
4041 newisec->sclass = isec->sclass;
4042 newisec->sid = isec->sid;
4043 newisec->initialized = 1;
4044
4045 return 0;
4046}
4047
4048static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04004049 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050{
Paul Moore253bfae2010-04-22 14:46:19 -04004051 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052}
4053
4054static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4055 int size, int flags)
4056{
Paul Moore253bfae2010-04-22 14:46:19 -04004057 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058}
4059
4060static int selinux_socket_getsockname(struct socket *sock)
4061{
Paul Moore253bfae2010-04-22 14:46:19 -04004062 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063}
4064
4065static int selinux_socket_getpeername(struct socket *sock)
4066{
Paul Moore253bfae2010-04-22 14:46:19 -04004067 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068}
4069
Eric Paris828dfe12008-04-17 13:17:49 -04004070static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071{
Paul Mooref8687af2006-10-30 15:22:15 -08004072 int err;
4073
Paul Moore253bfae2010-04-22 14:46:19 -04004074 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08004075 if (err)
4076 return err;
4077
4078 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079}
4080
4081static int selinux_socket_getsockopt(struct socket *sock, int level,
4082 int optname)
4083{
Paul Moore253bfae2010-04-22 14:46:19 -04004084 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085}
4086
4087static int selinux_socket_shutdown(struct socket *sock, int how)
4088{
Paul Moore253bfae2010-04-22 14:46:19 -04004089 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090}
4091
David S. Miller3610cda2011-01-05 15:38:53 -08004092static int selinux_socket_unix_stream_connect(struct sock *sock,
4093 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 struct sock *newsk)
4095{
David S. Miller3610cda2011-01-05 15:38:53 -08004096 struct sk_security_struct *sksec_sock = sock->sk_security;
4097 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004098 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004099 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004100 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004101 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 int err;
4103
Thomas Liu2bf49692009-07-14 12:14:09 -04004104 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004105 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004106 ad.u.net = &net;
4107 ad.u.net->sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
Paul Moore4d1e2452010-04-22 14:46:18 -04004109 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4110 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4112 if (err)
4113 return err;
4114
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004116 sksec_new->peer_sid = sksec_sock->sid;
4117 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4118 &sksec_new->sid);
4119 if (err)
4120 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004121
Paul Moore4d1e2452010-04-22 14:46:18 -04004122 /* connecting socket */
4123 sksec_sock->peer_sid = sksec_new->sid;
4124
4125 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126}
4127
4128static int selinux_socket_unix_may_send(struct socket *sock,
4129 struct socket *other)
4130{
Paul Moore253bfae2010-04-22 14:46:19 -04004131 struct sk_security_struct *ssec = sock->sk->sk_security;
4132 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004133 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004134 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004135 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136
Thomas Liu2bf49692009-07-14 12:14:09 -04004137 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004138 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004139 ad.u.net = &net;
4140 ad.u.net->sk = other->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141
Paul Moore253bfae2010-04-22 14:46:19 -04004142 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4143 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144}
4145
Paul Mooreeffad8d2008-01-29 08:49:27 -05004146static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4147 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004148 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004149{
4150 int err;
4151 u32 if_sid;
4152 u32 node_sid;
4153
4154 err = sel_netif_sid(ifindex, &if_sid);
4155 if (err)
4156 return err;
4157 err = avc_has_perm(peer_sid, if_sid,
4158 SECCLASS_NETIF, NETIF__INGRESS, ad);
4159 if (err)
4160 return err;
4161
4162 err = sel_netnode_sid(addrp, family, &node_sid);
4163 if (err)
4164 return err;
4165 return avc_has_perm(peer_sid, node_sid,
4166 SECCLASS_NODE, NODE__RECVFROM, ad);
4167}
4168
Paul Moore220deb92008-01-29 08:38:23 -05004169static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004170 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004171{
Paul Moore277d3422008-12-31 12:54:11 -05004172 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004173 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004174 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004175 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004176 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004177 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004178 char *addrp;
4179
Thomas Liu2bf49692009-07-14 12:14:09 -04004180 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004181 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004182 ad.u.net = &net;
4183 ad.u.net->netif = skb->skb_iif;
4184 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004185 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4186 if (err)
4187 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004188
Paul Moore58bfbb52009-03-27 17:10:41 -04004189 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004190 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004191 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004192 if (err)
4193 return err;
4194 }
Paul Moore220deb92008-01-29 08:38:23 -05004195
Steffen Klassertb9679a72011-02-23 12:55:21 +01004196 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4197 if (err)
4198 return err;
4199 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004200
James Morris4e5ab4c2006-06-09 00:33:33 -07004201 return err;
4202}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004203
James Morris4e5ab4c2006-06-09 00:33:33 -07004204static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4205{
Paul Moore220deb92008-01-29 08:38:23 -05004206 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004207 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004208 u16 family = sk->sk_family;
4209 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004210 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004211 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004212 struct lsm_network_audit net = {0,};
Paul Moore220deb92008-01-29 08:38:23 -05004213 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004214 u8 secmark_active;
4215 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004216
James Morris4e5ab4c2006-06-09 00:33:33 -07004217 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004218 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004219
4220 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004221 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004222 family = PF_INET;
4223
Paul Moored8395c82008-10-10 10:16:30 -04004224 /* If any sort of compatibility mode is enabled then handoff processing
4225 * to the selinux_sock_rcv_skb_compat() function to deal with the
4226 * special handling. We do this in an attempt to keep this function
4227 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004228 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004229 return selinux_sock_rcv_skb_compat(sk, skb, family);
4230
4231 secmark_active = selinux_secmark_enabled();
4232 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4233 if (!secmark_active && !peerlbl_active)
4234 return 0;
4235
Thomas Liu2bf49692009-07-14 12:14:09 -04004236 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004237 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004238 ad.u.net = &net;
4239 ad.u.net->netif = skb->skb_iif;
4240 ad.u.net->family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004241 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004242 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004243 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004244
Paul Moored8395c82008-10-10 10:16:30 -04004245 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004246 u32 peer_sid;
4247
4248 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4249 if (err)
4250 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004251 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004252 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004253 if (err) {
4254 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004255 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004256 }
Paul Moored621d352008-01-29 08:43:36 -05004257 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4258 PEER__RECV, &ad);
Chad Hanson351381d2013-12-23 17:45:01 -05004259 if (err) {
Paul Mooredfaebe92008-10-10 10:16:31 -04004260 selinux_netlbl_err(skb, err, 0);
Chad Hanson351381d2013-12-23 17:45:01 -05004261 return err;
4262 }
Paul Moored621d352008-01-29 08:43:36 -05004263 }
4264
Paul Moored8395c82008-10-10 10:16:30 -04004265 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004266 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4267 PACKET__RECV, &ad);
4268 if (err)
4269 return err;
4270 }
4271
Paul Moored621d352008-01-29 08:43:36 -05004272 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273}
4274
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004275static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4276 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
4278 int err = 0;
4279 char *scontext;
4280 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004281 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004282 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Paul Moore253bfae2010-04-22 14:46:19 -04004284 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4285 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004286 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004287 if (peer_sid == SECSID_NULL)
4288 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004290 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004292 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293
4294 if (scontext_len > len) {
4295 err = -ERANGE;
4296 goto out_len;
4297 }
4298
4299 if (copy_to_user(optval, scontext, scontext_len))
4300 err = -EFAULT;
4301
4302out_len:
4303 if (put_user(scontext_len, optlen))
4304 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 return err;
4307}
4308
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004309static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004310{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004311 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004312 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004313
Paul Mooreaa862902008-10-10 10:16:29 -04004314 if (skb && skb->protocol == htons(ETH_P_IP))
4315 family = PF_INET;
4316 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4317 family = PF_INET6;
4318 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004319 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004320 else
4321 goto out;
4322
4323 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004324 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004325 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004326 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004327
Paul Moore75e22912008-01-29 08:38:04 -05004328out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004329 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004330 if (peer_secid == SECSID_NULL)
4331 return -EINVAL;
4332 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004333}
4334
Al Viro7d877f32005-10-21 03:20:43 -04004335static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336{
Paul Moore84914b72010-04-22 14:46:18 -04004337 struct sk_security_struct *sksec;
4338
4339 sksec = kzalloc(sizeof(*sksec), priority);
4340 if (!sksec)
4341 return -ENOMEM;
4342
4343 sksec->peer_sid = SECINITSID_UNLABELED;
4344 sksec->sid = SECINITSID_UNLABELED;
4345 selinux_netlbl_sk_security_reset(sksec);
4346 sk->sk_security = sksec;
4347
4348 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349}
4350
4351static void selinux_sk_free_security(struct sock *sk)
4352{
Paul Moore84914b72010-04-22 14:46:18 -04004353 struct sk_security_struct *sksec = sk->sk_security;
4354
4355 sk->sk_security = NULL;
4356 selinux_netlbl_sk_security_free(sksec);
4357 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358}
4359
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004360static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4361{
Eric Parisdd3e7832010-04-07 15:08:46 -04004362 struct sk_security_struct *sksec = sk->sk_security;
4363 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004364
Eric Parisdd3e7832010-04-07 15:08:46 -04004365 newsksec->sid = sksec->sid;
4366 newsksec->peer_sid = sksec->peer_sid;
4367 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004368
Eric Parisdd3e7832010-04-07 15:08:46 -04004369 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004370}
4371
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004372static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004373{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004374 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004375 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004376 else {
4377 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004378
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004379 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004380 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004381}
4382
Eric Paris828dfe12008-04-17 13:17:49 -04004383static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004384{
4385 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4386 struct sk_security_struct *sksec = sk->sk_security;
4387
David Woodhouse2148ccc2006-09-29 15:50:25 -07004388 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4389 sk->sk_family == PF_UNIX)
4390 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004391 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004392}
4393
Adrian Bunk9a673e52006-08-15 00:03:53 -07004394static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4395 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004396{
4397 struct sk_security_struct *sksec = sk->sk_security;
4398 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004399 u16 family = sk->sk_family;
Paul Moore2ea04e52013-12-04 16:10:51 -05004400 u32 connsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004401 u32 peersid;
4402
Paul Mooreaa862902008-10-10 10:16:29 -04004403 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4404 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4405 family = PF_INET;
4406
4407 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004408 if (err)
4409 return err;
Paul Moore2ea04e52013-12-04 16:10:51 -05004410 err = selinux_conn_sid(sksec->sid, peersid, &connsid);
4411 if (err)
4412 return err;
4413 req->secid = connsid;
4414 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004415
Paul Moore389fb802009-03-27 17:10:34 -04004416 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004417}
4418
Adrian Bunk9a673e52006-08-15 00:03:53 -07004419static void selinux_inet_csk_clone(struct sock *newsk,
4420 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004421{
4422 struct sk_security_struct *newsksec = newsk->sk_security;
4423
4424 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004425 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004426 /* NOTE: Ideally, we should also get the isec->sid for the
4427 new socket in sync, but we don't have the isec available yet.
4428 So we will wait until sock_graft to do it, by which
4429 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004430
Paul Moore9f2ad662006-11-17 17:38:53 -05004431 /* We don't need to take any sort of lock here as we are the only
4432 * thread with access to newsksec */
Paul Moore389fb802009-03-27 17:10:34 -04004433 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004434}
4435
Paul Moore014ab192008-10-10 10:16:33 -04004436static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004437{
Paul Mooreaa862902008-10-10 10:16:29 -04004438 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004439 struct sk_security_struct *sksec = sk->sk_security;
4440
Paul Mooreaa862902008-10-10 10:16:29 -04004441 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4442 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4443 family = PF_INET;
4444
4445 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004446}
4447
Eric Paris2606fd12010-10-13 16:24:41 -04004448static int selinux_secmark_relabel_packet(u32 sid)
4449{
4450 const struct task_security_struct *__tsec;
4451 u32 tsid;
4452
4453 __tsec = current_security();
4454 tsid = __tsec->sid;
4455
4456 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4457}
4458
4459static void selinux_secmark_refcount_inc(void)
4460{
4461 atomic_inc(&selinux_secmark_refcount);
4462}
4463
4464static void selinux_secmark_refcount_dec(void)
4465{
4466 atomic_dec(&selinux_secmark_refcount);
4467}
4468
Adrian Bunk9a673e52006-08-15 00:03:53 -07004469static void selinux_req_classify_flow(const struct request_sock *req,
4470 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004471{
David S. Miller1d28f422011-03-12 00:29:39 -05004472 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004473}
4474
Paul Mooreed6d76e2009-08-28 18:12:49 -04004475static int selinux_tun_dev_create(void)
4476{
4477 u32 sid = current_sid();
4478
4479 /* we aren't taking into account the "sockcreate" SID since the socket
4480 * that is being created here is not a socket in the traditional sense,
4481 * instead it is a private sock, accessible only to the kernel, and
4482 * representing a wide range of network traffic spanning multiple
4483 * connections unlike traditional sockets - check the TUN driver to
4484 * get a better understanding of why this socket is special */
4485
4486 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4487 NULL);
4488}
4489
4490static void selinux_tun_dev_post_create(struct sock *sk)
4491{
4492 struct sk_security_struct *sksec = sk->sk_security;
4493
4494 /* we don't currently perform any NetLabel based labeling here and it
4495 * isn't clear that we would want to do so anyway; while we could apply
4496 * labeling without the support of the TUN user the resulting labeled
4497 * traffic from the other end of the connection would almost certainly
4498 * cause confusion to the TUN user that had no idea network labeling
4499 * protocols were being used */
4500
4501 /* see the comments in selinux_tun_dev_create() about why we don't use
4502 * the sockcreate SID here */
4503
4504 sksec->sid = current_sid();
4505 sksec->sclass = SECCLASS_TUN_SOCKET;
4506}
4507
4508static int selinux_tun_dev_attach(struct sock *sk)
4509{
4510 struct sk_security_struct *sksec = sk->sk_security;
4511 u32 sid = current_sid();
4512 int err;
4513
4514 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4515 TUN_SOCKET__RELABELFROM, NULL);
4516 if (err)
4517 return err;
4518 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4519 TUN_SOCKET__RELABELTO, NULL);
4520 if (err)
4521 return err;
4522
4523 sksec->sid = sid;
4524
4525 return 0;
4526}
4527
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4529{
4530 int err = 0;
4531 u32 perm;
4532 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004533 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004534
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 if (skb->len < NLMSG_SPACE(0)) {
4536 err = -EINVAL;
4537 goto out;
4538 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004539 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004540
Paul Moore253bfae2010-04-22 14:46:19 -04004541 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 if (err) {
4543 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004544 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 "SELinux: unrecognized netlink message"
4546 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004547 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004548 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 err = 0;
4550 }
4551
4552 /* Ignore */
4553 if (err == -ENOENT)
4554 err = 0;
4555 goto out;
4556 }
4557
Paul Moore253bfae2010-04-22 14:46:19 -04004558 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559out:
4560 return err;
4561}
4562
4563#ifdef CONFIG_NETFILTER
4564
Paul Mooreeffad8d2008-01-29 08:49:27 -05004565static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4566 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567{
Paul Mooredfaebe92008-10-10 10:16:31 -04004568 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004569 char *addrp;
4570 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004571 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004572 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004573 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004574 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004575 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004576 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004577
Paul Mooreeffad8d2008-01-29 08:49:27 -05004578 if (!selinux_policycap_netpeer)
4579 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004580
Paul Mooreeffad8d2008-01-29 08:49:27 -05004581 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004582 netlbl_active = netlbl_enabled();
4583 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004584 if (!secmark_active && !peerlbl_active)
4585 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004586
Paul Moored8395c82008-10-10 10:16:30 -04004587 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4588 return NF_DROP;
4589
Thomas Liu2bf49692009-07-14 12:14:09 -04004590 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004591 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004592 ad.u.net = &net;
4593 ad.u.net->netif = ifindex;
4594 ad.u.net->family = family;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004595 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4596 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597
Paul Mooredfaebe92008-10-10 10:16:31 -04004598 if (peerlbl_active) {
4599 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4600 peer_sid, &ad);
4601 if (err) {
4602 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004603 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004604 }
4605 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004606
4607 if (secmark_active)
4608 if (avc_has_perm(peer_sid, skb->secmark,
4609 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4610 return NF_DROP;
4611
Paul Moore948bf852008-10-10 10:16:32 -04004612 if (netlbl_active)
4613 /* we do this in the FORWARD path and not the POST_ROUTING
4614 * path because we want to make sure we apply the necessary
4615 * labeling before IPsec is applied so we can leverage AH
4616 * protection */
4617 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4618 return NF_DROP;
4619
Paul Mooreeffad8d2008-01-29 08:49:27 -05004620 return NF_ACCEPT;
4621}
4622
4623static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4624 struct sk_buff *skb,
4625 const struct net_device *in,
4626 const struct net_device *out,
4627 int (*okfn)(struct sk_buff *))
4628{
4629 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4630}
4631
4632#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4633static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4634 struct sk_buff *skb,
4635 const struct net_device *in,
4636 const struct net_device *out,
4637 int (*okfn)(struct sk_buff *))
4638{
4639 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4640}
4641#endif /* IPV6 */
4642
Paul Moore948bf852008-10-10 10:16:32 -04004643static unsigned int selinux_ip_output(struct sk_buff *skb,
4644 u16 family)
4645{
Paul Moore1c5d9d12013-12-04 16:10:45 -05004646 struct sock *sk;
Paul Moore948bf852008-10-10 10:16:32 -04004647 u32 sid;
4648
4649 if (!netlbl_enabled())
4650 return NF_ACCEPT;
4651
4652 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4653 * because we want to make sure we apply the necessary labeling
4654 * before IPsec is applied so we can leverage AH protection */
Paul Moore1c5d9d12013-12-04 16:10:45 -05004655 sk = skb->sk;
4656 if (sk) {
4657 struct sk_security_struct *sksec;
4658
4659 if (sk->sk_state == TCP_LISTEN)
4660 /* if the socket is the listening state then this
4661 * packet is a SYN-ACK packet which means it needs to
4662 * be labeled based on the connection/request_sock and
4663 * not the parent socket. unfortunately, we can't
4664 * lookup the request_sock yet as it isn't queued on
4665 * the parent socket until after the SYN-ACK is sent.
4666 * the "solution" is to simply pass the packet as-is
4667 * as any IP option based labeling should be copied
4668 * from the initial connection request (in the IP
4669 * layer). it is far from ideal, but until we get a
4670 * security label in the packet itself this is the
4671 * best we can do. */
4672 return NF_ACCEPT;
4673
4674 /* standard practice, label using the parent socket */
4675 sksec = sk->sk_security;
Paul Moore948bf852008-10-10 10:16:32 -04004676 sid = sksec->sid;
4677 } else
4678 sid = SECINITSID_KERNEL;
4679 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4680 return NF_DROP;
4681
4682 return NF_ACCEPT;
4683}
4684
4685static unsigned int selinux_ipv4_output(unsigned int hooknum,
4686 struct sk_buff *skb,
4687 const struct net_device *in,
4688 const struct net_device *out,
4689 int (*okfn)(struct sk_buff *))
4690{
4691 return selinux_ip_output(skb, PF_INET);
4692}
4693
Paul Mooreeffad8d2008-01-29 08:49:27 -05004694static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4695 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004696 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004697{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004698 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004699 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004700 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004701 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004702 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004703 char *addrp;
4704 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004705
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706 if (sk == NULL)
4707 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004708 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004709
Thomas Liu2bf49692009-07-14 12:14:09 -04004710 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004711 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004712 ad.u.net = &net;
4713 ad.u.net->netif = ifindex;
4714 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004715 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4716 return NF_DROP;
4717
Paul Moore58bfbb52009-03-27 17:10:41 -04004718 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004719 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004720 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004721 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004722
Steffen Klassertb9679a72011-02-23 12:55:21 +01004723 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4724 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004725
Paul Mooreeffad8d2008-01-29 08:49:27 -05004726 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727}
4728
Paul Mooreeffad8d2008-01-29 08:49:27 -05004729static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4730 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004732 u32 secmark_perm;
4733 u32 peer_sid;
4734 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004735 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004736 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004737 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004738 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004739 u8 secmark_active;
4740 u8 peerlbl_active;
4741
Paul Mooreeffad8d2008-01-29 08:49:27 -05004742 /* If any sort of compatibility mode is enabled then handoff processing
4743 * to the selinux_ip_postroute_compat() function to deal with the
4744 * special handling. We do this in an attempt to keep this function
4745 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004746 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004747 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Moore420cc6d2013-12-10 14:58:01 -05004748
Paul Mooreeffad8d2008-01-29 08:49:27 -05004749 secmark_active = selinux_secmark_enabled();
4750 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4751 if (!secmark_active && !peerlbl_active)
4752 return NF_ACCEPT;
4753
Paul Mooreeffad8d2008-01-29 08:49:27 -05004754 sk = skb->sk;
Paul Moore420cc6d2013-12-10 14:58:01 -05004755
4756#ifdef CONFIG_XFRM
4757 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4758 * packet transformation so allow the packet to pass without any checks
4759 * since we'll have another chance to perform access control checks
4760 * when the packet is on it's final way out.
4761 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4762 * is NULL, in this case go ahead and apply access control.
4763 * is NULL, in this case go ahead and apply access control.
4764 * NOTE: if this is a local socket (skb->sk != NULL) that is in the
4765 * TCP listening state we cannot wait until the XFRM processing
4766 * is done as we will miss out on the SA label if we do;
4767 * unfortunately, this means more work, but it is only once per
4768 * connection. */
4769 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
4770 !(sk != NULL && sk->sk_state == TCP_LISTEN))
4771 return NF_ACCEPT;
4772#endif
4773
Paul Moored8395c82008-10-10 10:16:30 -04004774 if (sk == NULL) {
Paul Moore2ea04e52013-12-04 16:10:51 -05004775 /* Without an associated socket the packet is either coming
4776 * from the kernel or it is being forwarded; check the packet
4777 * to determine which and if the packet is being forwarded
4778 * query the packet directly to determine the security label. */
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004779 if (skb->skb_iif) {
4780 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004781 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004782 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004783 } else {
4784 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004785 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004786 }
Paul Moore2ea04e52013-12-04 16:10:51 -05004787 } else if (sk->sk_state == TCP_LISTEN) {
4788 /* Locally generated packet but the associated socket is in the
4789 * listening state which means this is a SYN-ACK packet. In
4790 * this particular case the correct security label is assigned
4791 * to the connection/request_sock but unfortunately we can't
4792 * query the request_sock as it isn't queued on the parent
4793 * socket until after the SYN-ACK packet is sent; the only
4794 * viable choice is to regenerate the label like we do in
4795 * selinux_inet_conn_request(). See also selinux_ip_output()
4796 * for similar problems. */
4797 u32 skb_sid;
4798 struct sk_security_struct *sksec = sk->sk_security;
4799 if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
4800 return NF_DROP;
Paul Moore420cc6d2013-12-10 14:58:01 -05004801 /* At this point, if the returned skb peerlbl is SECSID_NULL
4802 * and the packet has been through at least one XFRM
4803 * transformation then we must be dealing with the "final"
4804 * form of labeled IPsec packet; since we've already applied
4805 * all of our access controls on this packet we can safely
4806 * pass the packet. */
4807 if (skb_sid == SECSID_NULL) {
4808 switch (family) {
4809 case PF_INET:
4810 if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
4811 return NF_ACCEPT;
4812 break;
4813 case PF_INET6:
4814 if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
4815 return NF_ACCEPT;
4816 default:
4817 return NF_DROP_ERR(-ECONNREFUSED);
4818 }
4819 }
Paul Moore2ea04e52013-12-04 16:10:51 -05004820 if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
4821 return NF_DROP;
4822 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004823 } else {
Paul Moore2ea04e52013-12-04 16:10:51 -05004824 /* Locally generated packet, fetch the security label from the
4825 * associated socket. */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004826 struct sk_security_struct *sksec = sk->sk_security;
4827 peer_sid = sksec->sid;
4828 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004829 }
4830
Thomas Liu2bf49692009-07-14 12:14:09 -04004831 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004832 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004833 ad.u.net = &net;
4834 ad.u.net->netif = ifindex;
4835 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004836 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004837 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004838
Paul Mooreeffad8d2008-01-29 08:49:27 -05004839 if (secmark_active)
4840 if (avc_has_perm(peer_sid, skb->secmark,
4841 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004842 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004843
4844 if (peerlbl_active) {
4845 u32 if_sid;
4846 u32 node_sid;
4847
4848 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004849 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004850 if (avc_has_perm(peer_sid, if_sid,
4851 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004852 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004853
4854 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004855 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004856 if (avc_has_perm(peer_sid, node_sid,
4857 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004858 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004859 }
4860
4861 return NF_ACCEPT;
4862}
4863
4864static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4865 struct sk_buff *skb,
4866 const struct net_device *in,
4867 const struct net_device *out,
4868 int (*okfn)(struct sk_buff *))
4869{
4870 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871}
4872
4873#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004874static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4875 struct sk_buff *skb,
4876 const struct net_device *in,
4877 const struct net_device *out,
4878 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004880 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882#endif /* IPV6 */
4883
4884#endif /* CONFIG_NETFILTER */
4885
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4887{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 int err;
4889
Eric Paris200ac532009-02-12 15:01:04 -05004890 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 if (err)
4892 return err;
4893
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004894 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895}
4896
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897static int ipc_alloc_security(struct task_struct *task,
4898 struct kern_ipc_perm *perm,
4899 u16 sclass)
4900{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004902 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
James Morris89d155e2005-10-30 14:59:21 -08004904 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 if (!isec)
4906 return -ENOMEM;
4907
David Howells275bb412008-11-14 10:39:19 +11004908 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004910 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 perm->security = isec;
4912
4913 return 0;
4914}
4915
4916static void ipc_free_security(struct kern_ipc_perm *perm)
4917{
4918 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 perm->security = NULL;
4920 kfree(isec);
4921}
4922
4923static int msg_msg_alloc_security(struct msg_msg *msg)
4924{
4925 struct msg_security_struct *msec;
4926
James Morris89d155e2005-10-30 14:59:21 -08004927 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 if (!msec)
4929 return -ENOMEM;
4930
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 msec->sid = SECINITSID_UNLABELED;
4932 msg->security = msec;
4933
4934 return 0;
4935}
4936
4937static void msg_msg_free_security(struct msg_msg *msg)
4938{
4939 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940
4941 msg->security = NULL;
4942 kfree(msec);
4943}
4944
4945static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004946 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004949 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004950 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004951 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 isec = ipc_perms->security;
4954
Thomas Liu2bf49692009-07-14 12:14:09 -04004955 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004956 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 ad.u.ipc_id = ipc_perms->key;
4958
David Howells275bb412008-11-14 10:39:19 +11004959 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960}
4961
4962static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4963{
4964 return msg_msg_alloc_security(msg);
4965}
4966
4967static void selinux_msg_msg_free_security(struct msg_msg *msg)
4968{
4969 msg_msg_free_security(msg);
4970}
4971
4972/* message queue security operations */
4973static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4974{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004976 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004977 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004978 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 int rc;
4980
4981 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4982 if (rc)
4983 return rc;
4984
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 isec = msq->q_perm.security;
4986
Thomas Liu2bf49692009-07-14 12:14:09 -04004987 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004988 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04004989 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
David Howells275bb412008-11-14 10:39:19 +11004991 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 MSGQ__CREATE, &ad);
4993 if (rc) {
4994 ipc_free_security(&msq->q_perm);
4995 return rc;
4996 }
4997 return 0;
4998}
4999
5000static void selinux_msg_queue_free_security(struct msg_queue *msq)
5001{
5002 ipc_free_security(&msq->q_perm);
5003}
5004
5005static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
5006{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005008 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005009 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005010 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 isec = msq->q_perm.security;
5013
Thomas Liu2bf49692009-07-14 12:14:09 -04005014 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005015 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 ad.u.ipc_id = msq->q_perm.key;
5017
David Howells275bb412008-11-14 10:39:19 +11005018 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 MSGQ__ASSOCIATE, &ad);
5020}
5021
5022static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
5023{
5024 int err;
5025 int perms;
5026
Eric Paris828dfe12008-04-17 13:17:49 -04005027 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 case IPC_INFO:
5029 case MSG_INFO:
5030 /* No specific object, just general system-wide information. */
5031 return task_has_system(current, SYSTEM__IPC_INFO);
5032 case IPC_STAT:
5033 case MSG_STAT:
5034 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
5035 break;
5036 case IPC_SET:
5037 perms = MSGQ__SETATTR;
5038 break;
5039 case IPC_RMID:
5040 perms = MSGQ__DESTROY;
5041 break;
5042 default:
5043 return 0;
5044 }
5045
Stephen Smalley6af963f2005-05-01 08:58:39 -07005046 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 return err;
5048}
5049
5050static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
5051{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 struct ipc_security_struct *isec;
5053 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005054 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005055 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005056 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 int rc;
5058
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 isec = msq->q_perm.security;
5060 msec = msg->security;
5061
5062 /*
5063 * First time through, need to assign label to the message
5064 */
5065 if (msec->sid == SECINITSID_UNLABELED) {
5066 /*
5067 * Compute new sid based on current process and
5068 * message queue this message will be stored in
5069 */
David Howells275bb412008-11-14 10:39:19 +11005070 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05005071 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 if (rc)
5073 return rc;
5074 }
5075
Thomas Liu2bf49692009-07-14 12:14:09 -04005076 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005077 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 ad.u.ipc_id = msq->q_perm.key;
5079
5080 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005081 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 MSGQ__WRITE, &ad);
5083 if (!rc)
5084 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005085 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5086 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 if (!rc)
5088 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005089 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5090 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091
5092 return rc;
5093}
5094
5095static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5096 struct task_struct *target,
5097 long type, int mode)
5098{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 struct ipc_security_struct *isec;
5100 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005101 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005102 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005103 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 int rc;
5105
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 isec = msq->q_perm.security;
5107 msec = msg->security;
5108
Thomas Liu2bf49692009-07-14 12:14:09 -04005109 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005110 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005111 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
David Howells275bb412008-11-14 10:39:19 +11005113 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 SECCLASS_MSGQ, MSGQ__READ, &ad);
5115 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005116 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 SECCLASS_MSG, MSG__RECEIVE, &ad);
5118 return rc;
5119}
5120
5121/* Shared Memory security operations */
5122static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5123{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005125 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005126 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005127 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 int rc;
5129
5130 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5131 if (rc)
5132 return rc;
5133
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 isec = shp->shm_perm.security;
5135
Thomas Liu2bf49692009-07-14 12:14:09 -04005136 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005137 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005138 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139
David Howells275bb412008-11-14 10:39:19 +11005140 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 SHM__CREATE, &ad);
5142 if (rc) {
5143 ipc_free_security(&shp->shm_perm);
5144 return rc;
5145 }
5146 return 0;
5147}
5148
5149static void selinux_shm_free_security(struct shmid_kernel *shp)
5150{
5151 ipc_free_security(&shp->shm_perm);
5152}
5153
5154static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5155{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005157 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005158 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005159 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 isec = shp->shm_perm.security;
5162
Thomas Liu2bf49692009-07-14 12:14:09 -04005163 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005164 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 ad.u.ipc_id = shp->shm_perm.key;
5166
David Howells275bb412008-11-14 10:39:19 +11005167 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 SHM__ASSOCIATE, &ad);
5169}
5170
5171/* Note, at this point, shp is locked down */
5172static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5173{
5174 int perms;
5175 int err;
5176
Eric Paris828dfe12008-04-17 13:17:49 -04005177 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 case IPC_INFO:
5179 case SHM_INFO:
5180 /* No specific object, just general system-wide information. */
5181 return task_has_system(current, SYSTEM__IPC_INFO);
5182 case IPC_STAT:
5183 case SHM_STAT:
5184 perms = SHM__GETATTR | SHM__ASSOCIATE;
5185 break;
5186 case IPC_SET:
5187 perms = SHM__SETATTR;
5188 break;
5189 case SHM_LOCK:
5190 case SHM_UNLOCK:
5191 perms = SHM__LOCK;
5192 break;
5193 case IPC_RMID:
5194 perms = SHM__DESTROY;
5195 break;
5196 default:
5197 return 0;
5198 }
5199
Stephen Smalley6af963f2005-05-01 08:58:39 -07005200 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 return err;
5202}
5203
5204static int selinux_shm_shmat(struct shmid_kernel *shp,
5205 char __user *shmaddr, int shmflg)
5206{
5207 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208
5209 if (shmflg & SHM_RDONLY)
5210 perms = SHM__READ;
5211 else
5212 perms = SHM__READ | SHM__WRITE;
5213
Stephen Smalley6af963f2005-05-01 08:58:39 -07005214 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215}
5216
5217/* Semaphore security operations */
5218static int selinux_sem_alloc_security(struct sem_array *sma)
5219{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005221 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005222 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005223 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 int rc;
5225
5226 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5227 if (rc)
5228 return rc;
5229
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 isec = sma->sem_perm.security;
5231
Thomas Liu2bf49692009-07-14 12:14:09 -04005232 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005233 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005234 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235
David Howells275bb412008-11-14 10:39:19 +11005236 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 SEM__CREATE, &ad);
5238 if (rc) {
5239 ipc_free_security(&sma->sem_perm);
5240 return rc;
5241 }
5242 return 0;
5243}
5244
5245static void selinux_sem_free_security(struct sem_array *sma)
5246{
5247 ipc_free_security(&sma->sem_perm);
5248}
5249
5250static int selinux_sem_associate(struct sem_array *sma, int semflg)
5251{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005253 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005254 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005255 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 isec = sma->sem_perm.security;
5258
Thomas Liu2bf49692009-07-14 12:14:09 -04005259 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005260 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 ad.u.ipc_id = sma->sem_perm.key;
5262
David Howells275bb412008-11-14 10:39:19 +11005263 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 SEM__ASSOCIATE, &ad);
5265}
5266
5267/* Note, at this point, sma is locked down */
5268static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5269{
5270 int err;
5271 u32 perms;
5272
Eric Paris828dfe12008-04-17 13:17:49 -04005273 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 case IPC_INFO:
5275 case SEM_INFO:
5276 /* No specific object, just general system-wide information. */
5277 return task_has_system(current, SYSTEM__IPC_INFO);
5278 case GETPID:
5279 case GETNCNT:
5280 case GETZCNT:
5281 perms = SEM__GETATTR;
5282 break;
5283 case GETVAL:
5284 case GETALL:
5285 perms = SEM__READ;
5286 break;
5287 case SETVAL:
5288 case SETALL:
5289 perms = SEM__WRITE;
5290 break;
5291 case IPC_RMID:
5292 perms = SEM__DESTROY;
5293 break;
5294 case IPC_SET:
5295 perms = SEM__SETATTR;
5296 break;
5297 case IPC_STAT:
5298 case SEM_STAT:
5299 perms = SEM__GETATTR | SEM__ASSOCIATE;
5300 break;
5301 default:
5302 return 0;
5303 }
5304
Stephen Smalley6af963f2005-05-01 08:58:39 -07005305 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 return err;
5307}
5308
5309static int selinux_sem_semop(struct sem_array *sma,
5310 struct sembuf *sops, unsigned nsops, int alter)
5311{
5312 u32 perms;
5313
5314 if (alter)
5315 perms = SEM__READ | SEM__WRITE;
5316 else
5317 perms = SEM__READ;
5318
Stephen Smalley6af963f2005-05-01 08:58:39 -07005319 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320}
5321
5322static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5323{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 u32 av = 0;
5325
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 av = 0;
5327 if (flag & S_IRUGO)
5328 av |= IPC__UNIX_READ;
5329 if (flag & S_IWUGO)
5330 av |= IPC__UNIX_WRITE;
5331
5332 if (av == 0)
5333 return 0;
5334
Stephen Smalley6af963f2005-05-01 08:58:39 -07005335 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336}
5337
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005338static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5339{
5340 struct ipc_security_struct *isec = ipcp->security;
5341 *secid = isec->sid;
5342}
5343
Eric Paris828dfe12008-04-17 13:17:49 -04005344static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345{
5346 if (inode)
5347 inode_doinit_with_dentry(inode, dentry);
5348}
5349
5350static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005351 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352{
David Howells275bb412008-11-14 10:39:19 +11005353 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005354 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005356 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357
5358 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005359 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 if (error)
5361 return error;
5362 }
5363
David Howells275bb412008-11-14 10:39:19 +11005364 rcu_read_lock();
5365 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366
5367 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005368 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005370 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005372 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005374 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005375 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005376 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005377 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005378 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 else
David Howells275bb412008-11-14 10:39:19 +11005380 goto invalid;
5381 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382
5383 if (!sid)
5384 return 0;
5385
Al Viro04ff9702007-03-12 16:17:58 +00005386 error = security_sid_to_context(sid, value, &len);
5387 if (error)
5388 return error;
5389 return len;
David Howells275bb412008-11-14 10:39:19 +11005390
5391invalid:
5392 rcu_read_unlock();
5393 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394}
5395
5396static int selinux_setprocattr(struct task_struct *p,
5397 char *name, void *value, size_t size)
5398{
5399 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005400 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005401 struct cred *new;
5402 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 int error;
5404 char *str = value;
5405
5406 if (current != p) {
5407 /* SELinux only allows a process to change its own
5408 security attributes. */
5409 return -EACCES;
5410 }
5411
5412 /*
5413 * Basic control over ability to set these attributes at all.
5414 * current == p, but we'll pass them separately in case the
5415 * above restriction is ever removed.
5416 */
5417 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005418 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005420 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005421 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005422 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005423 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005424 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005426 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 else
5428 error = -EINVAL;
5429 if (error)
5430 return error;
5431
5432 /* Obtain a SID for the context, if one was specified. */
5433 if (size && str[1] && str[1] != '\n') {
5434 if (str[size-1] == '\n') {
5435 str[size-1] = 0;
5436 size--;
5437 }
5438 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005439 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5440 if (!capable(CAP_MAC_ADMIN))
5441 return error;
5442 error = security_context_to_sid_force(value, size,
5443 &sid);
5444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 if (error)
5446 return error;
5447 }
5448
David Howellsd84f4f92008-11-14 10:39:23 +11005449 new = prepare_creds();
5450 if (!new)
5451 return -ENOMEM;
5452
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 /* Permission checking based on the specified context is
5454 performed during the actual operation (execve,
5455 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005456 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 checks and may_create for the file creation checks. The
5458 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005459 tsec = new->security;
5460 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005462 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005464 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005465 error = may_create_key(sid, p);
5466 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005467 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005468 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005469 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005470 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005471 } else if (!strcmp(name, "current")) {
5472 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005474 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005475
David Howellsd84f4f92008-11-14 10:39:23 +11005476 /* Only allow single threaded processes to change context */
5477 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005478 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005479 error = security_bounded_transition(tsec->sid, sid);
5480 if (error)
5481 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
5484 /* Check permissions for the transition. */
5485 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005486 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005488 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489
5490 /* Check for ptracing, and update the task SID if ok.
5491 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005492 ptsid = 0;
Oleg Nesterov58c23142013-12-23 17:45:01 -05005493 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02005494 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005495 if (tracer)
5496 ptsid = task_sid(tracer);
Oleg Nesterov58c23142013-12-23 17:45:01 -05005497 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
David Howellsd84f4f92008-11-14 10:39:23 +11005499 if (tracer) {
5500 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5501 PROCESS__PTRACE, NULL);
5502 if (error)
5503 goto abort_change;
5504 }
5505
5506 tsec->sid = sid;
5507 } else {
5508 error = -EINVAL;
5509 goto abort_change;
5510 }
5511
5512 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005514
5515abort_change:
5516 abort_creds(new);
5517 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518}
5519
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005520static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5521{
5522 return security_sid_to_context(secid, secdata, seclen);
5523}
5524
David Howells7bf570d2008-04-29 20:52:51 +01005525static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005526{
5527 return security_context_to_sid(secdata, seclen, secid);
5528}
5529
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005530static void selinux_release_secctx(char *secdata, u32 seclen)
5531{
Paul Moore088999e2007-08-01 11:12:58 -04005532 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005533}
5534
David P. Quigley1ee65e32009-09-03 14:25:57 -04005535/*
5536 * called with inode->i_mutex locked
5537 */
5538static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5539{
5540 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5541}
5542
5543/*
5544 * called with inode->i_mutex locked
5545 */
5546static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5547{
5548 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5549}
5550
5551static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5552{
5553 int len = 0;
5554 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5555 ctx, true);
5556 if (len < 0)
5557 return len;
5558 *ctxlen = len;
5559 return 0;
5560}
Michael LeMayd7200242006-06-22 14:47:17 -07005561#ifdef CONFIG_KEYS
5562
David Howellsd84f4f92008-11-14 10:39:23 +11005563static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005564 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005565{
David Howellsd84f4f92008-11-14 10:39:23 +11005566 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005567 struct key_security_struct *ksec;
5568
5569 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5570 if (!ksec)
5571 return -ENOMEM;
5572
David Howellsd84f4f92008-11-14 10:39:23 +11005573 tsec = cred->security;
5574 if (tsec->keycreate_sid)
5575 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005576 else
David Howellsd84f4f92008-11-14 10:39:23 +11005577 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005578
David Howells275bb412008-11-14 10:39:19 +11005579 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005580 return 0;
5581}
5582
5583static void selinux_key_free(struct key *k)
5584{
5585 struct key_security_struct *ksec = k->security;
5586
5587 k->security = NULL;
5588 kfree(ksec);
5589}
5590
5591static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005592 const struct cred *cred,
5593 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005594{
5595 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005596 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005597 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005598
5599 /* if no specific permissions are requested, we skip the
5600 permission check. No serious, additional covert channels
5601 appear to be created. */
5602 if (perm == 0)
5603 return 0;
5604
David Howellsd84f4f92008-11-14 10:39:23 +11005605 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005606
5607 key = key_ref_to_ptr(key_ref);
5608 ksec = key->security;
5609
5610 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005611}
5612
David Howells70a5bb72008-04-29 01:01:26 -07005613static int selinux_key_getsecurity(struct key *key, char **_buffer)
5614{
5615 struct key_security_struct *ksec = key->security;
5616 char *context = NULL;
5617 unsigned len;
5618 int rc;
5619
5620 rc = security_sid_to_context(ksec->sid, &context, &len);
5621 if (!rc)
5622 rc = len;
5623 *_buffer = context;
5624 return rc;
5625}
5626
Michael LeMayd7200242006-06-22 14:47:17 -07005627#endif
5628
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005630 .name = "selinux",
5631
Ingo Molnar9e488582009-05-07 19:26:19 +10005632 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005633 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005635 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 .capable = selinux_capable,
5637 .quotactl = selinux_quotactl,
5638 .quota_on = selinux_quota_on,
5639 .syslog = selinux_syslog,
5640 .vm_enough_memory = selinux_vm_enough_memory,
5641
5642 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643
David Howellsa6f76f22008-11-14 10:39:24 +11005644 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005645 .bprm_committing_creds = selinux_bprm_committing_creds,
5646 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 .bprm_secureexec = selinux_bprm_secureexec,
5648
5649 .sb_alloc_security = selinux_sb_alloc_security,
5650 .sb_free_security = selinux_sb_free_security,
5651 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005652 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005653 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005654 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 .sb_statfs = selinux_sb_statfs,
5656 .sb_mount = selinux_mount,
5657 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005658 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005659 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005660 .sb_parse_opts_str = selinux_parse_opts_str,
5661
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
5663 .inode_alloc_security = selinux_inode_alloc_security,
5664 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005665 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 .inode_unlink = selinux_inode_unlink,
5669 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 .inode_rmdir = selinux_inode_rmdir,
5672 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 .inode_readlink = selinux_inode_readlink,
5675 .inode_follow_link = selinux_inode_follow_link,
5676 .inode_permission = selinux_inode_permission,
5677 .inode_setattr = selinux_inode_setattr,
5678 .inode_getattr = selinux_inode_getattr,
5679 .inode_setxattr = selinux_inode_setxattr,
5680 .inode_post_setxattr = selinux_inode_post_setxattr,
5681 .inode_getxattr = selinux_inode_getxattr,
5682 .inode_listxattr = selinux_inode_listxattr,
5683 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005684 .inode_getsecurity = selinux_inode_getsecurity,
5685 .inode_setsecurity = selinux_inode_setsecurity,
5686 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005687 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
5689 .file_permission = selinux_file_permission,
5690 .file_alloc_security = selinux_file_alloc_security,
5691 .file_free_security = selinux_file_free_security,
5692 .file_ioctl = selinux_file_ioctl,
5693 .file_mmap = selinux_file_mmap,
5694 .file_mprotect = selinux_file_mprotect,
5695 .file_lock = selinux_file_lock,
5696 .file_fcntl = selinux_file_fcntl,
5697 .file_set_fowner = selinux_file_set_fowner,
5698 .file_send_sigiotask = selinux_file_send_sigiotask,
5699 .file_receive = selinux_file_receive,
5700
Eric Paris828dfe12008-04-17 13:17:49 -04005701 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005702
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005704 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005705 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005706 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005707 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005708 .kernel_act_as = selinux_kernel_act_as,
5709 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005710 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 .task_setpgid = selinux_task_setpgid,
5712 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005713 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005714 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005716 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005717 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 .task_setrlimit = selinux_task_setrlimit,
5719 .task_setscheduler = selinux_task_setscheduler,
5720 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005721 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 .task_kill = selinux_task_kill,
5723 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005724 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
5726 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005727 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
5729 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5730 .msg_msg_free_security = selinux_msg_msg_free_security,
5731
5732 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5733 .msg_queue_free_security = selinux_msg_queue_free_security,
5734 .msg_queue_associate = selinux_msg_queue_associate,
5735 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5736 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5737 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5738
5739 .shm_alloc_security = selinux_shm_alloc_security,
5740 .shm_free_security = selinux_shm_free_security,
5741 .shm_associate = selinux_shm_associate,
5742 .shm_shmctl = selinux_shm_shmctl,
5743 .shm_shmat = selinux_shm_shmat,
5744
Eric Paris828dfe12008-04-17 13:17:49 -04005745 .sem_alloc_security = selinux_sem_alloc_security,
5746 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 .sem_associate = selinux_sem_associate,
5748 .sem_semctl = selinux_sem_semctl,
5749 .sem_semop = selinux_sem_semop,
5750
Eric Paris828dfe12008-04-17 13:17:49 -04005751 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752
Eric Paris828dfe12008-04-17 13:17:49 -04005753 .getprocattr = selinux_getprocattr,
5754 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005756 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005757 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005758 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005759 .inode_notifysecctx = selinux_inode_notifysecctx,
5760 .inode_setsecctx = selinux_inode_setsecctx,
5761 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005762
Eric Paris828dfe12008-04-17 13:17:49 -04005763 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 .unix_may_send = selinux_socket_unix_may_send,
5765
5766 .socket_create = selinux_socket_create,
5767 .socket_post_create = selinux_socket_post_create,
5768 .socket_bind = selinux_socket_bind,
5769 .socket_connect = selinux_socket_connect,
5770 .socket_listen = selinux_socket_listen,
5771 .socket_accept = selinux_socket_accept,
5772 .socket_sendmsg = selinux_socket_sendmsg,
5773 .socket_recvmsg = selinux_socket_recvmsg,
5774 .socket_getsockname = selinux_socket_getsockname,
5775 .socket_getpeername = selinux_socket_getpeername,
5776 .socket_getsockopt = selinux_socket_getsockopt,
5777 .socket_setsockopt = selinux_socket_setsockopt,
5778 .socket_shutdown = selinux_socket_shutdown,
5779 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005780 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5781 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 .sk_alloc_security = selinux_sk_alloc_security,
5783 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005784 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005785 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005786 .sock_graft = selinux_sock_graft,
5787 .inet_conn_request = selinux_inet_conn_request,
5788 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005789 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005790 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5791 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5792 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005793 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005794 .tun_dev_create = selinux_tun_dev_create,
5795 .tun_dev_post_create = selinux_tun_dev_post_create,
5796 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005797
5798#ifdef CONFIG_SECURITY_NETWORK_XFRM
5799 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5800 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5801 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005802 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005803 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5804 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005805 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005806 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005807 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005808 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005810
5811#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005812 .key_alloc = selinux_key_alloc,
5813 .key_free = selinux_key_free,
5814 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005815 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005816#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005817
5818#ifdef CONFIG_AUDIT
5819 .audit_rule_init = selinux_audit_rule_init,
5820 .audit_rule_known = selinux_audit_rule_known,
5821 .audit_rule_match = selinux_audit_rule_match,
5822 .audit_rule_free = selinux_audit_rule_free,
5823#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824};
5825
5826static __init int selinux_init(void)
5827{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005828 if (!security_module_enable(&selinux_ops)) {
5829 selinux_enabled = 0;
5830 return 0;
5831 }
5832
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 if (!selinux_enabled) {
5834 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5835 return 0;
5836 }
5837
5838 printk(KERN_INFO "SELinux: Initializing.\n");
5839
5840 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005841 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005843 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5844
James Morris7cae7e22006-03-22 00:09:22 -08005845 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5846 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005847 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848 avc_init();
5849
Eric Paris828dfe12008-04-17 13:17:49 -04005850 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 panic("SELinux: Unable to register with kernel.\n");
5852
Eric Paris828dfe12008-04-17 13:17:49 -04005853 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005854 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005855 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005856 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005857
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 return 0;
5859}
5860
Al Viroe8c26252010-03-23 06:36:54 -04005861static void delayed_superblock_init(struct super_block *sb, void *unused)
5862{
5863 superblock_doinit(sb, NULL);
5864}
5865
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866void selinux_complete_init(void)
5867{
Eric Parisfadcdb42007-02-22 18:11:31 -05005868 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
5870 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005871 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005872 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873}
5874
5875/* SELinux requires early initialization in order to label
5876 all processes and objects when they are created. */
5877security_initcall(selinux_init);
5878
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005879#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880
Paul Mooreeffad8d2008-01-29 08:49:27 -05005881static struct nf_hook_ops selinux_ipv4_ops[] = {
5882 {
5883 .hook = selinux_ipv4_postroute,
5884 .owner = THIS_MODULE,
5885 .pf = PF_INET,
5886 .hooknum = NF_INET_POST_ROUTING,
5887 .priority = NF_IP_PRI_SELINUX_LAST,
5888 },
5889 {
5890 .hook = selinux_ipv4_forward,
5891 .owner = THIS_MODULE,
5892 .pf = PF_INET,
5893 .hooknum = NF_INET_FORWARD,
5894 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005895 },
5896 {
5897 .hook = selinux_ipv4_output,
5898 .owner = THIS_MODULE,
5899 .pf = PF_INET,
5900 .hooknum = NF_INET_LOCAL_OUT,
5901 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903};
5904
5905#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5906
Paul Mooreeffad8d2008-01-29 08:49:27 -05005907static struct nf_hook_ops selinux_ipv6_ops[] = {
5908 {
5909 .hook = selinux_ipv6_postroute,
5910 .owner = THIS_MODULE,
5911 .pf = PF_INET6,
5912 .hooknum = NF_INET_POST_ROUTING,
5913 .priority = NF_IP6_PRI_SELINUX_LAST,
5914 },
5915 {
5916 .hook = selinux_ipv6_forward,
5917 .owner = THIS_MODULE,
5918 .pf = PF_INET6,
5919 .hooknum = NF_INET_FORWARD,
5920 .priority = NF_IP6_PRI_SELINUX_FIRST,
5921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922};
5923
5924#endif /* IPV6 */
5925
5926static int __init selinux_nf_ip_init(void)
5927{
5928 int err = 0;
5929
5930 if (!selinux_enabled)
5931 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005932
5933 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5934
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005935 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5936 if (err)
5937 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938
5939#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005940 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5941 if (err)
5942 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005944
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945out:
5946 return err;
5947}
5948
5949__initcall(selinux_nf_ip_init);
5950
5951#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5952static void selinux_nf_ip_exit(void)
5953{
Eric Parisfadcdb42007-02-22 18:11:31 -05005954 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005956 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005958 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959#endif /* IPV6 */
5960}
5961#endif
5962
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005963#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964
5965#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5966#define selinux_nf_ip_exit()
5967#endif
5968
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005969#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970
5971#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005972static int selinux_disabled;
5973
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974int selinux_disable(void)
5975{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 if (ss_initialized) {
5977 /* Not permitted after initial policy load. */
5978 return -EINVAL;
5979 }
5980
5981 if (selinux_disabled) {
5982 /* Only do this once. */
5983 return -EINVAL;
5984 }
5985
5986 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5987
5988 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005989 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08005991 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
Eric Parisaf8ff042009-09-20 21:23:01 -04005993 /* Try to destroy the avc node cache */
5994 avc_disable();
5995
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 /* Unregister netfilter hooks. */
5997 selinux_nf_ip_exit();
5998
5999 /* Unregister selinuxfs. */
6000 exit_sel_fs();
6001
6002 return 0;
6003}
6004#endif