blob: 639e5c4028ff692fb084189bc293b9fc1ab12fba [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)) {
Paul Moore23a5a7a2014-03-19 16:46:18 -04001332 /* We must have a dentry to determine the label on
1333 * procfs inodes */
1334 if (opt_dentry)
1335 /* Called from d_instantiate or
1336 * d_splice_alias. */
1337 dentry = dget(opt_dentry);
1338 else
1339 /* Called from selinux_complete_init, try to
1340 * find a dentry. */
1341 dentry = d_find_alias(inode);
1342 /*
1343 * This can be hit on boot when a file is accessed
1344 * before the policy is loaded. When we load policy we
1345 * may find inodes that have no dentry on the
1346 * sbsec->isec_head list. No reason to complain as
1347 * these will get fixed up the next time we go through
1348 * inode_doinit() with a dentry, before these inodes
1349 * could be used again by userspace.
1350 */
1351 if (!dentry)
1352 goto out_unlock;
1353 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1354 rc = selinux_proc_get_sid(dentry, isec->sclass, &sid);
1355 dput(dentry);
1356 if (rc)
1357 goto out_unlock;
1358 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
1360 break;
1361 }
1362
1363 isec->initialized = 1;
1364
Eric Paris23970742006-09-25 23:32:01 -07001365out_unlock:
1366 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367out:
1368 if (isec->sclass == SECCLASS_FILE)
1369 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 return rc;
1371}
1372
1373/* Convert a Linux signal to an access vector. */
1374static inline u32 signal_to_av(int sig)
1375{
1376 u32 perm = 0;
1377
1378 switch (sig) {
1379 case SIGCHLD:
1380 /* Commonly granted from child to parent. */
1381 perm = PROCESS__SIGCHLD;
1382 break;
1383 case SIGKILL:
1384 /* Cannot be caught or ignored */
1385 perm = PROCESS__SIGKILL;
1386 break;
1387 case SIGSTOP:
1388 /* Cannot be caught or ignored */
1389 perm = PROCESS__SIGSTOP;
1390 break;
1391 default:
1392 /* All other signals. */
1393 perm = PROCESS__SIGNAL;
1394 break;
1395 }
1396
1397 return perm;
1398}
1399
David Howells275bb412008-11-14 10:39:19 +11001400/*
David Howellsd84f4f92008-11-14 10:39:23 +11001401 * Check permission between a pair of credentials
1402 * fork check, ptrace check, etc.
1403 */
1404static int cred_has_perm(const struct cred *actor,
1405 const struct cred *target,
1406 u32 perms)
1407{
1408 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1409
1410 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1411}
1412
1413/*
David Howells88e67f32008-11-14 10:39:21 +11001414 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001415 * fork check, ptrace check, etc.
1416 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001417 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001418 */
1419static int task_has_perm(const struct task_struct *tsk1,
1420 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 u32 perms)
1422{
David Howells275bb412008-11-14 10:39:19 +11001423 const struct task_security_struct *__tsec1, *__tsec2;
1424 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
David Howells275bb412008-11-14 10:39:19 +11001426 rcu_read_lock();
1427 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1428 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1429 rcu_read_unlock();
1430 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431}
1432
David Howells3b11a1d2008-11-14 10:39:26 +11001433/*
1434 * Check permission between current and another task, e.g. signal checks,
1435 * fork check, ptrace check, etc.
1436 * current is the actor and tsk2 is the target
1437 * - this uses current's subjective creds
1438 */
1439static int current_has_perm(const struct task_struct *tsk,
1440 u32 perms)
1441{
1442 u32 sid, tsid;
1443
1444 sid = current_sid();
1445 tsid = task_sid(tsk);
1446 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1447}
1448
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001449#if CAP_LAST_CAP > 63
1450#error Fix SELinux to handle capabilities > 63.
1451#endif
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453/* Check whether a task is allowed to use a capability. */
Eric Paris6a9de492012-01-03 12:25:14 -05001454static int cred_has_capability(const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001455 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456{
Thomas Liu2bf49692009-07-14 12:14:09 -04001457 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001458 struct selinux_audit_data sad = {0,};
Eric Paris06112162008-11-11 22:02:50 +11001459 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001460 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001461 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001462 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001463 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Thomas Liu2bf49692009-07-14 12:14:09 -04001465 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001466 ad.selinux_audit_data = &sad;
Eric Paris6a9de492012-01-03 12:25:14 -05001467 ad.tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 ad.u.cap = cap;
1469
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001470 switch (CAP_TO_INDEX(cap)) {
1471 case 0:
1472 sclass = SECCLASS_CAPABILITY;
1473 break;
1474 case 1:
1475 sclass = SECCLASS_CAPABILITY2;
1476 break;
1477 default:
1478 printk(KERN_ERR
1479 "SELinux: out of range capability %d\n", cap);
1480 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001481 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001482 }
Eric Paris06112162008-11-11 22:02:50 +11001483
David Howells275bb412008-11-14 10:39:19 +11001484 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001485 if (audit == SECURITY_CAP_AUDIT) {
1486 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1487 if (rc2)
1488 return rc2;
1489 }
Eric Paris06112162008-11-11 22:02:50 +11001490 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491}
1492
1493/* Check whether a task is allowed to use a system operation. */
1494static int task_has_system(struct task_struct *tsk,
1495 u32 perms)
1496{
David Howells275bb412008-11-14 10:39:19 +11001497 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
David Howells275bb412008-11-14 10:39:19 +11001499 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 SECCLASS_SYSTEM, perms, NULL);
1501}
1502
1503/* Check whether a task has a particular permission to an inode.
1504 The 'adp' parameter is optional and allows other audit
1505 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001506static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 struct inode *inode,
1508 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001509 struct common_audit_data *adp,
1510 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001513 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
David Howellse0e81732009-09-02 09:13:40 +01001515 validate_creds(cred);
1516
Eric Paris828dfe12008-04-17 13:17:49 -04001517 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001518 return 0;
1519
David Howells88e67f32008-11-14 10:39:21 +11001520 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 isec = inode->i_security;
1522
Eric Paris9ade0cf2011-04-25 16:26:29 -04001523 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524}
1525
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001526static int inode_has_perm_noadp(const struct cred *cred,
1527 struct inode *inode,
1528 u32 perms,
1529 unsigned flags)
1530{
1531 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001532 struct selinux_audit_data sad = {0,};
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001533
1534 COMMON_AUDIT_DATA_INIT(&ad, INODE);
1535 ad.u.inode = inode;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001536 ad.selinux_audit_data = &sad;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001537 return inode_has_perm(cred, inode, perms, &ad, flags);
1538}
1539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540/* Same as inode_has_perm, but pass explicit audit data containing
1541 the dentry to help the auditing code to more easily generate the
1542 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001543static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 struct dentry *dentry,
1545 u32 av)
1546{
1547 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001548 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001549 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001550
Eric Paris2875fa02011-04-28 16:04:24 -04001551 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1552 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001553 ad.selinux_audit_data = &sad;
Eric Paris2875fa02011-04-28 16:04:24 -04001554 return inode_has_perm(cred, inode, av, &ad, 0);
1555}
1556
1557/* Same as inode_has_perm, but pass explicit audit data containing
1558 the path to help the auditing code to more easily generate the
1559 pathname if needed. */
1560static inline int path_has_perm(const struct cred *cred,
1561 struct path *path,
1562 u32 av)
1563{
1564 struct inode *inode = path->dentry->d_inode;
1565 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001566 struct selinux_audit_data sad = {0,};
Eric Paris2875fa02011-04-28 16:04:24 -04001567
Eric Parisf48b7392011-04-25 12:54:27 -04001568 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001569 ad.u.path = *path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001570 ad.selinux_audit_data = &sad;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001571 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572}
1573
1574/* Check whether a task can use an open file descriptor to
1575 access an inode in a given way. Check access to the
1576 descriptor itself, and then use dentry_has_perm to
1577 check a particular permission to the file.
1578 Access to the descriptor is implicitly granted if it
1579 has the same SID as the process. If av is zero, then
1580 access to the file is not checked, e.g. for cases
1581 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001582static int file_has_perm(const struct cred *cred,
1583 struct file *file,
1584 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001587 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001588 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001589 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001590 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 int rc;
1592
Eric Parisf48b7392011-04-25 12:54:27 -04001593 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1594 ad.u.path = file->f_path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001595 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
David Howells275bb412008-11-14 10:39:19 +11001597 if (sid != fsec->sid) {
1598 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 SECCLASS_FD,
1600 FD__USE,
1601 &ad);
1602 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001603 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
1605
1606 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001607 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001609 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
David Howells88e67f32008-11-14 10:39:21 +11001611out:
1612 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613}
1614
1615/* Check whether a task can create a file. */
1616static int may_create(struct inode *dir,
1617 struct dentry *dentry,
1618 u16 tclass)
1619{
Paul Moore5fb49872010-04-22 14:46:19 -04001620 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 struct inode_security_struct *dsec;
1622 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001623 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001624 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001625 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 int rc;
1627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 dsec = dir->i_security;
1629 sbsec = dir->i_sb->s_security;
1630
David Howells275bb412008-11-14 10:39:19 +11001631 sid = tsec->sid;
1632 newsid = tsec->create_sid;
1633
Eric Parisa2694342011-04-25 13:10:27 -04001634 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1635 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001636 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
David Howells275bb412008-11-14 10:39:19 +11001638 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 DIR__ADD_NAME | DIR__SEARCH,
1640 &ad);
1641 if (rc)
1642 return rc;
1643
David P. Quigleycd895962009-01-16 09:22:04 -05001644 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001645 rc = security_transition_sid(sid, dsec->sid, tclass,
1646 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if (rc)
1648 return rc;
1649 }
1650
David Howells275bb412008-11-14 10:39:19 +11001651 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 if (rc)
1653 return rc;
1654
1655 return avc_has_perm(newsid, sbsec->sid,
1656 SECCLASS_FILESYSTEM,
1657 FILESYSTEM__ASSOCIATE, &ad);
1658}
1659
Michael LeMay4eb582c2006-06-26 00:24:57 -07001660/* Check whether a task can create a key. */
1661static int may_create_key(u32 ksid,
1662 struct task_struct *ctx)
1663{
David Howells275bb412008-11-14 10:39:19 +11001664 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001665
David Howells275bb412008-11-14 10:39:19 +11001666 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001667}
1668
Eric Paris828dfe12008-04-17 13:17:49 -04001669#define MAY_LINK 0
1670#define MAY_UNLINK 1
1671#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673/* Check whether a task can link, unlink, or rmdir a file/directory. */
1674static int may_link(struct inode *dir,
1675 struct dentry *dentry,
1676 int kind)
1677
1678{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001680 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001681 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001682 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 u32 av;
1684 int rc;
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 dsec = dir->i_security;
1687 isec = dentry->d_inode->i_security;
1688
Eric Parisa2694342011-04-25 13:10:27 -04001689 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1690 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001691 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 av = DIR__SEARCH;
1694 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001695 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 if (rc)
1697 return rc;
1698
1699 switch (kind) {
1700 case MAY_LINK:
1701 av = FILE__LINK;
1702 break;
1703 case MAY_UNLINK:
1704 av = FILE__UNLINK;
1705 break;
1706 case MAY_RMDIR:
1707 av = DIR__RMDIR;
1708 break;
1709 default:
Eric Paris744ba352008-04-17 11:52:44 -04001710 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1711 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 return 0;
1713 }
1714
David Howells275bb412008-11-14 10:39:19 +11001715 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return rc;
1717}
1718
1719static inline int may_rename(struct inode *old_dir,
1720 struct dentry *old_dentry,
1721 struct inode *new_dir,
1722 struct dentry *new_dentry)
1723{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001725 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001726 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001727 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 u32 av;
1729 int old_is_dir, new_is_dir;
1730 int rc;
1731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 old_dsec = old_dir->i_security;
1733 old_isec = old_dentry->d_inode->i_security;
1734 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1735 new_dsec = new_dir->i_security;
1736
Eric Parisa2694342011-04-25 13:10:27 -04001737 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001738 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Eric Parisa2694342011-04-25 13:10:27 -04001740 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001741 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1743 if (rc)
1744 return rc;
David Howells275bb412008-11-14 10:39:19 +11001745 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 old_isec->sclass, FILE__RENAME, &ad);
1747 if (rc)
1748 return rc;
1749 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001750 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 old_isec->sclass, DIR__REPARENT, &ad);
1752 if (rc)
1753 return rc;
1754 }
1755
Eric Parisa2694342011-04-25 13:10:27 -04001756 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 av = DIR__ADD_NAME | DIR__SEARCH;
1758 if (new_dentry->d_inode)
1759 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001760 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 if (rc)
1762 return rc;
1763 if (new_dentry->d_inode) {
1764 new_isec = new_dentry->d_inode->i_security;
1765 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001766 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 new_isec->sclass,
1768 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1769 if (rc)
1770 return rc;
1771 }
1772
1773 return 0;
1774}
1775
1776/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001777static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 struct super_block *sb,
1779 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001780 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001783 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001786 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787}
1788
1789/* Convert a Linux mode and permission mask to an access vector. */
1790static inline u32 file_mask_to_av(int mode, int mask)
1791{
1792 u32 av = 0;
1793
Al Virodba19c62011-07-25 20:49:29 -04001794 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 if (mask & MAY_EXEC)
1796 av |= FILE__EXECUTE;
1797 if (mask & MAY_READ)
1798 av |= FILE__READ;
1799
1800 if (mask & MAY_APPEND)
1801 av |= FILE__APPEND;
1802 else if (mask & MAY_WRITE)
1803 av |= FILE__WRITE;
1804
1805 } else {
1806 if (mask & MAY_EXEC)
1807 av |= DIR__SEARCH;
1808 if (mask & MAY_WRITE)
1809 av |= DIR__WRITE;
1810 if (mask & MAY_READ)
1811 av |= DIR__READ;
1812 }
1813
1814 return av;
1815}
1816
1817/* Convert a Linux file to an access vector. */
1818static inline u32 file_to_av(struct file *file)
1819{
1820 u32 av = 0;
1821
1822 if (file->f_mode & FMODE_READ)
1823 av |= FILE__READ;
1824 if (file->f_mode & FMODE_WRITE) {
1825 if (file->f_flags & O_APPEND)
1826 av |= FILE__APPEND;
1827 else
1828 av |= FILE__WRITE;
1829 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001830 if (!av) {
1831 /*
1832 * Special file opened with flags 3 for ioctl-only use.
1833 */
1834 av = FILE__IOCTL;
1835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 return av;
1838}
1839
Eric Paris8b6a5a32008-10-29 17:06:46 -04001840/*
1841 * Convert a file to an access vector and include the correct open
1842 * open permission.
1843 */
1844static inline u32 open_file_to_av(struct file *file)
1845{
1846 u32 av = file_to_av(file);
1847
Eric Paris49b7b8d2010-07-23 11:44:09 -04001848 if (selinux_policycap_openperm)
1849 av |= FILE__OPEN;
1850
Eric Paris8b6a5a32008-10-29 17:06:46 -04001851 return av;
1852}
1853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854/* Hook functions begin here. */
1855
Ingo Molnar9e488582009-05-07 19:26:19 +10001856static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001857 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 int rc;
1860
Ingo Molnar9e488582009-05-07 19:26:19 +10001861 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 if (rc)
1863 return rc;
1864
Eric Paris69f594a2012-01-03 12:25:15 -05001865 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001866 u32 sid = current_sid();
1867 u32 csid = task_sid(child);
1868 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001869 }
1870
David Howells3b11a1d2008-11-14 10:39:26 +11001871 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001872}
1873
1874static int selinux_ptrace_traceme(struct task_struct *parent)
1875{
1876 int rc;
1877
Eric Paris200ac532009-02-12 15:01:04 -05001878 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001879 if (rc)
1880 return rc;
1881
1882 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883}
1884
1885static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001886 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887{
1888 int error;
1889
David Howells3b11a1d2008-11-14 10:39:26 +11001890 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (error)
1892 return error;
1893
Eric Paris200ac532009-02-12 15:01:04 -05001894 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895}
1896
David Howellsd84f4f92008-11-14 10:39:23 +11001897static int selinux_capset(struct cred *new, const struct cred *old,
1898 const kernel_cap_t *effective,
1899 const kernel_cap_t *inheritable,
1900 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901{
1902 int error;
1903
Eric Paris200ac532009-02-12 15:01:04 -05001904 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001905 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 if (error)
1907 return error;
1908
David Howellsd84f4f92008-11-14 10:39:23 +11001909 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910}
1911
James Morris5626d3e2009-01-30 10:05:06 +11001912/*
1913 * (This comment used to live with the selinux_task_setuid hook,
1914 * which was removed).
1915 *
1916 * Since setuid only affects the current process, and since the SELinux
1917 * controls are not based on the Linux identity attributes, SELinux does not
1918 * need to control this operation. However, SELinux does control the use of
1919 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1920 */
1921
Eric Paris6a9de492012-01-03 12:25:14 -05001922static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1923 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924{
1925 int rc;
1926
Eric Paris6a9de492012-01-03 12:25:14 -05001927 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 if (rc)
1929 return rc;
1930
Eric Paris6a9de492012-01-03 12:25:14 -05001931 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932}
1933
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1935{
David Howells88e67f32008-11-14 10:39:21 +11001936 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 int rc = 0;
1938
1939 if (!sb)
1940 return 0;
1941
1942 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001943 case Q_SYNC:
1944 case Q_QUOTAON:
1945 case Q_QUOTAOFF:
1946 case Q_SETINFO:
1947 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001948 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001949 break;
1950 case Q_GETFMT:
1951 case Q_GETINFO:
1952 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001953 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001954 break;
1955 default:
1956 rc = 0; /* let the kernel handle invalid cmds */
1957 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 }
1959 return rc;
1960}
1961
1962static int selinux_quota_on(struct dentry *dentry)
1963{
David Howells88e67f32008-11-14 10:39:21 +11001964 const struct cred *cred = current_cred();
1965
Eric Paris2875fa02011-04-28 16:04:24 -04001966 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967}
1968
Eric Paris12b30522010-11-15 18:36:29 -05001969static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
1971 int rc;
1972
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08001974 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
1975 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001976 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1977 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001978 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
1979 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
1980 /* Set level of messages printed to console */
1981 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04001982 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1983 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001984 case SYSLOG_ACTION_CLOSE: /* Close log */
1985 case SYSLOG_ACTION_OPEN: /* Open log */
1986 case SYSLOG_ACTION_READ: /* Read from log */
1987 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
1988 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001989 default:
1990 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1991 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 }
1993 return rc;
1994}
1995
1996/*
1997 * Check that a process has enough memory to allocate a new virtual
1998 * mapping. 0 means there is enough memory for the allocation to
1999 * succeed and -ENOMEM implies there is not.
2000 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 * Do not audit the selinux permission check, as this is applied to all
2002 * processes that allocate mappings.
2003 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002004static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005{
2006 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Eric Paris6a9de492012-01-03 12:25:14 -05002008 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002009 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (rc == 0)
2011 cap_sys_admin = 1;
2012
Alan Cox34b4e4a2007-08-22 14:01:28 -07002013 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014}
2015
2016/* binprm security operations */
2017
David Howellsa6f76f22008-11-14 10:39:24 +11002018static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019{
David Howellsa6f76f22008-11-14 10:39:24 +11002020 const struct task_security_struct *old_tsec;
2021 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002023 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002024 struct selinux_audit_data sad = {0,};
David Howellsa6f76f22008-11-14 10:39:24 +11002025 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 int rc;
2027
Eric Paris200ac532009-02-12 15:01:04 -05002028 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 if (rc)
2030 return rc;
2031
David Howellsa6f76f22008-11-14 10:39:24 +11002032 /* SELinux context only depends on initial program or script and not
2033 * the script interpreter */
2034 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 return 0;
2036
David Howellsa6f76f22008-11-14 10:39:24 +11002037 old_tsec = current_security();
2038 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 isec = inode->i_security;
2040
2041 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002042 new_tsec->sid = old_tsec->sid;
2043 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Michael LeMay28eba5b2006-06-27 02:53:42 -07002045 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002046 new_tsec->create_sid = 0;
2047 new_tsec->keycreate_sid = 0;
2048 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
David Howellsa6f76f22008-11-14 10:39:24 +11002050 if (old_tsec->exec_sid) {
2051 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002053 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 } else {
2055 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002056 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002057 SECCLASS_PROCESS, NULL,
2058 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 if (rc)
2060 return rc;
2061 }
2062
Eric Parisf48b7392011-04-25 12:54:27 -04002063 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002064 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002065 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Josef Sipek3d5ff522006-12-08 02:37:38 -08002067 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002068 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
David Howellsa6f76f22008-11-14 10:39:24 +11002070 if (new_tsec->sid == old_tsec->sid) {
2071 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2073 if (rc)
2074 return rc;
2075 } else {
2076 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002077 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2079 if (rc)
2080 return rc;
2081
David Howellsa6f76f22008-11-14 10:39:24 +11002082 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2084 if (rc)
2085 return rc;
2086
David Howellsa6f76f22008-11-14 10:39:24 +11002087 /* Check for shared state */
2088 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2089 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2090 SECCLASS_PROCESS, PROCESS__SHARE,
2091 NULL);
2092 if (rc)
2093 return -EPERM;
2094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
David Howellsa6f76f22008-11-14 10:39:24 +11002096 /* Make sure that anyone attempting to ptrace over a task that
2097 * changes its SID has the appropriate permit */
2098 if (bprm->unsafe &
2099 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2100 struct task_struct *tracer;
2101 struct task_security_struct *sec;
2102 u32 ptsid = 0;
2103
2104 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002105 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002106 if (likely(tracer != NULL)) {
2107 sec = __task_cred(tracer)->security;
2108 ptsid = sec->sid;
2109 }
2110 rcu_read_unlock();
2111
2112 if (ptsid != 0) {
2113 rc = avc_has_perm(ptsid, new_tsec->sid,
2114 SECCLASS_PROCESS,
2115 PROCESS__PTRACE, NULL);
2116 if (rc)
2117 return -EPERM;
2118 }
2119 }
2120
2121 /* Clear any possibly unsafe personality bits on exec: */
2122 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 }
2124
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 return 0;
2126}
2127
Eric Paris828dfe12008-04-17 13:17:49 -04002128static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129{
Paul Moore5fb49872010-04-22 14:46:19 -04002130 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002131 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 int atsecure = 0;
2133
David Howells275bb412008-11-14 10:39:19 +11002134 sid = tsec->sid;
2135 osid = tsec->osid;
2136
2137 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 /* Enable secure mode for SIDs transitions unless
2139 the noatsecure permission is granted between
2140 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002141 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002142 SECCLASS_PROCESS,
2143 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 }
2145
Eric Paris200ac532009-02-12 15:01:04 -05002146 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147}
2148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002150static inline void flush_unauthorized_files(const struct cred *cred,
2151 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152{
Thomas Liu2bf49692009-07-14 12:14:09 -04002153 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002154 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002156 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002157 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002159 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002161 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002163 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002164 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002165 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002166 struct inode *inode;
2167
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 /* Revalidate access to controlling tty.
2169 Use inode_has_perm on the tty inode directly rather
2170 than using file_has_perm, as this particular open
2171 file may belong to another process and we are only
2172 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002173 file_priv = list_first_entry(&tty->tty_files,
2174 struct tty_file_private, list);
2175 file = file_priv->file;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002176 inode = file->f_path.dentry->d_inode;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07002177 if (inode_has_perm_noadp(cred, inode,
2178 FILE__READ | FILE__WRITE, 0)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002179 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 }
2181 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002182 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002183 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002185 /* Reset controlling tty. */
2186 if (drop_tty)
2187 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
2189 /* Revalidate access to inherited open files. */
2190
Eric Parisf48b7392011-04-25 12:54:27 -04002191 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002192 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
2194 spin_lock(&files->file_lock);
2195 for (;;) {
2196 unsigned long set, i;
2197 int fd;
2198
2199 j++;
Josh Boyer27cd8f52012-07-25 10:40:34 -04002200 i = j * BITS_PER_LONG;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002201 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002202 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 break;
David Howells1fd36ad2012-02-16 17:49:54 +00002204 set = fdt->open_fds[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 if (!set)
2206 continue;
2207 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002208 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 if (set & 1) {
2210 file = fget(i);
2211 if (!file)
2212 continue;
David Howells88e67f32008-11-14 10:39:21 +11002213 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 file,
2215 file_to_av(file))) {
2216 sys_close(i);
2217 fd = get_unused_fd();
2218 if (fd != i) {
2219 if (fd >= 0)
2220 put_unused_fd(fd);
2221 fput(file);
2222 continue;
2223 }
2224 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002225 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 } else {
David Howells745ca242008-11-14 10:39:22 +11002227 devnull = dentry_open(
2228 dget(selinux_null),
2229 mntget(selinuxfs_mount),
2230 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002231 if (IS_ERR(devnull)) {
2232 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 put_unused_fd(fd);
2234 fput(file);
2235 continue;
2236 }
2237 }
2238 fd_install(fd, devnull);
2239 }
2240 fput(file);
2241 }
2242 }
2243 spin_lock(&files->file_lock);
2244
2245 }
2246 spin_unlock(&files->file_lock);
2247}
2248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249/*
David Howellsa6f76f22008-11-14 10:39:24 +11002250 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 */
David Howellsa6f76f22008-11-14 10:39:24 +11002252static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253{
David Howellsa6f76f22008-11-14 10:39:24 +11002254 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 int rc, i;
2257
David Howellsa6f76f22008-11-14 10:39:24 +11002258 new_tsec = bprm->cred->security;
2259 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 return;
2261
2262 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002263 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
David Howellsa6f76f22008-11-14 10:39:24 +11002265 /* Always clear parent death signal on SID transitions. */
2266 current->pdeath_signal = 0;
2267
2268 /* Check whether the new SID can inherit resource limits from the old
2269 * SID. If not, reset all soft limits to the lower of the current
2270 * task's hard limit and the init task's soft limit.
2271 *
2272 * Note that the setting of hard limits (even to lower them) can be
2273 * controlled by the setrlimit check. The inclusion of the init task's
2274 * soft limit into the computation is to avoid resetting soft limits
2275 * higher than the default soft limit for cases where the default is
2276 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2277 */
2278 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2279 PROCESS__RLIMITINH, NULL);
2280 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002281 /* protect against do_prlimit() */
2282 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002283 for (i = 0; i < RLIM_NLIMITS; i++) {
2284 rlim = current->signal->rlim + i;
2285 initrlim = init_task.signal->rlim + i;
2286 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2287 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002288 task_unlock(current);
2289 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002290 }
2291}
2292
2293/*
2294 * Clean up the process immediately after the installation of new credentials
2295 * due to exec
2296 */
2297static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2298{
2299 const struct task_security_struct *tsec = current_security();
2300 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002301 u32 osid, sid;
2302 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002303
David Howellsa6f76f22008-11-14 10:39:24 +11002304 osid = tsec->osid;
2305 sid = tsec->sid;
2306
2307 if (sid == osid)
2308 return;
2309
2310 /* Check whether the new SID can inherit signal state from the old SID.
2311 * If not, clear itimers to avoid subsequent signal generation and
2312 * flush and unblock signals.
2313 *
2314 * This must occur _after_ the task SID has been updated so that any
2315 * kill done after the flush will be checked against the new SID.
2316 */
2317 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 if (rc) {
2319 memset(&itimer, 0, sizeof itimer);
2320 for (i = 0; i < 3; i++)
2321 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002323 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2324 __flush_signals(current);
2325 flush_signal_handlers(current, 1);
2326 sigemptyset(&current->blocked);
2327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 spin_unlock_irq(&current->sighand->siglock);
2329 }
2330
David Howellsa6f76f22008-11-14 10:39:24 +11002331 /* Wake up the parent if it is waiting so that it can recheck
2332 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002333 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002334 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002335 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336}
2337
2338/* superblock security operations */
2339
2340static int selinux_sb_alloc_security(struct super_block *sb)
2341{
2342 return superblock_alloc_security(sb);
2343}
2344
2345static void selinux_sb_free_security(struct super_block *sb)
2346{
2347 superblock_free_security(sb);
2348}
2349
2350static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2351{
2352 if (plen > olen)
2353 return 0;
2354
2355 return !memcmp(prefix, option, plen);
2356}
2357
2358static inline int selinux_option(char *option, int len)
2359{
Eric Paris832cbd92008-04-01 13:24:09 -04002360 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2361 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2362 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002363 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2364 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365}
2366
2367static inline void take_option(char **to, char *from, int *first, int len)
2368{
2369 if (!*first) {
2370 **to = ',';
2371 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002372 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 *first = 0;
2374 memcpy(*to, from, len);
2375 *to += len;
2376}
2377
Eric Paris828dfe12008-04-17 13:17:49 -04002378static inline void take_selinux_option(char **to, char *from, int *first,
2379 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002380{
2381 int current_size = 0;
2382
2383 if (!*first) {
2384 **to = '|';
2385 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002386 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002387 *first = 0;
2388
2389 while (current_size < len) {
2390 if (*from != '"') {
2391 **to = *from;
2392 *to += 1;
2393 }
2394 from += 1;
2395 current_size += 1;
2396 }
2397}
2398
Eric Parise0007522008-03-05 10:31:54 -05002399static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400{
2401 int fnosec, fsec, rc = 0;
2402 char *in_save, *in_curr, *in_end;
2403 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002404 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406 in_curr = orig;
2407 sec_curr = copy;
2408
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2410 if (!nosec) {
2411 rc = -ENOMEM;
2412 goto out;
2413 }
2414
2415 nosec_save = nosec;
2416 fnosec = fsec = 1;
2417 in_save = in_end = orig;
2418
2419 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002420 if (*in_end == '"')
2421 open_quote = !open_quote;
2422 if ((*in_end == ',' && open_quote == 0) ||
2423 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 int len = in_end - in_curr;
2425
2426 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002427 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 else
2429 take_option(&nosec, in_curr, &fnosec, len);
2430
2431 in_curr = in_end + 1;
2432 }
2433 } while (*in_end++);
2434
Eric Paris6931dfc2005-06-30 02:58:51 -07002435 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002436 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437out:
2438 return rc;
2439}
2440
Eric Paris026eb162011-03-03 16:09:14 -05002441static int selinux_sb_remount(struct super_block *sb, void *data)
2442{
2443 int rc, i, *flags;
2444 struct security_mnt_opts opts;
2445 char *secdata, **mount_options;
2446 struct superblock_security_struct *sbsec = sb->s_security;
2447
2448 if (!(sbsec->flags & SE_SBINITIALIZED))
2449 return 0;
2450
2451 if (!data)
2452 return 0;
2453
2454 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2455 return 0;
2456
2457 security_init_mnt_opts(&opts);
2458 secdata = alloc_secdata();
2459 if (!secdata)
2460 return -ENOMEM;
2461 rc = selinux_sb_copy_data(data, secdata);
2462 if (rc)
2463 goto out_free_secdata;
2464
2465 rc = selinux_parse_opts_str(secdata, &opts);
2466 if (rc)
2467 goto out_free_secdata;
2468
2469 mount_options = opts.mnt_opts;
2470 flags = opts.mnt_opts_flags;
2471
2472 for (i = 0; i < opts.num_mnt_opts; i++) {
2473 u32 sid;
2474 size_t len;
2475
2476 if (flags[i] == SE_SBLABELSUPP)
2477 continue;
2478 len = strlen(mount_options[i]);
2479 rc = security_context_to_sid(mount_options[i], len, &sid);
2480 if (rc) {
2481 printk(KERN_WARNING "SELinux: security_context_to_sid"
2482 "(%s) failed for (dev %s, type %s) errno=%d\n",
2483 mount_options[i], sb->s_id, sb->s_type->name, rc);
2484 goto out_free_opts;
2485 }
2486 rc = -EINVAL;
2487 switch (flags[i]) {
2488 case FSCONTEXT_MNT:
2489 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2490 goto out_bad_option;
2491 break;
2492 case CONTEXT_MNT:
2493 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2494 goto out_bad_option;
2495 break;
2496 case ROOTCONTEXT_MNT: {
2497 struct inode_security_struct *root_isec;
2498 root_isec = sb->s_root->d_inode->i_security;
2499
2500 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2501 goto out_bad_option;
2502 break;
2503 }
2504 case DEFCONTEXT_MNT:
2505 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2506 goto out_bad_option;
2507 break;
2508 default:
2509 goto out_free_opts;
2510 }
2511 }
2512
2513 rc = 0;
2514out_free_opts:
2515 security_free_mnt_opts(&opts);
2516out_free_secdata:
2517 free_secdata(secdata);
2518 return rc;
2519out_bad_option:
2520 printk(KERN_WARNING "SELinux: unable to change security options "
2521 "during remount (dev %s, type=%s)\n", sb->s_id,
2522 sb->s_type->name);
2523 goto out_free_opts;
2524}
2525
James Morris12204e22008-12-19 10:44:42 +11002526static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527{
David Howells88e67f32008-11-14 10:39:21 +11002528 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002529 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002530 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 int rc;
2532
2533 rc = superblock_doinit(sb, data);
2534 if (rc)
2535 return rc;
2536
James Morris74192242008-12-19 11:41:10 +11002537 /* Allow all mounts performed by the kernel */
2538 if (flags & MS_KERNMOUNT)
2539 return 0;
2540
Eric Parisa2694342011-04-25 13:10:27 -04002541 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002542 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002543 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002544 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545}
2546
David Howells726c3342006-06-23 02:02:58 -07002547static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548{
David Howells88e67f32008-11-14 10:39:21 +11002549 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002550 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002551 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
Eric Parisa2694342011-04-25 13:10:27 -04002553 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002554 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002555 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002556 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557}
2558
Eric Paris828dfe12008-04-17 13:17:49 -04002559static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002560 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002561 char *type,
2562 unsigned long flags,
2563 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564{
David Howells88e67f32008-11-14 10:39:21 +11002565 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
2567 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002568 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002569 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 else
Eric Paris2875fa02011-04-28 16:04:24 -04002571 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572}
2573
2574static int selinux_umount(struct vfsmount *mnt, int flags)
2575{
David Howells88e67f32008-11-14 10:39:21 +11002576 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
David Howells88e67f32008-11-14 10:39:21 +11002578 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002579 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580}
2581
2582/* inode security operations */
2583
2584static int selinux_inode_alloc_security(struct inode *inode)
2585{
2586 return inode_alloc_security(inode);
2587}
2588
2589static void selinux_inode_free_security(struct inode *inode)
2590{
2591 inode_free_security(inode);
2592}
2593
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002594static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002595 const struct qstr *qstr, char **name,
2596 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002597{
Paul Moore5fb49872010-04-22 14:46:19 -04002598 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002599 struct inode_security_struct *dsec;
2600 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002601 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002602 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002603 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002604
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002605 dsec = dir->i_security;
2606 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002607
David Howells275bb412008-11-14 10:39:19 +11002608 sid = tsec->sid;
2609 newsid = tsec->create_sid;
2610
Eric Paris415103f2010-12-02 16:13:40 -05002611 if ((sbsec->flags & SE_SBINITIALIZED) &&
2612 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2613 newsid = sbsec->mntpoint_sid;
2614 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002615 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002616 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002617 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002618 if (rc) {
2619 printk(KERN_WARNING "%s: "
2620 "security_transition_sid failed, rc=%d (dev=%s "
2621 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002622 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002623 -rc, inode->i_sb->s_id, inode->i_ino);
2624 return rc;
2625 }
2626 }
2627
Eric Paris296fddf2006-09-25 23:32:00 -07002628 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002629 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002630 struct inode_security_struct *isec = inode->i_security;
2631 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2632 isec->sid = newsid;
2633 isec->initialized = 1;
2634 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002635
David P. Quigleycd895962009-01-16 09:22:04 -05002636 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002637 return -EOPNOTSUPP;
2638
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002639 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002640 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002641 if (!namep)
2642 return -ENOMEM;
2643 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002644 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002645
2646 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002647 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002648 if (rc) {
2649 kfree(namep);
2650 return rc;
2651 }
2652 *value = context;
2653 *len = clen;
2654 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002655
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002656 return 0;
2657}
2658
Al Viro4acdaf22011-07-26 01:42:34 -04002659static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660{
2661 return may_create(dir, dentry, SECCLASS_FILE);
2662}
2663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2665{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 return may_link(dir, old_dentry, MAY_LINK);
2667}
2668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2670{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return may_link(dir, dentry, MAY_UNLINK);
2672}
2673
2674static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2675{
2676 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2677}
2678
Al Viro18bb1db2011-07-26 01:41:39 -04002679static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680{
2681 return may_create(dir, dentry, SECCLASS_DIR);
2682}
2683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2685{
2686 return may_link(dir, dentry, MAY_RMDIR);
2687}
2688
Al Viro1a67aaf2011-07-26 01:52:52 -04002689static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2692}
2693
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002695 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696{
2697 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2698}
2699
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700static int selinux_inode_readlink(struct dentry *dentry)
2701{
David Howells88e67f32008-11-14 10:39:21 +11002702 const struct cred *cred = current_cred();
2703
Eric Paris2875fa02011-04-28 16:04:24 -04002704 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705}
2706
2707static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2708{
David Howells88e67f32008-11-14 10:39:21 +11002709 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
Eric Paris2875fa02011-04-28 16:04:24 -04002711 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712}
2713
Al Viroe74f71e2011-06-20 19:38:15 -04002714static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715{
David Howells88e67f32008-11-14 10:39:21 +11002716 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002717 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002718 struct selinux_audit_data sad = {0,};
Eric Parisb782e0a2010-07-23 11:44:03 -04002719 u32 perms;
2720 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002721 unsigned flags = mask & MAY_NOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
Eric Parisb782e0a2010-07-23 11:44:03 -04002723 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002724 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2725
Eric Parisb782e0a2010-07-23 11:44:03 -04002726 /* No permission to check. Existence test. */
2727 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Eric Parisf48b7392011-04-25 12:54:27 -04002730 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002731 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002732 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002733
2734 if (from_access)
Eric Paris3b3b0e42012-04-03 09:37:02 -07002735 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
Eric Parisb782e0a2010-07-23 11:44:03 -04002736
2737 perms = file_mask_to_av(inode->i_mode, mask);
2738
Eric Paris9ade0cf2011-04-25 16:26:29 -04002739 return inode_has_perm(cred, inode, perms, &ad, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740}
2741
2742static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2743{
David Howells88e67f32008-11-14 10:39:21 +11002744 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002745 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002747 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2748 if (ia_valid & ATTR_FORCE) {
2749 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2750 ATTR_FORCE);
2751 if (!ia_valid)
2752 return 0;
2753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002755 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2756 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002757 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
Eric Paris2875fa02011-04-28 16:04:24 -04002759 return dentry_has_perm(cred, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760}
2761
2762static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2763{
David Howells88e67f32008-11-14 10:39:21 +11002764 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002765 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002766
Eric Paris2875fa02011-04-28 16:04:24 -04002767 path.dentry = dentry;
2768 path.mnt = mnt;
2769
2770 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771}
2772
David Howells8f0cfa52008-04-29 00:59:41 -07002773static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002774{
David Howells88e67f32008-11-14 10:39:21 +11002775 const struct cred *cred = current_cred();
2776
Serge E. Hallynb5376772007-10-16 23:31:36 -07002777 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2778 sizeof XATTR_SECURITY_PREFIX - 1)) {
2779 if (!strcmp(name, XATTR_NAME_CAPS)) {
2780 if (!capable(CAP_SETFCAP))
2781 return -EPERM;
2782 } else if (!capable(CAP_SYS_ADMIN)) {
2783 /* A different attribute in the security namespace.
2784 Restrict to administrator. */
2785 return -EPERM;
2786 }
2787 }
2788
2789 /* Not an attribute we recognize, so just check the
2790 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002791 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002792}
2793
David Howells8f0cfa52008-04-29 00:59:41 -07002794static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2795 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 struct inode *inode = dentry->d_inode;
2798 struct inode_security_struct *isec = inode->i_security;
2799 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002800 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002801 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11002802 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 int rc = 0;
2804
Serge E. Hallynb5376772007-10-16 23:31:36 -07002805 if (strcmp(name, XATTR_NAME_SELINUX))
2806 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002809 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 return -EOPNOTSUPP;
2811
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002812 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 return -EPERM;
2814
Eric Parisa2694342011-04-25 13:10:27 -04002815 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002816 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002817 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
David Howells275bb412008-11-14 10:39:19 +11002819 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 FILE__RELABELFROM, &ad);
2821 if (rc)
2822 return rc;
2823
2824 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002825 if (rc == -EINVAL) {
2826 if (!capable(CAP_MAC_ADMIN))
2827 return rc;
2828 rc = security_context_to_sid_force(value, size, &newsid);
2829 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 if (rc)
2831 return rc;
2832
David Howells275bb412008-11-14 10:39:19 +11002833 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 FILE__RELABELTO, &ad);
2835 if (rc)
2836 return rc;
2837
David Howells275bb412008-11-14 10:39:19 +11002838 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002839 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 if (rc)
2841 return rc;
2842
2843 return avc_has_perm(newsid,
2844 sbsec->sid,
2845 SECCLASS_FILESYSTEM,
2846 FILESYSTEM__ASSOCIATE,
2847 &ad);
2848}
2849
David Howells8f0cfa52008-04-29 00:59:41 -07002850static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002851 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002852 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853{
2854 struct inode *inode = dentry->d_inode;
2855 struct inode_security_struct *isec = inode->i_security;
2856 u32 newsid;
2857 int rc;
2858
2859 if (strcmp(name, XATTR_NAME_SELINUX)) {
2860 /* Not an attribute we recognize, so nothing to do. */
2861 return;
2862 }
2863
Stephen Smalley12b29f32008-05-07 13:03:20 -04002864 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002866 printk(KERN_ERR "SELinux: unable to map context to SID"
2867 "for (%s, %lu), rc=%d\n",
2868 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return;
2870 }
2871
2872 isec->sid = newsid;
2873 return;
2874}
2875
David Howells8f0cfa52008-04-29 00:59:41 -07002876static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877{
David Howells88e67f32008-11-14 10:39:21 +11002878 const struct cred *cred = current_cred();
2879
Eric Paris2875fa02011-04-28 16:04:24 -04002880 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881}
2882
Eric Paris828dfe12008-04-17 13:17:49 -04002883static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884{
David Howells88e67f32008-11-14 10:39:21 +11002885 const struct cred *cred = current_cred();
2886
Eric Paris2875fa02011-04-28 16:04:24 -04002887 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888}
2889
David Howells8f0cfa52008-04-29 00:59:41 -07002890static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002892 if (strcmp(name, XATTR_NAME_SELINUX))
2893 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 /* No one is allowed to remove a SELinux security label.
2896 You can change the label, but all data must be labeled. */
2897 return -EACCES;
2898}
2899
James Morrisd381d8a2005-10-30 14:59:22 -08002900/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002901 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002902 *
2903 * Permission check is handled by selinux_inode_getxattr hook.
2904 */
David P. Quigley42492592008-02-04 22:29:39 -08002905static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906{
David P. Quigley42492592008-02-04 22:29:39 -08002907 u32 size;
2908 int error;
2909 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002912 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2913 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002915 /*
2916 * If the caller has CAP_MAC_ADMIN, then get the raw context
2917 * value even if it is not defined by current policy; otherwise,
2918 * use the in-core value under current policy.
2919 * Use the non-auditing forms of the permission checks since
2920 * getxattr may be called by unprivileged processes commonly
2921 * and lack of permission just means that we fall back to the
2922 * in-core context value, not a denial.
2923 */
Eric Paris6a9de492012-01-03 12:25:14 -05002924 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002925 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002926 if (!error)
2927 error = security_sid_to_context_force(isec->sid, &context,
2928 &size);
2929 else
2930 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002931 if (error)
2932 return error;
2933 error = size;
2934 if (alloc) {
2935 *buffer = context;
2936 goto out_nofree;
2937 }
2938 kfree(context);
2939out_nofree:
2940 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941}
2942
2943static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002944 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
2946 struct inode_security_struct *isec = inode->i_security;
2947 u32 newsid;
2948 int rc;
2949
2950 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2951 return -EOPNOTSUPP;
2952
2953 if (!value || !size)
2954 return -EACCES;
2955
Eric Paris828dfe12008-04-17 13:17:49 -04002956 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 if (rc)
2958 return rc;
2959
2960 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002961 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 return 0;
2963}
2964
2965static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2966{
2967 const int len = sizeof(XATTR_NAME_SELINUX);
2968 if (buffer && len <= buffer_size)
2969 memcpy(buffer, XATTR_NAME_SELINUX, len);
2970 return len;
2971}
2972
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002973static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2974{
2975 struct inode_security_struct *isec = inode->i_security;
2976 *secid = isec->sid;
2977}
2978
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979/* file security operations */
2980
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002981static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982{
David Howells88e67f32008-11-14 10:39:21 +11002983 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002984 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2987 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2988 mask |= MAY_APPEND;
2989
Paul Moore389fb802009-03-27 17:10:34 -04002990 return file_has_perm(cred, file,
2991 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992}
2993
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002994static int selinux_file_permission(struct file *file, int mask)
2995{
Stephen Smalley20dda182009-06-22 14:54:53 -04002996 struct inode *inode = file->f_path.dentry->d_inode;
2997 struct file_security_struct *fsec = file->f_security;
2998 struct inode_security_struct *isec = inode->i_security;
2999 u32 sid = current_sid();
3000
Paul Moore389fb802009-03-27 17:10:34 -04003001 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003002 /* No permission to check. Existence test. */
3003 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003004
Stephen Smalley20dda182009-06-22 14:54:53 -04003005 if (sid == fsec->sid && fsec->isid == isec->sid &&
3006 fsec->pseqno == avc_policy_seqno())
3007 /* No change since dentry_open check. */
3008 return 0;
3009
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003010 return selinux_revalidate_file_permission(file, mask);
3011}
3012
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013static int selinux_file_alloc_security(struct file *file)
3014{
3015 return file_alloc_security(file);
3016}
3017
3018static void selinux_file_free_security(struct file *file)
3019{
3020 file_free_security(file);
3021}
3022
3023static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3024 unsigned long arg)
3025{
David Howells88e67f32008-11-14 10:39:21 +11003026 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05003027 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
Eric Paris0b24dcb2011-02-25 15:39:20 -05003029 switch (cmd) {
3030 case FIONREAD:
3031 /* fall through */
3032 case FIBMAP:
3033 /* fall through */
3034 case FIGETBSZ:
3035 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003036 case FS_IOC_GETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003037 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003038 case FS_IOC_GETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003039 error = file_has_perm(cred, file, FILE__GETATTR);
3040 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Al Viro2f99c362012-03-23 16:04:05 -04003042 case FS_IOC_SETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003043 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003044 case FS_IOC_SETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003045 error = file_has_perm(cred, file, FILE__SETATTR);
3046 break;
3047
3048 /* sys_ioctl() checks */
3049 case FIONBIO:
3050 /* fall through */
3051 case FIOASYNC:
3052 error = file_has_perm(cred, file, 0);
3053 break;
3054
3055 case KDSKBENT:
3056 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05003057 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3058 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003059 break;
3060
3061 /* default case assumes that the command will go
3062 * to the file's ioctl() function.
3063 */
3064 default:
3065 error = file_has_perm(cred, file, FILE__IOCTL);
3066 }
3067 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068}
3069
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003070static int default_noexec;
3071
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3073{
David Howells88e67f32008-11-14 10:39:21 +11003074 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003075 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003076
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003077 if (default_noexec &&
3078 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 /*
3080 * We are making executable an anonymous mapping or a
3081 * private file mapping that will also be writable.
3082 * This has an additional check.
3083 */
David Howellsd84f4f92008-11-14 10:39:23 +11003084 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003086 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089 if (file) {
3090 /* read access is always possible with a mapping */
3091 u32 av = FILE__READ;
3092
3093 /* write access only matters if the mapping is shared */
3094 if (shared && (prot & PROT_WRITE))
3095 av |= FILE__WRITE;
3096
3097 if (prot & PROT_EXEC)
3098 av |= FILE__EXECUTE;
3099
David Howells88e67f32008-11-14 10:39:21 +11003100 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 }
David Howellsd84f4f92008-11-14 10:39:23 +11003102
3103error:
3104 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105}
3106
3107static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003108 unsigned long prot, unsigned long flags,
3109 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110{
Eric Parised032182007-06-28 15:55:21 -04003111 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003112 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
Eric Paris84336d1a2009-07-31 12:54:05 -04003114 /*
3115 * notice that we are intentionally putting the SELinux check before
3116 * the secondary cap_file_mmap check. This is such a likely attempt
3117 * at bad behaviour/exploit that we always want to get the AVC, even
3118 * if DAC would have also denied the operation.
3119 */
Eric Parisa2551df2009-07-31 12:54:11 -04003120 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003121 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3122 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003123 if (rc)
3124 return rc;
3125 }
3126
3127 /* do DAC check on address space usage */
3128 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003129 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 return rc;
3131
3132 if (selinux_checkreqprot)
3133 prot = reqprot;
3134
3135 return file_map_prot_check(file, prot,
3136 (flags & MAP_TYPE) == MAP_SHARED);
3137}
3138
3139static int selinux_file_mprotect(struct vm_area_struct *vma,
3140 unsigned long reqprot,
3141 unsigned long prot)
3142{
David Howells88e67f32008-11-14 10:39:21 +11003143 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
3145 if (selinux_checkreqprot)
3146 prot = reqprot;
3147
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003148 if (default_noexec &&
3149 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003150 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003151 if (vma->vm_start >= vma->vm_mm->start_brk &&
3152 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003153 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003154 } else if (!vma->vm_file &&
3155 vma->vm_start <= vma->vm_mm->start_stack &&
3156 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003157 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003158 } else if (vma->vm_file && vma->anon_vma) {
3159 /*
3160 * We are making executable a file mapping that has
3161 * had some COW done. Since pages might have been
3162 * written, check ability to execute the possibly
3163 * modified content. This typically should only
3164 * occur for text relocations.
3165 */
David Howellsd84f4f92008-11-14 10:39:23 +11003166 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003167 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003168 if (rc)
3169 return rc;
3170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3173}
3174
3175static int selinux_file_lock(struct file *file, unsigned int cmd)
3176{
David Howells88e67f32008-11-14 10:39:21 +11003177 const struct cred *cred = current_cred();
3178
3179 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180}
3181
3182static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3183 unsigned long arg)
3184{
David Howells88e67f32008-11-14 10:39:21 +11003185 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 int err = 0;
3187
3188 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003189 case F_SETFL:
3190 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3191 err = -EINVAL;
3192 break;
3193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Eric Paris828dfe12008-04-17 13:17:49 -04003195 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003196 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003198 }
3199 /* fall through */
3200 case F_SETOWN:
3201 case F_SETSIG:
3202 case F_GETFL:
3203 case F_GETOWN:
3204 case F_GETSIG:
3205 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003206 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003207 break;
3208 case F_GETLK:
3209 case F_SETLK:
3210 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003212 case F_GETLK64:
3213 case F_SETLK64:
3214 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003216 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3217 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003219 }
David Howells88e67f32008-11-14 10:39:21 +11003220 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003221 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 }
3223
3224 return err;
3225}
3226
3227static int selinux_file_set_fowner(struct file *file)
3228{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 struct file_security_struct *fsec;
3230
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003232 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
3234 return 0;
3235}
3236
3237static int selinux_file_send_sigiotask(struct task_struct *tsk,
3238 struct fown_struct *fown, int signum)
3239{
Eric Paris828dfe12008-04-17 13:17:49 -04003240 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003241 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 struct file_security_struct *fsec;
3244
3245 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003246 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 fsec = file->f_security;
3249
3250 if (!signum)
3251 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3252 else
3253 perm = signal_to_av(signum);
3254
David Howells275bb412008-11-14 10:39:19 +11003255 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 SECCLASS_PROCESS, perm, NULL);
3257}
3258
3259static int selinux_file_receive(struct file *file)
3260{
David Howells88e67f32008-11-14 10:39:21 +11003261 const struct cred *cred = current_cred();
3262
3263 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264}
3265
David Howells745ca242008-11-14 10:39:22 +11003266static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003267{
3268 struct file_security_struct *fsec;
3269 struct inode *inode;
3270 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003271
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003272 inode = file->f_path.dentry->d_inode;
3273 fsec = file->f_security;
3274 isec = inode->i_security;
3275 /*
3276 * Save inode label and policy sequence number
3277 * at open-time so that selinux_file_permission
3278 * can determine whether revalidation is necessary.
3279 * Task label is already saved in the file security
3280 * struct as its SID.
3281 */
3282 fsec->isid = isec->sid;
3283 fsec->pseqno = avc_policy_seqno();
3284 /*
3285 * Since the inode label or policy seqno may have changed
3286 * between the selinux_inode_permission check and the saving
3287 * of state above, recheck that access is still permitted.
3288 * Otherwise, access might never be revalidated against the
3289 * new inode label or new policy.
3290 * This check is not redundant - do not remove.
3291 */
Linus Torvalds95f4efb2011-06-08 15:11:56 -07003292 return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003293}
3294
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295/* task security operations */
3296
3297static int selinux_task_create(unsigned long clone_flags)
3298{
David Howells3b11a1d2008-11-14 10:39:26 +11003299 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300}
3301
David Howellsf1752ee2008-11-14 10:39:17 +11003302/*
David Howellsee18d642009-09-02 09:14:21 +01003303 * allocate the SELinux part of blank credentials
3304 */
3305static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3306{
3307 struct task_security_struct *tsec;
3308
3309 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3310 if (!tsec)
3311 return -ENOMEM;
3312
3313 cred->security = tsec;
3314 return 0;
3315}
3316
3317/*
David Howellsf1752ee2008-11-14 10:39:17 +11003318 * detach and free the LSM part of a set of credentials
3319 */
3320static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321{
David Howellsf1752ee2008-11-14 10:39:17 +11003322 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003323
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003324 /*
3325 * cred->security == NULL if security_cred_alloc_blank() or
3326 * security_prepare_creds() returned an error.
3327 */
3328 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003329 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003330 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331}
3332
David Howellsd84f4f92008-11-14 10:39:23 +11003333/*
3334 * prepare a new set of credentials for modification
3335 */
3336static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3337 gfp_t gfp)
3338{
3339 const struct task_security_struct *old_tsec;
3340 struct task_security_struct *tsec;
3341
3342 old_tsec = old->security;
3343
3344 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3345 if (!tsec)
3346 return -ENOMEM;
3347
3348 new->security = tsec;
3349 return 0;
3350}
3351
3352/*
David Howellsee18d642009-09-02 09:14:21 +01003353 * transfer the SELinux data to a blank set of creds
3354 */
3355static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3356{
3357 const struct task_security_struct *old_tsec = old->security;
3358 struct task_security_struct *tsec = new->security;
3359
3360 *tsec = *old_tsec;
3361}
3362
3363/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003364 * set the security data for a kernel service
3365 * - all the creation contexts are set to unlabelled
3366 */
3367static int selinux_kernel_act_as(struct cred *new, u32 secid)
3368{
3369 struct task_security_struct *tsec = new->security;
3370 u32 sid = current_sid();
3371 int ret;
3372
3373 ret = avc_has_perm(sid, secid,
3374 SECCLASS_KERNEL_SERVICE,
3375 KERNEL_SERVICE__USE_AS_OVERRIDE,
3376 NULL);
3377 if (ret == 0) {
3378 tsec->sid = secid;
3379 tsec->create_sid = 0;
3380 tsec->keycreate_sid = 0;
3381 tsec->sockcreate_sid = 0;
3382 }
3383 return ret;
3384}
3385
3386/*
3387 * set the file creation context in a security record to the same as the
3388 * objective context of the specified inode
3389 */
3390static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3391{
3392 struct inode_security_struct *isec = inode->i_security;
3393 struct task_security_struct *tsec = new->security;
3394 u32 sid = current_sid();
3395 int ret;
3396
3397 ret = avc_has_perm(sid, isec->sid,
3398 SECCLASS_KERNEL_SERVICE,
3399 KERNEL_SERVICE__CREATE_FILES_AS,
3400 NULL);
3401
3402 if (ret == 0)
3403 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003404 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003405}
3406
Eric Parisdd8dbf22009-11-03 16:35:32 +11003407static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003408{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003409 u32 sid;
3410 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003411 struct selinux_audit_data sad = {0,};
Eric Parisdd8dbf22009-11-03 16:35:32 +11003412
3413 sid = task_sid(current);
3414
3415 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003416 ad.selinux_audit_data = &sad;
Eric Parisdd8dbf22009-11-03 16:35:32 +11003417 ad.u.kmod_name = kmod_name;
3418
3419 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3420 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003421}
3422
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3424{
David Howells3b11a1d2008-11-14 10:39:26 +11003425 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426}
3427
3428static int selinux_task_getpgid(struct task_struct *p)
3429{
David Howells3b11a1d2008-11-14 10:39:26 +11003430 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431}
3432
3433static int selinux_task_getsid(struct task_struct *p)
3434{
David Howells3b11a1d2008-11-14 10:39:26 +11003435 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436}
3437
David Quigleyf9008e42006-06-30 01:55:46 -07003438static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3439{
David Howells275bb412008-11-14 10:39:19 +11003440 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003441}
3442
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443static int selinux_task_setnice(struct task_struct *p, int nice)
3444{
3445 int rc;
3446
Eric Paris200ac532009-02-12 15:01:04 -05003447 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 if (rc)
3449 return rc;
3450
David Howells3b11a1d2008-11-14 10:39:26 +11003451 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452}
3453
James Morris03e68062006-06-23 02:03:58 -07003454static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3455{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003456 int rc;
3457
Eric Paris200ac532009-02-12 15:01:04 -05003458 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003459 if (rc)
3460 return rc;
3461
David Howells3b11a1d2008-11-14 10:39:26 +11003462 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003463}
3464
David Quigleya1836a42006-06-30 01:55:49 -07003465static int selinux_task_getioprio(struct task_struct *p)
3466{
David Howells3b11a1d2008-11-14 10:39:26 +11003467 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003468}
3469
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003470static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3471 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003473 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474
3475 /* Control the ability to change the hard limit (whether
3476 lowering or raising it), so that the hard limit can
3477 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003478 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003480 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481
3482 return 0;
3483}
3484
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003485static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003487 int rc;
3488
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003489 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003490 if (rc)
3491 return rc;
3492
David Howells3b11a1d2008-11-14 10:39:26 +11003493 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494}
3495
3496static int selinux_task_getscheduler(struct task_struct *p)
3497{
David Howells3b11a1d2008-11-14 10:39:26 +11003498 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499}
3500
David Quigley35601542006-06-23 02:04:01 -07003501static int selinux_task_movememory(struct task_struct *p)
3502{
David Howells3b11a1d2008-11-14 10:39:26 +11003503 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003504}
3505
David Quigleyf9008e42006-06-30 01:55:46 -07003506static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3507 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508{
3509 u32 perm;
3510 int rc;
3511
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 if (!sig)
3513 perm = PROCESS__SIGNULL; /* null signal; existence test */
3514 else
3515 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003516 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003517 rc = avc_has_perm(secid, task_sid(p),
3518 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003519 else
David Howells3b11a1d2008-11-14 10:39:26 +11003520 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003521 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522}
3523
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524static int selinux_task_wait(struct task_struct *p)
3525{
Eric Paris8a535142007-10-22 16:10:31 -04003526 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527}
3528
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529static void selinux_task_to_inode(struct task_struct *p,
3530 struct inode *inode)
3531{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003533 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
David Howells275bb412008-11-14 10:39:19 +11003535 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537}
3538
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003540static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003541 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542{
3543 int offset, ihlen, ret = -EINVAL;
3544 struct iphdr _iph, *ih;
3545
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003546 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3548 if (ih == NULL)
3549 goto out;
3550
3551 ihlen = ih->ihl * 4;
3552 if (ihlen < sizeof(_iph))
3553 goto out;
3554
Eric Paris48c62af2012-04-02 13:15:44 -04003555 ad->u.net->v4info.saddr = ih->saddr;
3556 ad->u.net->v4info.daddr = ih->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 ret = 0;
3558
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003559 if (proto)
3560 *proto = ih->protocol;
3561
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003563 case IPPROTO_TCP: {
3564 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
Eric Paris828dfe12008-04-17 13:17:49 -04003566 if (ntohs(ih->frag_off) & IP_OFFSET)
3567 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
3569 offset += ihlen;
3570 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3571 if (th == NULL)
3572 break;
3573
Eric Paris48c62af2012-04-02 13:15:44 -04003574 ad->u.net->sport = th->source;
3575 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578
Eric Paris828dfe12008-04-17 13:17:49 -04003579 case IPPROTO_UDP: {
3580 struct udphdr _udph, *uh;
3581
3582 if (ntohs(ih->frag_off) & IP_OFFSET)
3583 break;
3584
3585 offset += ihlen;
3586 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3587 if (uh == NULL)
3588 break;
3589
Eric Paris48c62af2012-04-02 13:15:44 -04003590 ad->u.net->sport = uh->source;
3591 ad->u.net->dport = uh->dest;
Eric Paris828dfe12008-04-17 13:17:49 -04003592 break;
3593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
James Morris2ee92d42006-11-13 16:09:01 -08003595 case IPPROTO_DCCP: {
3596 struct dccp_hdr _dccph, *dh;
3597
3598 if (ntohs(ih->frag_off) & IP_OFFSET)
3599 break;
3600
3601 offset += ihlen;
3602 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3603 if (dh == NULL)
3604 break;
3605
Eric Paris48c62af2012-04-02 13:15:44 -04003606 ad->u.net->sport = dh->dccph_sport;
3607 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003608 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003609 }
James Morris2ee92d42006-11-13 16:09:01 -08003610
Eric Paris828dfe12008-04-17 13:17:49 -04003611 default:
3612 break;
3613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614out:
3615 return ret;
3616}
3617
3618#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3619
3620/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003621static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003622 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623{
3624 u8 nexthdr;
3625 int ret = -EINVAL, offset;
3626 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003627 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003629 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3631 if (ip6 == NULL)
3632 goto out;
3633
Eric Paris48c62af2012-04-02 13:15:44 -04003634 ad->u.net->v6info.saddr = ip6->saddr;
3635 ad->u.net->v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 ret = 0;
3637
3638 nexthdr = ip6->nexthdr;
3639 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003640 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 if (offset < 0)
3642 goto out;
3643
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003644 if (proto)
3645 *proto = nexthdr;
3646
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 switch (nexthdr) {
3648 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003649 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650
3651 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3652 if (th == NULL)
3653 break;
3654
Eric Paris48c62af2012-04-02 13:15:44 -04003655 ad->u.net->sport = th->source;
3656 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 break;
3658 }
3659
3660 case IPPROTO_UDP: {
3661 struct udphdr _udph, *uh;
3662
3663 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3664 if (uh == NULL)
3665 break;
3666
Eric Paris48c62af2012-04-02 13:15:44 -04003667 ad->u.net->sport = uh->source;
3668 ad->u.net->dport = uh->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 break;
3670 }
3671
James Morris2ee92d42006-11-13 16:09:01 -08003672 case IPPROTO_DCCP: {
3673 struct dccp_hdr _dccph, *dh;
3674
3675 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3676 if (dh == NULL)
3677 break;
3678
Eric Paris48c62af2012-04-02 13:15:44 -04003679 ad->u.net->sport = dh->dccph_sport;
3680 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003681 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003682 }
James Morris2ee92d42006-11-13 16:09:01 -08003683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 /* includes fragments */
3685 default:
3686 break;
3687 }
3688out:
3689 return ret;
3690}
3691
3692#endif /* IPV6 */
3693
Thomas Liu2bf49692009-07-14 12:14:09 -04003694static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003695 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696{
David Howellscf9481e2008-07-27 21:31:07 +10003697 char *addrp;
3698 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
Eric Paris48c62af2012-04-02 13:15:44 -04003700 switch (ad->u.net->family) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003702 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003703 if (ret)
3704 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003705 addrp = (char *)(src ? &ad->u.net->v4info.saddr :
3706 &ad->u.net->v4info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003707 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708
3709#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3710 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003711 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003712 if (ret)
3713 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003714 addrp = (char *)(src ? &ad->u.net->v6info.saddr :
3715 &ad->u.net->v6info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003716 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717#endif /* IPV6 */
3718 default:
David Howellscf9481e2008-07-27 21:31:07 +10003719 addrp = NULL;
3720 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 }
3722
David Howellscf9481e2008-07-27 21:31:07 +10003723parse_error:
3724 printk(KERN_WARNING
3725 "SELinux: failure in selinux_parse_skb(),"
3726 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003728
3729okay:
3730 if (_addrp)
3731 *_addrp = addrp;
3732 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733}
3734
Paul Moore4f6a9932007-03-01 14:35:22 -05003735/**
Paul Moore220deb92008-01-29 08:38:23 -05003736 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003737 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003738 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003739 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003740 *
3741 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003742 * Check the various different forms of network peer labeling and determine
3743 * the peer label/SID for the packet; most of the magic actually occurs in
3744 * the security server function security_net_peersid_cmp(). The function
3745 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3746 * or -EACCES if @sid is invalid due to inconsistencies with the different
3747 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003748 *
3749 */
Paul Moore220deb92008-01-29 08:38:23 -05003750static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003751{
Paul Moore71f1cb02008-01-29 08:51:16 -05003752 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003753 u32 xfrm_sid;
3754 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003755 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003756
Paul Moore73ec9552013-12-10 14:57:54 -05003757 selinux_xfrm_skb_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003758 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003759
Paul Moore71f1cb02008-01-29 08:51:16 -05003760 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3761 if (unlikely(err)) {
3762 printk(KERN_WARNING
3763 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3764 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003765 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003766 }
Paul Moore220deb92008-01-29 08:38:23 -05003767
3768 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003769}
3770
Paul Moore2ea04e52013-12-04 16:10:51 -05003771/**
3772 * selinux_conn_sid - Determine the child socket label for a connection
3773 * @sk_sid: the parent socket's SID
3774 * @skb_sid: the packet's SID
3775 * @conn_sid: the resulting connection SID
3776 *
3777 * If @skb_sid is valid then the user:role:type information from @sk_sid is
3778 * combined with the MLS information from @skb_sid in order to create
3779 * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
3780 * of @sk_sid. Returns zero on success, negative values on failure.
3781 *
3782 */
3783static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
3784{
3785 int err = 0;
3786
3787 if (skb_sid != SECSID_NULL)
3788 err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid);
3789 else
3790 *conn_sid = sk_sid;
3791
3792 return err;
3793}
3794
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003796
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003797static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3798 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003799{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003800 if (tsec->sockcreate_sid > SECSID_NULL) {
3801 *socksid = tsec->sockcreate_sid;
3802 return 0;
3803 }
3804
3805 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3806 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003807}
3808
Paul Moore253bfae2010-04-22 14:46:19 -04003809static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810{
Paul Moore253bfae2010-04-22 14:46:19 -04003811 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003812 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003813 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003814 struct lsm_network_audit net = {0,};
Paul Moore253bfae2010-04-22 14:46:19 -04003815 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816
Paul Moore253bfae2010-04-22 14:46:19 -04003817 if (sksec->sid == SECINITSID_KERNEL)
3818 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
Thomas Liu2bf49692009-07-14 12:14:09 -04003820 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003821 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003822 ad.u.net = &net;
3823 ad.u.net->sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
Paul Moore253bfae2010-04-22 14:46:19 -04003825 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826}
3827
3828static int selinux_socket_create(int family, int type,
3829 int protocol, int kern)
3830{
Paul Moore5fb49872010-04-22 14:46:19 -04003831 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003832 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003833 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003834 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835
3836 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003837 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838
David Howells275bb412008-11-14 10:39:19 +11003839 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003840 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3841 if (rc)
3842 return rc;
3843
Paul Moored4f2d972010-04-22 14:46:18 -04003844 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845}
3846
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003847static int selinux_socket_post_create(struct socket *sock, int family,
3848 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849{
Paul Moore5fb49872010-04-22 14:46:19 -04003850 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003851 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003852 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003853 int err = 0;
3854
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003855 isec->sclass = socket_type_to_security_class(family, type, protocol);
3856
David Howells275bb412008-11-14 10:39:19 +11003857 if (kern)
3858 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003859 else {
3860 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3861 if (err)
3862 return err;
3863 }
David Howells275bb412008-11-14 10:39:19 +11003864
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 isec->initialized = 1;
3866
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003867 if (sock->sk) {
3868 sksec = sock->sk->sk_security;
3869 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003870 sksec->sclass = isec->sclass;
Paul Moore389fb802009-03-27 17:10:34 -04003871 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003872 }
3873
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003874 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875}
3876
3877/* Range of port numbers used to automatically bind.
3878 Need to determine whether we should perform a name_bind
3879 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880
3881static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3882{
Paul Moore253bfae2010-04-22 14:46:19 -04003883 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 u16 family;
3885 int err;
3886
Paul Moore253bfae2010-04-22 14:46:19 -04003887 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 if (err)
3889 goto out;
3890
3891 /*
3892 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003893 * Multiple address binding for SCTP is not supported yet: we just
3894 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 */
Paul Moore253bfae2010-04-22 14:46:19 -04003896 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 if (family == PF_INET || family == PF_INET6) {
3898 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003899 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003900 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003901 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003902 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 struct sockaddr_in *addr4 = NULL;
3904 struct sockaddr_in6 *addr6 = NULL;
3905 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003906 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 if (family == PF_INET) {
3909 addr4 = (struct sockaddr_in *)address;
3910 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 addrp = (char *)&addr4->sin_addr.s_addr;
3912 } else {
3913 addr6 = (struct sockaddr_in6 *)address;
3914 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 addrp = (char *)&addr6->sin6_addr.s6_addr;
3916 }
3917
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003918 if (snum) {
3919 int low, high;
3920
3921 inet_get_local_port_range(&low, &high);
3922
3923 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003924 err = sel_netport_sid(sk->sk_protocol,
3925 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003926 if (err)
3927 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003928 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003929 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003930 ad.u.net = &net;
3931 ad.u.net->sport = htons(snum);
3932 ad.u.net->family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003933 err = avc_has_perm(sksec->sid, sid,
3934 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003935 SOCKET__NAME_BIND, &ad);
3936 if (err)
3937 goto out;
3938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 }
Eric Paris828dfe12008-04-17 13:17:49 -04003940
Paul Moore253bfae2010-04-22 14:46:19 -04003941 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003942 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 node_perm = TCP_SOCKET__NODE_BIND;
3944 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003945
James Morris13402582005-09-30 14:24:34 -04003946 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 node_perm = UDP_SOCKET__NODE_BIND;
3948 break;
James Morris2ee92d42006-11-13 16:09:01 -08003949
3950 case SECCLASS_DCCP_SOCKET:
3951 node_perm = DCCP_SOCKET__NODE_BIND;
3952 break;
3953
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 default:
3955 node_perm = RAWIP_SOCKET__NODE_BIND;
3956 break;
3957 }
Eric Paris828dfe12008-04-17 13:17:49 -04003958
Paul Moore224dfbd2008-01-29 08:38:13 -05003959 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 if (err)
3961 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003962
Thomas Liu2bf49692009-07-14 12:14:09 -04003963 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003964 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003965 ad.u.net = &net;
3966 ad.u.net->sport = htons(snum);
3967 ad.u.net->family = family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
3969 if (family == PF_INET)
Eric Paris48c62af2012-04-02 13:15:44 -04003970 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 else
Eric Paris48c62af2012-04-02 13:15:44 -04003972 ad.u.net->v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
Paul Moore253bfae2010-04-22 14:46:19 -04003974 err = avc_has_perm(sksec->sid, sid,
3975 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 if (err)
3977 goto out;
3978 }
3979out:
3980 return err;
3981}
3982
3983static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3984{
Paul Moore014ab192008-10-10 10:16:33 -04003985 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003986 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 int err;
3988
Paul Moore253bfae2010-04-22 14:46:19 -04003989 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 if (err)
3991 return err;
3992
3993 /*
James Morris2ee92d42006-11-13 16:09:01 -08003994 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 */
Paul Moore253bfae2010-04-22 14:46:19 -04003996 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
3997 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003998 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003999 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004000 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 struct sockaddr_in *addr4 = NULL;
4002 struct sockaddr_in6 *addr6 = NULL;
4003 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08004004 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005
4006 if (sk->sk_family == PF_INET) {
4007 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07004008 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 return -EINVAL;
4010 snum = ntohs(addr4->sin_port);
4011 } else {
4012 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07004013 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 return -EINVAL;
4015 snum = ntohs(addr6->sin6_port);
4016 }
4017
Paul Moore3e112172008-04-10 10:48:14 -04004018 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 if (err)
4020 goto out;
4021
Paul Moore253bfae2010-04-22 14:46:19 -04004022 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08004023 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
4024
Thomas Liu2bf49692009-07-14 12:14:09 -04004025 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004026 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004027 ad.u.net = &net;
4028 ad.u.net->dport = htons(snum);
4029 ad.u.net->family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04004030 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 if (err)
4032 goto out;
4033 }
4034
Paul Moore014ab192008-10-10 10:16:33 -04004035 err = selinux_netlbl_socket_connect(sk, address);
4036
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037out:
4038 return err;
4039}
4040
4041static int selinux_socket_listen(struct socket *sock, int backlog)
4042{
Paul Moore253bfae2010-04-22 14:46:19 -04004043 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044}
4045
4046static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
4047{
4048 int err;
4049 struct inode_security_struct *isec;
4050 struct inode_security_struct *newisec;
4051
Paul Moore253bfae2010-04-22 14:46:19 -04004052 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 if (err)
4054 return err;
4055
4056 newisec = SOCK_INODE(newsock)->i_security;
4057
4058 isec = SOCK_INODE(sock)->i_security;
4059 newisec->sclass = isec->sclass;
4060 newisec->sid = isec->sid;
4061 newisec->initialized = 1;
4062
4063 return 0;
4064}
4065
4066static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04004067 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068{
Paul Moore253bfae2010-04-22 14:46:19 -04004069 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070}
4071
4072static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4073 int size, int flags)
4074{
Paul Moore253bfae2010-04-22 14:46:19 -04004075 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076}
4077
4078static int selinux_socket_getsockname(struct socket *sock)
4079{
Paul Moore253bfae2010-04-22 14:46:19 -04004080 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081}
4082
4083static int selinux_socket_getpeername(struct socket *sock)
4084{
Paul Moore253bfae2010-04-22 14:46:19 -04004085 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086}
4087
Eric Paris828dfe12008-04-17 13:17:49 -04004088static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089{
Paul Mooref8687af2006-10-30 15:22:15 -08004090 int err;
4091
Paul Moore253bfae2010-04-22 14:46:19 -04004092 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08004093 if (err)
4094 return err;
4095
4096 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097}
4098
4099static int selinux_socket_getsockopt(struct socket *sock, int level,
4100 int optname)
4101{
Paul Moore253bfae2010-04-22 14:46:19 -04004102 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103}
4104
4105static int selinux_socket_shutdown(struct socket *sock, int how)
4106{
Paul Moore253bfae2010-04-22 14:46:19 -04004107 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108}
4109
David S. Miller3610cda2011-01-05 15:38:53 -08004110static int selinux_socket_unix_stream_connect(struct sock *sock,
4111 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 struct sock *newsk)
4113{
David S. Miller3610cda2011-01-05 15:38:53 -08004114 struct sk_security_struct *sksec_sock = sock->sk_security;
4115 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004116 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004117 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004118 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004119 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 int err;
4121
Thomas Liu2bf49692009-07-14 12:14:09 -04004122 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004123 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004124 ad.u.net = &net;
4125 ad.u.net->sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
Paul Moore4d1e2452010-04-22 14:46:18 -04004127 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4128 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4130 if (err)
4131 return err;
4132
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004134 sksec_new->peer_sid = sksec_sock->sid;
4135 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4136 &sksec_new->sid);
4137 if (err)
4138 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004139
Paul Moore4d1e2452010-04-22 14:46:18 -04004140 /* connecting socket */
4141 sksec_sock->peer_sid = sksec_new->sid;
4142
4143 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144}
4145
4146static int selinux_socket_unix_may_send(struct socket *sock,
4147 struct socket *other)
4148{
Paul Moore253bfae2010-04-22 14:46:19 -04004149 struct sk_security_struct *ssec = sock->sk->sk_security;
4150 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004151 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004152 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004153 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Thomas Liu2bf49692009-07-14 12:14:09 -04004155 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004156 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004157 ad.u.net = &net;
4158 ad.u.net->sk = other->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
Paul Moore253bfae2010-04-22 14:46:19 -04004160 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4161 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162}
4163
Paul Mooreeffad8d2008-01-29 08:49:27 -05004164static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4165 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004166 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004167{
4168 int err;
4169 u32 if_sid;
4170 u32 node_sid;
4171
4172 err = sel_netif_sid(ifindex, &if_sid);
4173 if (err)
4174 return err;
4175 err = avc_has_perm(peer_sid, if_sid,
4176 SECCLASS_NETIF, NETIF__INGRESS, ad);
4177 if (err)
4178 return err;
4179
4180 err = sel_netnode_sid(addrp, family, &node_sid);
4181 if (err)
4182 return err;
4183 return avc_has_perm(peer_sid, node_sid,
4184 SECCLASS_NODE, NODE__RECVFROM, ad);
4185}
4186
Paul Moore220deb92008-01-29 08:38:23 -05004187static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004188 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004189{
Paul Moore277d3422008-12-31 12:54:11 -05004190 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004191 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004192 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004193 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004194 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004195 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004196 char *addrp;
4197
Thomas Liu2bf49692009-07-14 12:14:09 -04004198 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004199 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004200 ad.u.net = &net;
4201 ad.u.net->netif = skb->skb_iif;
4202 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004203 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4204 if (err)
4205 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004206
Paul Moore58bfbb52009-03-27 17:10:41 -04004207 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004208 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004209 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004210 if (err)
4211 return err;
4212 }
Paul Moore220deb92008-01-29 08:38:23 -05004213
Steffen Klassertb9679a72011-02-23 12:55:21 +01004214 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4215 if (err)
4216 return err;
4217 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004218
James Morris4e5ab4c2006-06-09 00:33:33 -07004219 return err;
4220}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004221
James Morris4e5ab4c2006-06-09 00:33:33 -07004222static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4223{
Paul Moore220deb92008-01-29 08:38:23 -05004224 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004225 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004226 u16 family = sk->sk_family;
4227 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004228 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004229 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004230 struct lsm_network_audit net = {0,};
Paul Moore220deb92008-01-29 08:38:23 -05004231 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004232 u8 secmark_active;
4233 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004234
James Morris4e5ab4c2006-06-09 00:33:33 -07004235 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004236 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004237
4238 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004239 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004240 family = PF_INET;
4241
Paul Moored8395c82008-10-10 10:16:30 -04004242 /* If any sort of compatibility mode is enabled then handoff processing
4243 * to the selinux_sock_rcv_skb_compat() function to deal with the
4244 * special handling. We do this in an attempt to keep this function
4245 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004246 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004247 return selinux_sock_rcv_skb_compat(sk, skb, family);
4248
4249 secmark_active = selinux_secmark_enabled();
4250 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4251 if (!secmark_active && !peerlbl_active)
4252 return 0;
4253
Thomas Liu2bf49692009-07-14 12:14:09 -04004254 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004255 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004256 ad.u.net = &net;
4257 ad.u.net->netif = skb->skb_iif;
4258 ad.u.net->family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004259 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004260 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004261 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004262
Paul Moored8395c82008-10-10 10:16:30 -04004263 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004264 u32 peer_sid;
4265
4266 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4267 if (err)
4268 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004269 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004270 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004271 if (err) {
4272 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004273 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004274 }
Paul Moored621d352008-01-29 08:43:36 -05004275 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4276 PEER__RECV, &ad);
Chad Hanson351381d2013-12-23 17:45:01 -05004277 if (err) {
Paul Mooredfaebe92008-10-10 10:16:31 -04004278 selinux_netlbl_err(skb, err, 0);
Chad Hanson351381d2013-12-23 17:45:01 -05004279 return err;
4280 }
Paul Moored621d352008-01-29 08:43:36 -05004281 }
4282
Paul Moored8395c82008-10-10 10:16:30 -04004283 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004284 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4285 PACKET__RECV, &ad);
4286 if (err)
4287 return err;
4288 }
4289
Paul Moored621d352008-01-29 08:43:36 -05004290 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291}
4292
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004293static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4294 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295{
4296 int err = 0;
4297 char *scontext;
4298 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004299 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004300 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301
Paul Moore253bfae2010-04-22 14:46:19 -04004302 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4303 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004304 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004305 if (peer_sid == SECSID_NULL)
4306 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004308 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004310 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311
4312 if (scontext_len > len) {
4313 err = -ERANGE;
4314 goto out_len;
4315 }
4316
4317 if (copy_to_user(optval, scontext, scontext_len))
4318 err = -EFAULT;
4319
4320out_len:
4321 if (put_user(scontext_len, optlen))
4322 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 return err;
4325}
4326
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004327static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004328{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004329 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004330 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004331
Paul Mooreaa862902008-10-10 10:16:29 -04004332 if (skb && skb->protocol == htons(ETH_P_IP))
4333 family = PF_INET;
4334 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4335 family = PF_INET6;
4336 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004337 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004338 else
4339 goto out;
4340
4341 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004342 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004343 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004344 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004345
Paul Moore75e22912008-01-29 08:38:04 -05004346out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004347 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004348 if (peer_secid == SECSID_NULL)
4349 return -EINVAL;
4350 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004351}
4352
Al Viro7d877f32005-10-21 03:20:43 -04004353static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354{
Paul Moore84914b72010-04-22 14:46:18 -04004355 struct sk_security_struct *sksec;
4356
4357 sksec = kzalloc(sizeof(*sksec), priority);
4358 if (!sksec)
4359 return -ENOMEM;
4360
4361 sksec->peer_sid = SECINITSID_UNLABELED;
4362 sksec->sid = SECINITSID_UNLABELED;
4363 selinux_netlbl_sk_security_reset(sksec);
4364 sk->sk_security = sksec;
4365
4366 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367}
4368
4369static void selinux_sk_free_security(struct sock *sk)
4370{
Paul Moore84914b72010-04-22 14:46:18 -04004371 struct sk_security_struct *sksec = sk->sk_security;
4372
4373 sk->sk_security = NULL;
4374 selinux_netlbl_sk_security_free(sksec);
4375 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376}
4377
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004378static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4379{
Eric Parisdd3e7832010-04-07 15:08:46 -04004380 struct sk_security_struct *sksec = sk->sk_security;
4381 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004382
Eric Parisdd3e7832010-04-07 15:08:46 -04004383 newsksec->sid = sksec->sid;
4384 newsksec->peer_sid = sksec->peer_sid;
4385 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004386
Eric Parisdd3e7832010-04-07 15:08:46 -04004387 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004388}
4389
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004390static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004391{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004392 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004393 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004394 else {
4395 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004396
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004397 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004398 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004399}
4400
Eric Paris828dfe12008-04-17 13:17:49 -04004401static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004402{
4403 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4404 struct sk_security_struct *sksec = sk->sk_security;
4405
David Woodhouse2148ccc2006-09-29 15:50:25 -07004406 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4407 sk->sk_family == PF_UNIX)
4408 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004409 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004410}
4411
Adrian Bunk9a673e52006-08-15 00:03:53 -07004412static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4413 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004414{
4415 struct sk_security_struct *sksec = sk->sk_security;
4416 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004417 u16 family = sk->sk_family;
Paul Moore2ea04e52013-12-04 16:10:51 -05004418 u32 connsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004419 u32 peersid;
4420
Paul Mooreaa862902008-10-10 10:16:29 -04004421 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4422 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4423 family = PF_INET;
4424
4425 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004426 if (err)
4427 return err;
Paul Moore2ea04e52013-12-04 16:10:51 -05004428 err = selinux_conn_sid(sksec->sid, peersid, &connsid);
4429 if (err)
4430 return err;
4431 req->secid = connsid;
4432 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004433
Paul Moore389fb802009-03-27 17:10:34 -04004434 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004435}
4436
Adrian Bunk9a673e52006-08-15 00:03:53 -07004437static void selinux_inet_csk_clone(struct sock *newsk,
4438 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004439{
4440 struct sk_security_struct *newsksec = newsk->sk_security;
4441
4442 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004443 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004444 /* NOTE: Ideally, we should also get the isec->sid for the
4445 new socket in sync, but we don't have the isec available yet.
4446 So we will wait until sock_graft to do it, by which
4447 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004448
Paul Moore9f2ad662006-11-17 17:38:53 -05004449 /* We don't need to take any sort of lock here as we are the only
4450 * thread with access to newsksec */
Paul Moore389fb802009-03-27 17:10:34 -04004451 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004452}
4453
Paul Moore014ab192008-10-10 10:16:33 -04004454static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004455{
Paul Mooreaa862902008-10-10 10:16:29 -04004456 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004457 struct sk_security_struct *sksec = sk->sk_security;
4458
Paul Mooreaa862902008-10-10 10:16:29 -04004459 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4460 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4461 family = PF_INET;
4462
4463 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004464}
4465
Eric Paris2606fd12010-10-13 16:24:41 -04004466static int selinux_secmark_relabel_packet(u32 sid)
4467{
4468 const struct task_security_struct *__tsec;
4469 u32 tsid;
4470
4471 __tsec = current_security();
4472 tsid = __tsec->sid;
4473
4474 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4475}
4476
4477static void selinux_secmark_refcount_inc(void)
4478{
4479 atomic_inc(&selinux_secmark_refcount);
4480}
4481
4482static void selinux_secmark_refcount_dec(void)
4483{
4484 atomic_dec(&selinux_secmark_refcount);
4485}
4486
Adrian Bunk9a673e52006-08-15 00:03:53 -07004487static void selinux_req_classify_flow(const struct request_sock *req,
4488 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004489{
David S. Miller1d28f422011-03-12 00:29:39 -05004490 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004491}
4492
Paul Mooreed6d76e2009-08-28 18:12:49 -04004493static int selinux_tun_dev_create(void)
4494{
4495 u32 sid = current_sid();
4496
4497 /* we aren't taking into account the "sockcreate" SID since the socket
4498 * that is being created here is not a socket in the traditional sense,
4499 * instead it is a private sock, accessible only to the kernel, and
4500 * representing a wide range of network traffic spanning multiple
4501 * connections unlike traditional sockets - check the TUN driver to
4502 * get a better understanding of why this socket is special */
4503
4504 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4505 NULL);
4506}
4507
4508static void selinux_tun_dev_post_create(struct sock *sk)
4509{
4510 struct sk_security_struct *sksec = sk->sk_security;
4511
4512 /* we don't currently perform any NetLabel based labeling here and it
4513 * isn't clear that we would want to do so anyway; while we could apply
4514 * labeling without the support of the TUN user the resulting labeled
4515 * traffic from the other end of the connection would almost certainly
4516 * cause confusion to the TUN user that had no idea network labeling
4517 * protocols were being used */
4518
4519 /* see the comments in selinux_tun_dev_create() about why we don't use
4520 * the sockcreate SID here */
4521
4522 sksec->sid = current_sid();
4523 sksec->sclass = SECCLASS_TUN_SOCKET;
4524}
4525
4526static int selinux_tun_dev_attach(struct sock *sk)
4527{
4528 struct sk_security_struct *sksec = sk->sk_security;
4529 u32 sid = current_sid();
4530 int err;
4531
4532 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4533 TUN_SOCKET__RELABELFROM, NULL);
4534 if (err)
4535 return err;
4536 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4537 TUN_SOCKET__RELABELTO, NULL);
4538 if (err)
4539 return err;
4540
4541 sksec->sid = sid;
4542
4543 return 0;
4544}
4545
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4547{
4548 int err = 0;
4549 u32 perm;
4550 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004551 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004552
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 if (skb->len < NLMSG_SPACE(0)) {
4554 err = -EINVAL;
4555 goto out;
4556 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004557 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004558
Paul Moore253bfae2010-04-22 14:46:19 -04004559 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 if (err) {
4561 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004562 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 "SELinux: unrecognized netlink message"
4564 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004565 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004566 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 err = 0;
4568 }
4569
4570 /* Ignore */
4571 if (err == -ENOENT)
4572 err = 0;
4573 goto out;
4574 }
4575
Paul Moore253bfae2010-04-22 14:46:19 -04004576 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577out:
4578 return err;
4579}
4580
4581#ifdef CONFIG_NETFILTER
4582
Paul Mooreeffad8d2008-01-29 08:49:27 -05004583static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4584 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585{
Paul Mooredfaebe92008-10-10 10:16:31 -04004586 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004587 char *addrp;
4588 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004589 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004590 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004591 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004592 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004593 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004594 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004595
Paul Mooreeffad8d2008-01-29 08:49:27 -05004596 if (!selinux_policycap_netpeer)
4597 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004598
Paul Mooreeffad8d2008-01-29 08:49:27 -05004599 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004600 netlbl_active = netlbl_enabled();
4601 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004602 if (!secmark_active && !peerlbl_active)
4603 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004604
Paul Moored8395c82008-10-10 10:16:30 -04004605 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4606 return NF_DROP;
4607
Thomas Liu2bf49692009-07-14 12:14:09 -04004608 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004609 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004610 ad.u.net = &net;
4611 ad.u.net->netif = ifindex;
4612 ad.u.net->family = family;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004613 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4614 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
Paul Mooredfaebe92008-10-10 10:16:31 -04004616 if (peerlbl_active) {
4617 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4618 peer_sid, &ad);
4619 if (err) {
4620 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004621 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004622 }
4623 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004624
4625 if (secmark_active)
4626 if (avc_has_perm(peer_sid, skb->secmark,
4627 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4628 return NF_DROP;
4629
Paul Moore948bf852008-10-10 10:16:32 -04004630 if (netlbl_active)
4631 /* we do this in the FORWARD path and not the POST_ROUTING
4632 * path because we want to make sure we apply the necessary
4633 * labeling before IPsec is applied so we can leverage AH
4634 * protection */
4635 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4636 return NF_DROP;
4637
Paul Mooreeffad8d2008-01-29 08:49:27 -05004638 return NF_ACCEPT;
4639}
4640
4641static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4642 struct sk_buff *skb,
4643 const struct net_device *in,
4644 const struct net_device *out,
4645 int (*okfn)(struct sk_buff *))
4646{
4647 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4648}
4649
4650#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4651static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4652 struct sk_buff *skb,
4653 const struct net_device *in,
4654 const struct net_device *out,
4655 int (*okfn)(struct sk_buff *))
4656{
4657 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4658}
4659#endif /* IPV6 */
4660
Paul Moore948bf852008-10-10 10:16:32 -04004661static unsigned int selinux_ip_output(struct sk_buff *skb,
4662 u16 family)
4663{
Paul Moore1c5d9d12013-12-04 16:10:45 -05004664 struct sock *sk;
Paul Moore948bf852008-10-10 10:16:32 -04004665 u32 sid;
4666
4667 if (!netlbl_enabled())
4668 return NF_ACCEPT;
4669
4670 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4671 * because we want to make sure we apply the necessary labeling
4672 * before IPsec is applied so we can leverage AH protection */
Paul Moore1c5d9d12013-12-04 16:10:45 -05004673 sk = skb->sk;
4674 if (sk) {
4675 struct sk_security_struct *sksec;
4676
4677 if (sk->sk_state == TCP_LISTEN)
4678 /* if the socket is the listening state then this
4679 * packet is a SYN-ACK packet which means it needs to
4680 * be labeled based on the connection/request_sock and
4681 * not the parent socket. unfortunately, we can't
4682 * lookup the request_sock yet as it isn't queued on
4683 * the parent socket until after the SYN-ACK is sent.
4684 * the "solution" is to simply pass the packet as-is
4685 * as any IP option based labeling should be copied
4686 * from the initial connection request (in the IP
4687 * layer). it is far from ideal, but until we get a
4688 * security label in the packet itself this is the
4689 * best we can do. */
4690 return NF_ACCEPT;
4691
4692 /* standard practice, label using the parent socket */
4693 sksec = sk->sk_security;
Paul Moore948bf852008-10-10 10:16:32 -04004694 sid = sksec->sid;
4695 } else
4696 sid = SECINITSID_KERNEL;
4697 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4698 return NF_DROP;
4699
4700 return NF_ACCEPT;
4701}
4702
4703static unsigned int selinux_ipv4_output(unsigned int hooknum,
4704 struct sk_buff *skb,
4705 const struct net_device *in,
4706 const struct net_device *out,
4707 int (*okfn)(struct sk_buff *))
4708{
4709 return selinux_ip_output(skb, PF_INET);
4710}
4711
Paul Mooreeffad8d2008-01-29 08:49:27 -05004712static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4713 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004714 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004715{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004717 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004718 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004719 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004720 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004721 char *addrp;
4722 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004723
Paul Mooreeffad8d2008-01-29 08:49:27 -05004724 if (sk == NULL)
4725 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004726 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004727
Thomas Liu2bf49692009-07-14 12:14:09 -04004728 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004729 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004730 ad.u.net = &net;
4731 ad.u.net->netif = ifindex;
4732 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004733 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4734 return NF_DROP;
4735
Paul Moore58bfbb52009-03-27 17:10:41 -04004736 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004737 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004738 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004739 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004740
Steffen Klassertb9679a72011-02-23 12:55:21 +01004741 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4742 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004743
Paul Mooreeffad8d2008-01-29 08:49:27 -05004744 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745}
4746
Paul Mooreeffad8d2008-01-29 08:49:27 -05004747static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4748 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004750 u32 secmark_perm;
4751 u32 peer_sid;
4752 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004753 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004754 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004755 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004756 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004757 u8 secmark_active;
4758 u8 peerlbl_active;
4759
Paul Mooreeffad8d2008-01-29 08:49:27 -05004760 /* If any sort of compatibility mode is enabled then handoff processing
4761 * to the selinux_ip_postroute_compat() function to deal with the
4762 * special handling. We do this in an attempt to keep this function
4763 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004764 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004765 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Moore420cc6d2013-12-10 14:58:01 -05004766
Paul Mooreeffad8d2008-01-29 08:49:27 -05004767 secmark_active = selinux_secmark_enabled();
4768 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4769 if (!secmark_active && !peerlbl_active)
4770 return NF_ACCEPT;
4771
Paul Mooreeffad8d2008-01-29 08:49:27 -05004772 sk = skb->sk;
Paul Moore420cc6d2013-12-10 14:58:01 -05004773
4774#ifdef CONFIG_XFRM
4775 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4776 * packet transformation so allow the packet to pass without any checks
4777 * since we'll have another chance to perform access control checks
4778 * when the packet is on it's final way out.
4779 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4780 * is NULL, in this case go ahead and apply access control.
4781 * is NULL, in this case go ahead and apply access control.
4782 * NOTE: if this is a local socket (skb->sk != NULL) that is in the
4783 * TCP listening state we cannot wait until the XFRM processing
4784 * is done as we will miss out on the SA label if we do;
4785 * unfortunately, this means more work, but it is only once per
4786 * connection. */
4787 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
4788 !(sk != NULL && sk->sk_state == TCP_LISTEN))
4789 return NF_ACCEPT;
4790#endif
4791
Paul Moored8395c82008-10-10 10:16:30 -04004792 if (sk == NULL) {
Paul Moore2ea04e52013-12-04 16:10:51 -05004793 /* Without an associated socket the packet is either coming
4794 * from the kernel or it is being forwarded; check the packet
4795 * to determine which and if the packet is being forwarded
4796 * query the packet directly to determine the security label. */
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004797 if (skb->skb_iif) {
4798 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004799 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004800 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004801 } else {
4802 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004803 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004804 }
Paul Moore2ea04e52013-12-04 16:10:51 -05004805 } else if (sk->sk_state == TCP_LISTEN) {
4806 /* Locally generated packet but the associated socket is in the
4807 * listening state which means this is a SYN-ACK packet. In
4808 * this particular case the correct security label is assigned
4809 * to the connection/request_sock but unfortunately we can't
4810 * query the request_sock as it isn't queued on the parent
4811 * socket until after the SYN-ACK packet is sent; the only
4812 * viable choice is to regenerate the label like we do in
4813 * selinux_inet_conn_request(). See also selinux_ip_output()
4814 * for similar problems. */
4815 u32 skb_sid;
4816 struct sk_security_struct *sksec = sk->sk_security;
4817 if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
4818 return NF_DROP;
Paul Moore420cc6d2013-12-10 14:58:01 -05004819 /* At this point, if the returned skb peerlbl is SECSID_NULL
4820 * and the packet has been through at least one XFRM
4821 * transformation then we must be dealing with the "final"
4822 * form of labeled IPsec packet; since we've already applied
4823 * all of our access controls on this packet we can safely
4824 * pass the packet. */
4825 if (skb_sid == SECSID_NULL) {
4826 switch (family) {
4827 case PF_INET:
4828 if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
4829 return NF_ACCEPT;
4830 break;
4831 case PF_INET6:
4832 if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
4833 return NF_ACCEPT;
4834 default:
4835 return NF_DROP_ERR(-ECONNREFUSED);
4836 }
4837 }
Paul Moore2ea04e52013-12-04 16:10:51 -05004838 if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
4839 return NF_DROP;
4840 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004841 } else {
Paul Moore2ea04e52013-12-04 16:10:51 -05004842 /* Locally generated packet, fetch the security label from the
4843 * associated socket. */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004844 struct sk_security_struct *sksec = sk->sk_security;
4845 peer_sid = sksec->sid;
4846 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004847 }
4848
Thomas Liu2bf49692009-07-14 12:14:09 -04004849 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004850 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004851 ad.u.net = &net;
4852 ad.u.net->netif = ifindex;
4853 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004854 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004855 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004856
Paul Mooreeffad8d2008-01-29 08:49:27 -05004857 if (secmark_active)
4858 if (avc_has_perm(peer_sid, skb->secmark,
4859 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004860 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004861
4862 if (peerlbl_active) {
4863 u32 if_sid;
4864 u32 node_sid;
4865
4866 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004867 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004868 if (avc_has_perm(peer_sid, if_sid,
4869 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004870 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004871
4872 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004873 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004874 if (avc_has_perm(peer_sid, node_sid,
4875 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004876 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004877 }
4878
4879 return NF_ACCEPT;
4880}
4881
4882static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4883 struct sk_buff *skb,
4884 const struct net_device *in,
4885 const struct net_device *out,
4886 int (*okfn)(struct sk_buff *))
4887{
4888 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889}
4890
4891#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004892static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4893 struct sk_buff *skb,
4894 const struct net_device *in,
4895 const struct net_device *out,
4896 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004898 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900#endif /* IPV6 */
4901
4902#endif /* CONFIG_NETFILTER */
4903
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4905{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 int err;
4907
Eric Paris200ac532009-02-12 15:01:04 -05004908 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 if (err)
4910 return err;
4911
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004912 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913}
4914
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915static int ipc_alloc_security(struct task_struct *task,
4916 struct kern_ipc_perm *perm,
4917 u16 sclass)
4918{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004920 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921
James Morris89d155e2005-10-30 14:59:21 -08004922 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 if (!isec)
4924 return -ENOMEM;
4925
David Howells275bb412008-11-14 10:39:19 +11004926 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004928 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 perm->security = isec;
4930
4931 return 0;
4932}
4933
4934static void ipc_free_security(struct kern_ipc_perm *perm)
4935{
4936 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 perm->security = NULL;
4938 kfree(isec);
4939}
4940
4941static int msg_msg_alloc_security(struct msg_msg *msg)
4942{
4943 struct msg_security_struct *msec;
4944
James Morris89d155e2005-10-30 14:59:21 -08004945 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 if (!msec)
4947 return -ENOMEM;
4948
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 msec->sid = SECINITSID_UNLABELED;
4950 msg->security = msec;
4951
4952 return 0;
4953}
4954
4955static void msg_msg_free_security(struct msg_msg *msg)
4956{
4957 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958
4959 msg->security = NULL;
4960 kfree(msec);
4961}
4962
4963static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004964 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004967 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004968 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004969 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 isec = ipc_perms->security;
4972
Thomas Liu2bf49692009-07-14 12:14:09 -04004973 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004974 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 ad.u.ipc_id = ipc_perms->key;
4976
David Howells275bb412008-11-14 10:39:19 +11004977 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978}
4979
4980static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4981{
4982 return msg_msg_alloc_security(msg);
4983}
4984
4985static void selinux_msg_msg_free_security(struct msg_msg *msg)
4986{
4987 msg_msg_free_security(msg);
4988}
4989
4990/* message queue security operations */
4991static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4992{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004994 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004995 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004996 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 int rc;
4998
4999 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
5000 if (rc)
5001 return rc;
5002
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 isec = msq->q_perm.security;
5004
Thomas Liu2bf49692009-07-14 12:14:09 -04005005 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005006 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005007 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
David Howells275bb412008-11-14 10:39:19 +11005009 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 MSGQ__CREATE, &ad);
5011 if (rc) {
5012 ipc_free_security(&msq->q_perm);
5013 return rc;
5014 }
5015 return 0;
5016}
5017
5018static void selinux_msg_queue_free_security(struct msg_queue *msq)
5019{
5020 ipc_free_security(&msq->q_perm);
5021}
5022
5023static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
5024{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005026 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005027 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005028 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 isec = msq->q_perm.security;
5031
Thomas Liu2bf49692009-07-14 12:14:09 -04005032 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005033 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 ad.u.ipc_id = msq->q_perm.key;
5035
David Howells275bb412008-11-14 10:39:19 +11005036 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 MSGQ__ASSOCIATE, &ad);
5038}
5039
5040static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
5041{
5042 int err;
5043 int perms;
5044
Eric Paris828dfe12008-04-17 13:17:49 -04005045 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 case IPC_INFO:
5047 case MSG_INFO:
5048 /* No specific object, just general system-wide information. */
5049 return task_has_system(current, SYSTEM__IPC_INFO);
5050 case IPC_STAT:
5051 case MSG_STAT:
5052 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
5053 break;
5054 case IPC_SET:
5055 perms = MSGQ__SETATTR;
5056 break;
5057 case IPC_RMID:
5058 perms = MSGQ__DESTROY;
5059 break;
5060 default:
5061 return 0;
5062 }
5063
Stephen Smalley6af963f2005-05-01 08:58:39 -07005064 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 return err;
5066}
5067
5068static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
5069{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 struct ipc_security_struct *isec;
5071 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005072 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005073 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005074 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 int rc;
5076
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 isec = msq->q_perm.security;
5078 msec = msg->security;
5079
5080 /*
5081 * First time through, need to assign label to the message
5082 */
5083 if (msec->sid == SECINITSID_UNLABELED) {
5084 /*
5085 * Compute new sid based on current process and
5086 * message queue this message will be stored in
5087 */
David Howells275bb412008-11-14 10:39:19 +11005088 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05005089 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 if (rc)
5091 return rc;
5092 }
5093
Thomas Liu2bf49692009-07-14 12:14:09 -04005094 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005095 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 ad.u.ipc_id = msq->q_perm.key;
5097
5098 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005099 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 MSGQ__WRITE, &ad);
5101 if (!rc)
5102 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005103 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5104 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 if (!rc)
5106 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005107 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5108 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
5110 return rc;
5111}
5112
5113static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5114 struct task_struct *target,
5115 long type, int mode)
5116{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 struct ipc_security_struct *isec;
5118 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005119 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005120 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005121 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 int rc;
5123
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 isec = msq->q_perm.security;
5125 msec = msg->security;
5126
Thomas Liu2bf49692009-07-14 12:14:09 -04005127 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005128 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005129 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130
David Howells275bb412008-11-14 10:39:19 +11005131 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 SECCLASS_MSGQ, MSGQ__READ, &ad);
5133 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005134 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 SECCLASS_MSG, MSG__RECEIVE, &ad);
5136 return rc;
5137}
5138
5139/* Shared Memory security operations */
5140static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5141{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005143 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005144 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005145 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 int rc;
5147
5148 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5149 if (rc)
5150 return rc;
5151
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 isec = shp->shm_perm.security;
5153
Thomas Liu2bf49692009-07-14 12:14:09 -04005154 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005155 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005156 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157
David Howells275bb412008-11-14 10:39:19 +11005158 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 SHM__CREATE, &ad);
5160 if (rc) {
5161 ipc_free_security(&shp->shm_perm);
5162 return rc;
5163 }
5164 return 0;
5165}
5166
5167static void selinux_shm_free_security(struct shmid_kernel *shp)
5168{
5169 ipc_free_security(&shp->shm_perm);
5170}
5171
5172static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5173{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005175 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005176 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005177 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 isec = shp->shm_perm.security;
5180
Thomas Liu2bf49692009-07-14 12:14:09 -04005181 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005182 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 ad.u.ipc_id = shp->shm_perm.key;
5184
David Howells275bb412008-11-14 10:39:19 +11005185 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 SHM__ASSOCIATE, &ad);
5187}
5188
5189/* Note, at this point, shp is locked down */
5190static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5191{
5192 int perms;
5193 int err;
5194
Eric Paris828dfe12008-04-17 13:17:49 -04005195 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 case IPC_INFO:
5197 case SHM_INFO:
5198 /* No specific object, just general system-wide information. */
5199 return task_has_system(current, SYSTEM__IPC_INFO);
5200 case IPC_STAT:
5201 case SHM_STAT:
5202 perms = SHM__GETATTR | SHM__ASSOCIATE;
5203 break;
5204 case IPC_SET:
5205 perms = SHM__SETATTR;
5206 break;
5207 case SHM_LOCK:
5208 case SHM_UNLOCK:
5209 perms = SHM__LOCK;
5210 break;
5211 case IPC_RMID:
5212 perms = SHM__DESTROY;
5213 break;
5214 default:
5215 return 0;
5216 }
5217
Stephen Smalley6af963f2005-05-01 08:58:39 -07005218 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 return err;
5220}
5221
5222static int selinux_shm_shmat(struct shmid_kernel *shp,
5223 char __user *shmaddr, int shmflg)
5224{
5225 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
5227 if (shmflg & SHM_RDONLY)
5228 perms = SHM__READ;
5229 else
5230 perms = SHM__READ | SHM__WRITE;
5231
Stephen Smalley6af963f2005-05-01 08:58:39 -07005232 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233}
5234
5235/* Semaphore security operations */
5236static int selinux_sem_alloc_security(struct sem_array *sma)
5237{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005239 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005240 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005241 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 int rc;
5243
5244 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5245 if (rc)
5246 return rc;
5247
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 isec = sma->sem_perm.security;
5249
Thomas Liu2bf49692009-07-14 12:14:09 -04005250 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005251 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005252 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253
David Howells275bb412008-11-14 10:39:19 +11005254 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 SEM__CREATE, &ad);
5256 if (rc) {
5257 ipc_free_security(&sma->sem_perm);
5258 return rc;
5259 }
5260 return 0;
5261}
5262
5263static void selinux_sem_free_security(struct sem_array *sma)
5264{
5265 ipc_free_security(&sma->sem_perm);
5266}
5267
5268static int selinux_sem_associate(struct sem_array *sma, int semflg)
5269{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005271 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005272 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005273 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 isec = sma->sem_perm.security;
5276
Thomas Liu2bf49692009-07-14 12:14:09 -04005277 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005278 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 ad.u.ipc_id = sma->sem_perm.key;
5280
David Howells275bb412008-11-14 10:39:19 +11005281 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 SEM__ASSOCIATE, &ad);
5283}
5284
5285/* Note, at this point, sma is locked down */
5286static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5287{
5288 int err;
5289 u32 perms;
5290
Eric Paris828dfe12008-04-17 13:17:49 -04005291 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 case IPC_INFO:
5293 case SEM_INFO:
5294 /* No specific object, just general system-wide information. */
5295 return task_has_system(current, SYSTEM__IPC_INFO);
5296 case GETPID:
5297 case GETNCNT:
5298 case GETZCNT:
5299 perms = SEM__GETATTR;
5300 break;
5301 case GETVAL:
5302 case GETALL:
5303 perms = SEM__READ;
5304 break;
5305 case SETVAL:
5306 case SETALL:
5307 perms = SEM__WRITE;
5308 break;
5309 case IPC_RMID:
5310 perms = SEM__DESTROY;
5311 break;
5312 case IPC_SET:
5313 perms = SEM__SETATTR;
5314 break;
5315 case IPC_STAT:
5316 case SEM_STAT:
5317 perms = SEM__GETATTR | SEM__ASSOCIATE;
5318 break;
5319 default:
5320 return 0;
5321 }
5322
Stephen Smalley6af963f2005-05-01 08:58:39 -07005323 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 return err;
5325}
5326
5327static int selinux_sem_semop(struct sem_array *sma,
5328 struct sembuf *sops, unsigned nsops, int alter)
5329{
5330 u32 perms;
5331
5332 if (alter)
5333 perms = SEM__READ | SEM__WRITE;
5334 else
5335 perms = SEM__READ;
5336
Stephen Smalley6af963f2005-05-01 08:58:39 -07005337 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338}
5339
5340static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5341{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 u32 av = 0;
5343
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 av = 0;
5345 if (flag & S_IRUGO)
5346 av |= IPC__UNIX_READ;
5347 if (flag & S_IWUGO)
5348 av |= IPC__UNIX_WRITE;
5349
5350 if (av == 0)
5351 return 0;
5352
Stephen Smalley6af963f2005-05-01 08:58:39 -07005353 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354}
5355
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005356static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5357{
5358 struct ipc_security_struct *isec = ipcp->security;
5359 *secid = isec->sid;
5360}
5361
Eric Paris828dfe12008-04-17 13:17:49 -04005362static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363{
5364 if (inode)
5365 inode_doinit_with_dentry(inode, dentry);
5366}
5367
5368static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005369 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370{
David Howells275bb412008-11-14 10:39:19 +11005371 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005372 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005374 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375
5376 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005377 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 if (error)
5379 return error;
5380 }
5381
David Howells275bb412008-11-14 10:39:19 +11005382 rcu_read_lock();
5383 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384
5385 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005386 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005388 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005390 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005392 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005393 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005394 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005395 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005396 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 else
David Howells275bb412008-11-14 10:39:19 +11005398 goto invalid;
5399 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
5401 if (!sid)
5402 return 0;
5403
Al Viro04ff9702007-03-12 16:17:58 +00005404 error = security_sid_to_context(sid, value, &len);
5405 if (error)
5406 return error;
5407 return len;
David Howells275bb412008-11-14 10:39:19 +11005408
5409invalid:
5410 rcu_read_unlock();
5411 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412}
5413
5414static int selinux_setprocattr(struct task_struct *p,
5415 char *name, void *value, size_t size)
5416{
5417 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005418 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005419 struct cred *new;
5420 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 int error;
5422 char *str = value;
5423
5424 if (current != p) {
5425 /* SELinux only allows a process to change its own
5426 security attributes. */
5427 return -EACCES;
5428 }
5429
5430 /*
5431 * Basic control over ability to set these attributes at all.
5432 * current == p, but we'll pass them separately in case the
5433 * above restriction is ever removed.
5434 */
5435 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005436 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005438 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005439 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005440 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005441 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005442 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005444 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 else
5446 error = -EINVAL;
5447 if (error)
5448 return error;
5449
5450 /* Obtain a SID for the context, if one was specified. */
5451 if (size && str[1] && str[1] != '\n') {
5452 if (str[size-1] == '\n') {
5453 str[size-1] = 0;
5454 size--;
5455 }
5456 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005457 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5458 if (!capable(CAP_MAC_ADMIN))
5459 return error;
5460 error = security_context_to_sid_force(value, size,
5461 &sid);
5462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 if (error)
5464 return error;
5465 }
5466
David Howellsd84f4f92008-11-14 10:39:23 +11005467 new = prepare_creds();
5468 if (!new)
5469 return -ENOMEM;
5470
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 /* Permission checking based on the specified context is
5472 performed during the actual operation (execve,
5473 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005474 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 checks and may_create for the file creation checks. The
5476 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005477 tsec = new->security;
5478 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005480 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005482 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005483 error = may_create_key(sid, p);
5484 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005485 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005486 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005487 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005488 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005489 } else if (!strcmp(name, "current")) {
5490 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005492 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005493
David Howellsd84f4f92008-11-14 10:39:23 +11005494 /* Only allow single threaded processes to change context */
5495 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005496 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005497 error = security_bounded_transition(tsec->sid, sid);
5498 if (error)
5499 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501
5502 /* Check permissions for the transition. */
5503 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005504 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005506 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
5508 /* Check for ptracing, and update the task SID if ok.
5509 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005510 ptsid = 0;
Oleg Nesterov58c23142013-12-23 17:45:01 -05005511 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02005512 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005513 if (tracer)
5514 ptsid = task_sid(tracer);
Oleg Nesterov58c23142013-12-23 17:45:01 -05005515 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
David Howellsd84f4f92008-11-14 10:39:23 +11005517 if (tracer) {
5518 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5519 PROCESS__PTRACE, NULL);
5520 if (error)
5521 goto abort_change;
5522 }
5523
5524 tsec->sid = sid;
5525 } else {
5526 error = -EINVAL;
5527 goto abort_change;
5528 }
5529
5530 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005532
5533abort_change:
5534 abort_creds(new);
5535 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536}
5537
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005538static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5539{
5540 return security_sid_to_context(secid, secdata, seclen);
5541}
5542
David Howells7bf570d2008-04-29 20:52:51 +01005543static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005544{
5545 return security_context_to_sid(secdata, seclen, secid);
5546}
5547
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005548static void selinux_release_secctx(char *secdata, u32 seclen)
5549{
Paul Moore088999e2007-08-01 11:12:58 -04005550 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005551}
5552
David P. Quigley1ee65e32009-09-03 14:25:57 -04005553/*
5554 * called with inode->i_mutex locked
5555 */
5556static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5557{
5558 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5559}
5560
5561/*
5562 * called with inode->i_mutex locked
5563 */
5564static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5565{
5566 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5567}
5568
5569static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5570{
5571 int len = 0;
5572 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5573 ctx, true);
5574 if (len < 0)
5575 return len;
5576 *ctxlen = len;
5577 return 0;
5578}
Michael LeMayd7200242006-06-22 14:47:17 -07005579#ifdef CONFIG_KEYS
5580
David Howellsd84f4f92008-11-14 10:39:23 +11005581static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005582 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005583{
David Howellsd84f4f92008-11-14 10:39:23 +11005584 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005585 struct key_security_struct *ksec;
5586
5587 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5588 if (!ksec)
5589 return -ENOMEM;
5590
David Howellsd84f4f92008-11-14 10:39:23 +11005591 tsec = cred->security;
5592 if (tsec->keycreate_sid)
5593 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005594 else
David Howellsd84f4f92008-11-14 10:39:23 +11005595 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005596
David Howells275bb412008-11-14 10:39:19 +11005597 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005598 return 0;
5599}
5600
5601static void selinux_key_free(struct key *k)
5602{
5603 struct key_security_struct *ksec = k->security;
5604
5605 k->security = NULL;
5606 kfree(ksec);
5607}
5608
5609static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005610 const struct cred *cred,
5611 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005612{
5613 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005614 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005615 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005616
5617 /* if no specific permissions are requested, we skip the
5618 permission check. No serious, additional covert channels
5619 appear to be created. */
5620 if (perm == 0)
5621 return 0;
5622
David Howellsd84f4f92008-11-14 10:39:23 +11005623 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005624
5625 key = key_ref_to_ptr(key_ref);
5626 ksec = key->security;
5627
5628 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005629}
5630
David Howells70a5bb72008-04-29 01:01:26 -07005631static int selinux_key_getsecurity(struct key *key, char **_buffer)
5632{
5633 struct key_security_struct *ksec = key->security;
5634 char *context = NULL;
5635 unsigned len;
5636 int rc;
5637
5638 rc = security_sid_to_context(ksec->sid, &context, &len);
5639 if (!rc)
5640 rc = len;
5641 *_buffer = context;
5642 return rc;
5643}
5644
Michael LeMayd7200242006-06-22 14:47:17 -07005645#endif
5646
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005648 .name = "selinux",
5649
Ingo Molnar9e488582009-05-07 19:26:19 +10005650 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005651 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005653 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 .capable = selinux_capable,
5655 .quotactl = selinux_quotactl,
5656 .quota_on = selinux_quota_on,
5657 .syslog = selinux_syslog,
5658 .vm_enough_memory = selinux_vm_enough_memory,
5659
5660 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
David Howellsa6f76f22008-11-14 10:39:24 +11005662 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005663 .bprm_committing_creds = selinux_bprm_committing_creds,
5664 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 .bprm_secureexec = selinux_bprm_secureexec,
5666
5667 .sb_alloc_security = selinux_sb_alloc_security,
5668 .sb_free_security = selinux_sb_free_security,
5669 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005670 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005671 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005672 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 .sb_statfs = selinux_sb_statfs,
5674 .sb_mount = selinux_mount,
5675 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005676 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005677 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005678 .sb_parse_opts_str = selinux_parse_opts_str,
5679
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680
5681 .inode_alloc_security = selinux_inode_alloc_security,
5682 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005683 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 .inode_unlink = selinux_inode_unlink,
5687 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 .inode_rmdir = selinux_inode_rmdir,
5690 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 .inode_readlink = selinux_inode_readlink,
5693 .inode_follow_link = selinux_inode_follow_link,
5694 .inode_permission = selinux_inode_permission,
5695 .inode_setattr = selinux_inode_setattr,
5696 .inode_getattr = selinux_inode_getattr,
5697 .inode_setxattr = selinux_inode_setxattr,
5698 .inode_post_setxattr = selinux_inode_post_setxattr,
5699 .inode_getxattr = selinux_inode_getxattr,
5700 .inode_listxattr = selinux_inode_listxattr,
5701 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005702 .inode_getsecurity = selinux_inode_getsecurity,
5703 .inode_setsecurity = selinux_inode_setsecurity,
5704 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005705 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706
5707 .file_permission = selinux_file_permission,
5708 .file_alloc_security = selinux_file_alloc_security,
5709 .file_free_security = selinux_file_free_security,
5710 .file_ioctl = selinux_file_ioctl,
5711 .file_mmap = selinux_file_mmap,
5712 .file_mprotect = selinux_file_mprotect,
5713 .file_lock = selinux_file_lock,
5714 .file_fcntl = selinux_file_fcntl,
5715 .file_set_fowner = selinux_file_set_fowner,
5716 .file_send_sigiotask = selinux_file_send_sigiotask,
5717 .file_receive = selinux_file_receive,
5718
Eric Paris828dfe12008-04-17 13:17:49 -04005719 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005720
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005722 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005723 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005724 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005725 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005726 .kernel_act_as = selinux_kernel_act_as,
5727 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005728 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 .task_setpgid = selinux_task_setpgid,
5730 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005731 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005732 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005734 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005735 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 .task_setrlimit = selinux_task_setrlimit,
5737 .task_setscheduler = selinux_task_setscheduler,
5738 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005739 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 .task_kill = selinux_task_kill,
5741 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005742 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743
5744 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005745 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746
5747 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5748 .msg_msg_free_security = selinux_msg_msg_free_security,
5749
5750 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5751 .msg_queue_free_security = selinux_msg_queue_free_security,
5752 .msg_queue_associate = selinux_msg_queue_associate,
5753 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5754 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5755 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5756
5757 .shm_alloc_security = selinux_shm_alloc_security,
5758 .shm_free_security = selinux_shm_free_security,
5759 .shm_associate = selinux_shm_associate,
5760 .shm_shmctl = selinux_shm_shmctl,
5761 .shm_shmat = selinux_shm_shmat,
5762
Eric Paris828dfe12008-04-17 13:17:49 -04005763 .sem_alloc_security = selinux_sem_alloc_security,
5764 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 .sem_associate = selinux_sem_associate,
5766 .sem_semctl = selinux_sem_semctl,
5767 .sem_semop = selinux_sem_semop,
5768
Eric Paris828dfe12008-04-17 13:17:49 -04005769 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
Eric Paris828dfe12008-04-17 13:17:49 -04005771 .getprocattr = selinux_getprocattr,
5772 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005774 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005775 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005776 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005777 .inode_notifysecctx = selinux_inode_notifysecctx,
5778 .inode_setsecctx = selinux_inode_setsecctx,
5779 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005780
Eric Paris828dfe12008-04-17 13:17:49 -04005781 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 .unix_may_send = selinux_socket_unix_may_send,
5783
5784 .socket_create = selinux_socket_create,
5785 .socket_post_create = selinux_socket_post_create,
5786 .socket_bind = selinux_socket_bind,
5787 .socket_connect = selinux_socket_connect,
5788 .socket_listen = selinux_socket_listen,
5789 .socket_accept = selinux_socket_accept,
5790 .socket_sendmsg = selinux_socket_sendmsg,
5791 .socket_recvmsg = selinux_socket_recvmsg,
5792 .socket_getsockname = selinux_socket_getsockname,
5793 .socket_getpeername = selinux_socket_getpeername,
5794 .socket_getsockopt = selinux_socket_getsockopt,
5795 .socket_setsockopt = selinux_socket_setsockopt,
5796 .socket_shutdown = selinux_socket_shutdown,
5797 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005798 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5799 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 .sk_alloc_security = selinux_sk_alloc_security,
5801 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005802 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005803 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005804 .sock_graft = selinux_sock_graft,
5805 .inet_conn_request = selinux_inet_conn_request,
5806 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005807 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005808 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5809 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5810 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005811 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005812 .tun_dev_create = selinux_tun_dev_create,
5813 .tun_dev_post_create = selinux_tun_dev_post_create,
5814 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005815
5816#ifdef CONFIG_SECURITY_NETWORK_XFRM
5817 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5818 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5819 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005820 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005821 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5822 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005823 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005824 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005825 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005826 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005828
5829#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005830 .key_alloc = selinux_key_alloc,
5831 .key_free = selinux_key_free,
5832 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005833 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005834#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005835
5836#ifdef CONFIG_AUDIT
5837 .audit_rule_init = selinux_audit_rule_init,
5838 .audit_rule_known = selinux_audit_rule_known,
5839 .audit_rule_match = selinux_audit_rule_match,
5840 .audit_rule_free = selinux_audit_rule_free,
5841#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842};
5843
5844static __init int selinux_init(void)
5845{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005846 if (!security_module_enable(&selinux_ops)) {
5847 selinux_enabled = 0;
5848 return 0;
5849 }
5850
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 if (!selinux_enabled) {
5852 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5853 return 0;
5854 }
5855
5856 printk(KERN_INFO "SELinux: Initializing.\n");
5857
5858 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005859 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005861 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5862
James Morris7cae7e22006-03-22 00:09:22 -08005863 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5864 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005865 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 avc_init();
5867
Eric Paris828dfe12008-04-17 13:17:49 -04005868 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 panic("SELinux: Unable to register with kernel.\n");
5870
Eric Paris828dfe12008-04-17 13:17:49 -04005871 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005872 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005873 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005874 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005875
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 return 0;
5877}
5878
Al Viroe8c26252010-03-23 06:36:54 -04005879static void delayed_superblock_init(struct super_block *sb, void *unused)
5880{
5881 superblock_doinit(sb, NULL);
5882}
5883
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884void selinux_complete_init(void)
5885{
Eric Parisfadcdb42007-02-22 18:11:31 -05005886 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887
5888 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005889 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005890 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891}
5892
5893/* SELinux requires early initialization in order to label
5894 all processes and objects when they are created. */
5895security_initcall(selinux_init);
5896
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005897#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898
Paul Mooreeffad8d2008-01-29 08:49:27 -05005899static struct nf_hook_ops selinux_ipv4_ops[] = {
5900 {
5901 .hook = selinux_ipv4_postroute,
5902 .owner = THIS_MODULE,
5903 .pf = PF_INET,
5904 .hooknum = NF_INET_POST_ROUTING,
5905 .priority = NF_IP_PRI_SELINUX_LAST,
5906 },
5907 {
5908 .hook = selinux_ipv4_forward,
5909 .owner = THIS_MODULE,
5910 .pf = PF_INET,
5911 .hooknum = NF_INET_FORWARD,
5912 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005913 },
5914 {
5915 .hook = selinux_ipv4_output,
5916 .owner = THIS_MODULE,
5917 .pf = PF_INET,
5918 .hooknum = NF_INET_LOCAL_OUT,
5919 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921};
5922
5923#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5924
Paul Mooreeffad8d2008-01-29 08:49:27 -05005925static struct nf_hook_ops selinux_ipv6_ops[] = {
5926 {
5927 .hook = selinux_ipv6_postroute,
5928 .owner = THIS_MODULE,
5929 .pf = PF_INET6,
5930 .hooknum = NF_INET_POST_ROUTING,
5931 .priority = NF_IP6_PRI_SELINUX_LAST,
5932 },
5933 {
5934 .hook = selinux_ipv6_forward,
5935 .owner = THIS_MODULE,
5936 .pf = PF_INET6,
5937 .hooknum = NF_INET_FORWARD,
5938 .priority = NF_IP6_PRI_SELINUX_FIRST,
5939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940};
5941
5942#endif /* IPV6 */
5943
5944static int __init selinux_nf_ip_init(void)
5945{
5946 int err = 0;
5947
5948 if (!selinux_enabled)
5949 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005950
5951 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5952
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005953 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5954 if (err)
5955 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
5957#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005958 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5959 if (err)
5960 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005962
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963out:
5964 return err;
5965}
5966
5967__initcall(selinux_nf_ip_init);
5968
5969#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5970static void selinux_nf_ip_exit(void)
5971{
Eric Parisfadcdb42007-02-22 18:11:31 -05005972 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005974 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005976 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977#endif /* IPV6 */
5978}
5979#endif
5980
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005981#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982
5983#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5984#define selinux_nf_ip_exit()
5985#endif
5986
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005987#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988
5989#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005990static int selinux_disabled;
5991
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992int selinux_disable(void)
5993{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 if (ss_initialized) {
5995 /* Not permitted after initial policy load. */
5996 return -EINVAL;
5997 }
5998
5999 if (selinux_disabled) {
6000 /* Only do this once. */
6001 return -EINVAL;
6002 }
6003
6004 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
6005
6006 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04006007 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08006009 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
Eric Parisaf8ff042009-09-20 21:23:01 -04006011 /* Try to destroy the avc node cache */
6012 avc_disable();
6013
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 /* Unregister netfilter hooks. */
6015 selinux_nf_ip_exit();
6016
6017 /* Unregister selinuxfs. */
6018 exit_sel_fs();
6019
6020 return 0;
6021}
6022#endif