blob: 4a176b4687192df1360df8b006071c06990f1ebe [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>
Eric Paris0b24dcb2011-02-25 15:39:20 -050031#include <linux/ext2_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/sched.h>
33#include <linux/security.h>
34#include <linux/xattr.h>
35#include <linux/capability.h>
36#include <linux/unistd.h>
37#include <linux/mm.h>
38#include <linux/mman.h>
39#include <linux/slab.h>
40#include <linux/pagemap.h>
Eric Paris0b24dcb2011-02-25 15:39:20 -050041#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/swap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/spinlock.h>
44#include <linux/syscalls.h>
Eric Paris2a7dba32011-02-01 11:05:39 -050045#include <linux/dcache.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/file.h>
Al Viro9f3acc32008-04-24 07:44:08 -040047#include <linux/fdtable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/namei.h>
49#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/netfilter_ipv4.h>
51#include <linux/netfilter_ipv6.h>
52#include <linux/tty.h>
53#include <net/icmp.h>
Stephen Hemminger227b60f2007-10-10 17:30:46 -070054#include <net/ip.h> /* for local_port_range[] */
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
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 Sharma600634972011-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. Hallyn3486740a2011-03-23 16:43:17 -070082#include <linux/user_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84#include "avc.h"
85#include "objsec.h"
86#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050087#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040088#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080089#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050090#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020091#include "audit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
David P. Quigley11689d42009-01-16 09:22:03 -050093#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050094
Linus Torvalds1da177e2005-04-16 15:20:36 -070095extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
James Morris20510f22007-10-16 23:31:32 -070096extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Paul Moored621d352008-01-29 08:43:36 -050098/* SECMARK reference count */
James Morris56a4ca92011-08-17 11:08:43 +100099static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
Paul Moored621d352008-01-29 08:43:36 -0500100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400102int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104static int __init enforcing_setup(char *str)
105{
Eric Parisf5269712008-05-14 11:27:45 -0400106 unsigned long enforcing;
107 if (!strict_strtoul(str, 0, &enforcing))
108 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 return 1;
110}
111__setup("enforcing=", enforcing_setup);
112#endif
113
114#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
115int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
116
117static int __init selinux_enabled_setup(char *str)
118{
Eric Parisf5269712008-05-14 11:27:45 -0400119 unsigned long enabled;
120 if (!strict_strtoul(str, 0, &enabled))
121 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 return 1;
123}
124__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400125#else
126int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127#endif
128
Christoph Lametere18b8902006-12-06 20:33:20 -0800129static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800130
Paul Moored621d352008-01-29 08:43:36 -0500131/**
132 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
133 *
134 * Description:
135 * This function checks the SECMARK reference counter to see if any SECMARK
136 * targets are currently configured, if the reference counter is greater than
137 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
138 * enabled, false (0) if SECMARK is disabled.
139 *
140 */
141static int selinux_secmark_enabled(void)
142{
143 return (atomic_read(&selinux_secmark_refcount) > 0);
144}
145
David Howellsd84f4f92008-11-14 10:39:23 +1100146/*
147 * initialise the security for the init task
148 */
149static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
David Howells3b11a1d2008-11-14 10:39:26 +1100151 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 struct task_security_struct *tsec;
153
James Morris89d155e2005-10-30 14:59:21 -0800154 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100156 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
David Howellsd84f4f92008-11-14 10:39:23 +1100158 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100159 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160}
161
David Howells275bb412008-11-14 10:39:19 +1100162/*
David Howells88e67f32008-11-14 10:39:21 +1100163 * get the security ID of a set of credentials
164 */
165static inline u32 cred_sid(const struct cred *cred)
166{
167 const struct task_security_struct *tsec;
168
169 tsec = cred->security;
170 return tsec->sid;
171}
172
173/*
David Howells3b11a1d2008-11-14 10:39:26 +1100174 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100175 */
176static inline u32 task_sid(const struct task_struct *task)
177{
David Howells275bb412008-11-14 10:39:19 +1100178 u32 sid;
179
180 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100181 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100182 rcu_read_unlock();
183 return sid;
184}
185
186/*
David Howells3b11a1d2008-11-14 10:39:26 +1100187 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100188 */
189static inline u32 current_sid(void)
190{
Paul Moore5fb49872010-04-22 14:46:19 -0400191 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +1100192
193 return tsec->sid;
194}
195
David Howells88e67f32008-11-14 10:39:21 +1100196/* Allocate and free functions for each kind of security blob. */
197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int inode_alloc_security(struct inode *inode)
199{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100201 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Josef Bacika02fe132008-04-04 09:35:05 +1100203 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 if (!isec)
205 return -ENOMEM;
206
Eric Paris23970742006-09-25 23:32:01 -0700207 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 isec->inode = inode;
210 isec->sid = SECINITSID_UNLABELED;
211 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100212 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 inode->i_security = isec;
214
215 return 0;
216}
217
218static void inode_free_security(struct inode *inode)
219{
220 struct inode_security_struct *isec = inode->i_security;
221 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 spin_lock(&sbsec->isec_lock);
224 if (!list_empty(&isec->list))
225 list_del_init(&isec->list);
226 spin_unlock(&sbsec->isec_lock);
227
228 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800229 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
231
232static int file_alloc_security(struct file *file)
233{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100235 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800237 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 if (!fsec)
239 return -ENOMEM;
240
David Howells275bb412008-11-14 10:39:19 +1100241 fsec->sid = sid;
242 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 file->f_security = fsec;
244
245 return 0;
246}
247
248static void file_free_security(struct file *file)
249{
250 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 file->f_security = NULL;
252 kfree(fsec);
253}
254
255static int superblock_alloc_security(struct super_block *sb)
256{
257 struct superblock_security_struct *sbsec;
258
James Morris89d155e2005-10-30 14:59:21 -0800259 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 if (!sbsec)
261 return -ENOMEM;
262
Eric Parisbc7e9822006-09-25 23:32:02 -0700263 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 INIT_LIST_HEAD(&sbsec->isec_head);
265 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 sbsec->sb = sb;
267 sbsec->sid = SECINITSID_UNLABELED;
268 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700269 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sb->s_security = sbsec;
271
272 return 0;
273}
274
275static void superblock_free_security(struct super_block *sb)
276{
277 struct superblock_security_struct *sbsec = sb->s_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 sb->s_security = NULL;
279 kfree(sbsec);
280}
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282/* The security server must be initialized before
283 any labeling or access decisions can be provided. */
284extern int ss_initialized;
285
286/* The file system's label must be initialized prior to use. */
287
Stephen Hemminger634a5392010-03-04 21:59:03 -0800288static const char *labeling_behaviors[6] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 "uses xattr",
290 "uses transition SIDs",
291 "uses task SIDs",
292 "uses genfs_contexts",
293 "not configured for labeling",
294 "uses mountpoint labeling",
295};
296
297static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
298
299static inline int inode_doinit(struct inode *inode)
300{
301 return inode_doinit_with_dentry(inode, NULL);
302}
303
304enum {
Eric Paris31e87932007-09-19 17:19:12 -0400305 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 Opt_context = 1,
307 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500308 Opt_defcontext = 3,
309 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500310 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311};
312
Steven Whitehousea447c092008-10-13 10:46:57 +0100313static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400314 {Opt_context, CONTEXT_STR "%s"},
315 {Opt_fscontext, FSCONTEXT_STR "%s"},
316 {Opt_defcontext, DEFCONTEXT_STR "%s"},
317 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500318 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400319 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320};
321
322#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
323
Eric Parisc312feb2006-07-10 04:43:53 -0700324static int may_context_mount_sb_relabel(u32 sid,
325 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100326 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700327{
David Howells275bb412008-11-14 10:39:19 +1100328 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700329 int rc;
330
331 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
332 FILESYSTEM__RELABELFROM, NULL);
333 if (rc)
334 return rc;
335
336 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
337 FILESYSTEM__RELABELTO, NULL);
338 return rc;
339}
340
Eric Paris08089252006-07-10 04:43:55 -0700341static int may_context_mount_inode_relabel(u32 sid,
342 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100343 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700344{
David Howells275bb412008-11-14 10:39:19 +1100345 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700346 int rc;
347 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
348 FILESYSTEM__RELABELFROM, NULL);
349 if (rc)
350 return rc;
351
352 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
353 FILESYSTEM__ASSOCIATE, NULL);
354 return rc;
355}
356
Eric Parisc9180a52007-11-30 13:00:35 -0500357static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
359 struct superblock_security_struct *sbsec = sb->s_security;
360 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500361 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 int rc = 0;
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
365 /* Make sure that the xattr handler exists and that no
366 error other than -ENODATA is returned by getxattr on
367 the root directory. -ENODATA is ok, as this may be
368 the first boot of the SELinux kernel before we have
369 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500370 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
372 "xattr support\n", sb->s_id, sb->s_type->name);
373 rc = -EOPNOTSUPP;
374 goto out;
375 }
Eric Parisc9180a52007-11-30 13:00:35 -0500376 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 if (rc < 0 && rc != -ENODATA) {
378 if (rc == -EOPNOTSUPP)
379 printk(KERN_WARNING "SELinux: (dev %s, type "
380 "%s) has no security xattr handler\n",
381 sb->s_id, sb->s_type->name);
382 else
383 printk(KERN_WARNING "SELinux: (dev %s, type "
384 "%s) getxattr errno %d\n", sb->s_id,
385 sb->s_type->name, -rc);
386 goto out;
387 }
388 }
389
David P. Quigley11689d42009-01-16 09:22:03 -0500390 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Eric Parisc9180a52007-11-30 13:00:35 -0500392 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500393 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500395 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500396 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 sb->s_id, sb->s_type->name,
398 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
David P. Quigley11689d42009-01-16 09:22:03 -0500400 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
401 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
402 sbsec->behavior == SECURITY_FS_USE_NONE ||
403 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
404 sbsec->flags &= ~SE_SBLABELSUPP;
405
David P. Quigleyddd29ec2009-09-09 14:25:37 -0400406 /* Special handling for sysfs. Is genfs but also has setxattr handler*/
407 if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
408 sbsec->flags |= SE_SBLABELSUPP;
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500411 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
413 /* Initialize any other inodes associated with the superblock, e.g.
414 inodes created prior to initial policy load or inodes created
415 during get_sb by a pseudo filesystem that directly
416 populates itself. */
417 spin_lock(&sbsec->isec_lock);
418next_inode:
419 if (!list_empty(&sbsec->isec_head)) {
420 struct inode_security_struct *isec =
421 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500422 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 struct inode *inode = isec->inode;
424 spin_unlock(&sbsec->isec_lock);
425 inode = igrab(inode);
426 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500427 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 inode_doinit(inode);
429 iput(inode);
430 }
431 spin_lock(&sbsec->isec_lock);
432 list_del_init(&isec->list);
433 goto next_inode;
434 }
435 spin_unlock(&sbsec->isec_lock);
436out:
Eric Parisc9180a52007-11-30 13:00:35 -0500437 return rc;
438}
439
440/*
441 * This function should allow an FS to ask what it's mount security
442 * options were so it can use those later for submounts, displaying
443 * mount options, or whatever.
444 */
445static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500446 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500447{
448 int rc = 0, i;
449 struct superblock_security_struct *sbsec = sb->s_security;
450 char *context = NULL;
451 u32 len;
452 char tmp;
453
Eric Parise0007522008-03-05 10:31:54 -0500454 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500455
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500456 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500457 return -EINVAL;
458
459 if (!ss_initialized)
460 return -EINVAL;
461
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500462 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500463 /* count the number of mount options for this sb */
464 for (i = 0; i < 8; i++) {
465 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500466 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500467 tmp >>= 1;
468 }
David P. Quigley11689d42009-01-16 09:22:03 -0500469 /* Check if the Label support flag is set */
470 if (sbsec->flags & SE_SBLABELSUPP)
471 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500472
Eric Parise0007522008-03-05 10:31:54 -0500473 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
474 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500475 rc = -ENOMEM;
476 goto out_free;
477 }
478
Eric Parise0007522008-03-05 10:31:54 -0500479 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
480 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500481 rc = -ENOMEM;
482 goto out_free;
483 }
484
485 i = 0;
486 if (sbsec->flags & FSCONTEXT_MNT) {
487 rc = security_sid_to_context(sbsec->sid, &context, &len);
488 if (rc)
489 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500490 opts->mnt_opts[i] = context;
491 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500492 }
493 if (sbsec->flags & CONTEXT_MNT) {
494 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
495 if (rc)
496 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500497 opts->mnt_opts[i] = context;
498 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500499 }
500 if (sbsec->flags & DEFCONTEXT_MNT) {
501 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
502 if (rc)
503 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500504 opts->mnt_opts[i] = context;
505 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500506 }
507 if (sbsec->flags & ROOTCONTEXT_MNT) {
508 struct inode *root = sbsec->sb->s_root->d_inode;
509 struct inode_security_struct *isec = root->i_security;
510
511 rc = security_sid_to_context(isec->sid, &context, &len);
512 if (rc)
513 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500514 opts->mnt_opts[i] = context;
515 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500516 }
David P. Quigley11689d42009-01-16 09:22:03 -0500517 if (sbsec->flags & SE_SBLABELSUPP) {
518 opts->mnt_opts[i] = NULL;
519 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
520 }
Eric Parisc9180a52007-11-30 13:00:35 -0500521
Eric Parise0007522008-03-05 10:31:54 -0500522 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500523
524 return 0;
525
526out_free:
Eric Parise0007522008-03-05 10:31:54 -0500527 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500528 return rc;
529}
530
531static int bad_option(struct superblock_security_struct *sbsec, char flag,
532 u32 old_sid, u32 new_sid)
533{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500534 char mnt_flags = sbsec->flags & SE_MNTMASK;
535
Eric Parisc9180a52007-11-30 13:00:35 -0500536 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500537 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500538 if (!(sbsec->flags & flag) ||
539 (old_sid != new_sid))
540 return 1;
541
542 /* check if we were passed the same options twice,
543 * aka someone passed context=a,context=b
544 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500545 if (!(sbsec->flags & SE_SBINITIALIZED))
546 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500547 return 1;
548 return 0;
549}
Eric Parise0007522008-03-05 10:31:54 -0500550
Eric Parisc9180a52007-11-30 13:00:35 -0500551/*
552 * Allow filesystems with binary mount data to explicitly set mount point
553 * labeling information.
554 */
Eric Parise0007522008-03-05 10:31:54 -0500555static int selinux_set_mnt_opts(struct super_block *sb,
556 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500557{
David Howells275bb412008-11-14 10:39:19 +1100558 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500559 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500560 struct superblock_security_struct *sbsec = sb->s_security;
561 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000562 struct inode *inode = sbsec->sb->s_root->d_inode;
563 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500564 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
565 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500566 char **mount_options = opts->mnt_opts;
567 int *flags = opts->mnt_opts_flags;
568 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500569
570 mutex_lock(&sbsec->lock);
571
572 if (!ss_initialized) {
573 if (!num_opts) {
574 /* Defer initialization until selinux_complete_init,
575 after the initial policy is loaded and the security
576 server is ready to handle calls. */
Eric Parisc9180a52007-11-30 13:00:35 -0500577 goto out;
578 }
579 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400580 printk(KERN_WARNING "SELinux: Unable to set superblock options "
581 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500582 goto out;
583 }
584
585 /*
Eric Parise0007522008-03-05 10:31:54 -0500586 * Binary mount data FS will come through this function twice. Once
587 * from an explicit call and once from the generic calls from the vfs.
588 * Since the generic VFS calls will not contain any security mount data
589 * we need to skip the double mount verification.
590 *
591 * This does open a hole in which we will not notice if the first
592 * mount using this sb set explict options and a second mount using
593 * this sb does not set any security options. (The first options
594 * will be used for both mounts)
595 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500596 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500597 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400598 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500599
600 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500601 * parse the mount options, check if they are valid sids.
602 * also check if someone is trying to mount the same sb more
603 * than once with different security options.
604 */
605 for (i = 0; i < num_opts; i++) {
606 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500607
608 if (flags[i] == SE_SBLABELSUPP)
609 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500610 rc = security_context_to_sid(mount_options[i],
611 strlen(mount_options[i]), &sid);
612 if (rc) {
613 printk(KERN_WARNING "SELinux: security_context_to_sid"
614 "(%s) failed for (dev %s, type %s) errno=%d\n",
615 mount_options[i], sb->s_id, name, rc);
616 goto out;
617 }
618 switch (flags[i]) {
619 case FSCONTEXT_MNT:
620 fscontext_sid = sid;
621
622 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
623 fscontext_sid))
624 goto out_double_mount;
625
626 sbsec->flags |= FSCONTEXT_MNT;
627 break;
628 case CONTEXT_MNT:
629 context_sid = sid;
630
631 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
632 context_sid))
633 goto out_double_mount;
634
635 sbsec->flags |= CONTEXT_MNT;
636 break;
637 case ROOTCONTEXT_MNT:
638 rootcontext_sid = sid;
639
640 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
641 rootcontext_sid))
642 goto out_double_mount;
643
644 sbsec->flags |= ROOTCONTEXT_MNT;
645
646 break;
647 case DEFCONTEXT_MNT:
648 defcontext_sid = sid;
649
650 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
651 defcontext_sid))
652 goto out_double_mount;
653
654 sbsec->flags |= DEFCONTEXT_MNT;
655
656 break;
657 default:
658 rc = -EINVAL;
659 goto out;
660 }
661 }
662
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500663 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500664 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500665 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500666 goto out_double_mount;
667 rc = 0;
668 goto out;
669 }
670
James Morris089be432008-07-15 18:32:49 +1000671 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500672 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500673
674 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500675 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500676 if (rc) {
677 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000678 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500679 goto out;
680 }
681
682 /* sets the context of the superblock for the fs being mounted. */
683 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100684 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500685 if (rc)
686 goto out;
687
688 sbsec->sid = fscontext_sid;
689 }
690
691 /*
692 * Switch to using mount point labeling behavior.
693 * sets the label used on all file below the mountpoint, and will set
694 * the superblock context if not already set.
695 */
696 if (context_sid) {
697 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100698 rc = may_context_mount_sb_relabel(context_sid, sbsec,
699 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500700 if (rc)
701 goto out;
702 sbsec->sid = context_sid;
703 } else {
David Howells275bb412008-11-14 10:39:19 +1100704 rc = may_context_mount_inode_relabel(context_sid, sbsec,
705 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500706 if (rc)
707 goto out;
708 }
709 if (!rootcontext_sid)
710 rootcontext_sid = context_sid;
711
712 sbsec->mntpoint_sid = context_sid;
713 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
714 }
715
716 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100717 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
718 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500719 if (rc)
720 goto out;
721
722 root_isec->sid = rootcontext_sid;
723 root_isec->initialized = 1;
724 }
725
726 if (defcontext_sid) {
727 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
728 rc = -EINVAL;
729 printk(KERN_WARNING "SELinux: defcontext option is "
730 "invalid for this filesystem type\n");
731 goto out;
732 }
733
734 if (defcontext_sid != sbsec->def_sid) {
735 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100736 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500737 if (rc)
738 goto out;
739 }
740
741 sbsec->def_sid = defcontext_sid;
742 }
743
744 rc = sb_finish_set_opts(sb);
745out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700746 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500748out_double_mount:
749 rc = -EINVAL;
750 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
751 "security settings for (dev %s, type %s)\n", sb->s_id, name);
752 goto out;
753}
754
755static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
756 struct super_block *newsb)
757{
758 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
759 struct superblock_security_struct *newsbsec = newsb->s_security;
760
761 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
762 int set_context = (oldsbsec->flags & CONTEXT_MNT);
763 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
764
Eric Paris0f5e6422008-04-21 16:24:11 -0400765 /*
766 * if the parent was able to be mounted it clearly had no special lsm
Al Viroe8c26252010-03-23 06:36:54 -0400767 * mount options. thus we can safely deal with this superblock later
Eric Paris0f5e6422008-04-21 16:24:11 -0400768 */
Al Viroe8c26252010-03-23 06:36:54 -0400769 if (!ss_initialized)
Eric Paris0f5e6422008-04-21 16:24:11 -0400770 return;
Eric Parisc9180a52007-11-30 13:00:35 -0500771
Eric Parisc9180a52007-11-30 13:00:35 -0500772 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500773 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500774
Eric Paris5a552612008-04-09 14:08:35 -0400775 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500776 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400777 return;
778
Eric Parisc9180a52007-11-30 13:00:35 -0500779 mutex_lock(&newsbsec->lock);
780
781 newsbsec->flags = oldsbsec->flags;
782
783 newsbsec->sid = oldsbsec->sid;
784 newsbsec->def_sid = oldsbsec->def_sid;
785 newsbsec->behavior = oldsbsec->behavior;
786
787 if (set_context) {
788 u32 sid = oldsbsec->mntpoint_sid;
789
790 if (!set_fscontext)
791 newsbsec->sid = sid;
792 if (!set_rootcontext) {
793 struct inode *newinode = newsb->s_root->d_inode;
794 struct inode_security_struct *newisec = newinode->i_security;
795 newisec->sid = sid;
796 }
797 newsbsec->mntpoint_sid = sid;
798 }
799 if (set_rootcontext) {
800 const struct inode *oldinode = oldsb->s_root->d_inode;
801 const struct inode_security_struct *oldisec = oldinode->i_security;
802 struct inode *newinode = newsb->s_root->d_inode;
803 struct inode_security_struct *newisec = newinode->i_security;
804
805 newisec->sid = oldisec->sid;
806 }
807
808 sb_finish_set_opts(newsb);
809 mutex_unlock(&newsbsec->lock);
810}
811
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200812static int selinux_parse_opts_str(char *options,
813 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500814{
Eric Parise0007522008-03-05 10:31:54 -0500815 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500816 char *context = NULL, *defcontext = NULL;
817 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500818 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500819
Eric Parise0007522008-03-05 10:31:54 -0500820 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500821
822 /* Standard string-based options. */
823 while ((p = strsep(&options, "|")) != NULL) {
824 int token;
825 substring_t args[MAX_OPT_ARGS];
826
827 if (!*p)
828 continue;
829
830 token = match_token(p, tokens, args);
831
832 switch (token) {
833 case Opt_context:
834 if (context || defcontext) {
835 rc = -EINVAL;
836 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
837 goto out_err;
838 }
839 context = match_strdup(&args[0]);
840 if (!context) {
841 rc = -ENOMEM;
842 goto out_err;
843 }
844 break;
845
846 case Opt_fscontext:
847 if (fscontext) {
848 rc = -EINVAL;
849 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
850 goto out_err;
851 }
852 fscontext = match_strdup(&args[0]);
853 if (!fscontext) {
854 rc = -ENOMEM;
855 goto out_err;
856 }
857 break;
858
859 case Opt_rootcontext:
860 if (rootcontext) {
861 rc = -EINVAL;
862 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
863 goto out_err;
864 }
865 rootcontext = match_strdup(&args[0]);
866 if (!rootcontext) {
867 rc = -ENOMEM;
868 goto out_err;
869 }
870 break;
871
872 case Opt_defcontext:
873 if (context || defcontext) {
874 rc = -EINVAL;
875 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
876 goto out_err;
877 }
878 defcontext = match_strdup(&args[0]);
879 if (!defcontext) {
880 rc = -ENOMEM;
881 goto out_err;
882 }
883 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500884 case Opt_labelsupport:
885 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500886 default:
887 rc = -EINVAL;
888 printk(KERN_WARNING "SELinux: unknown mount option\n");
889 goto out_err;
890
891 }
892 }
893
Eric Parise0007522008-03-05 10:31:54 -0500894 rc = -ENOMEM;
895 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
896 if (!opts->mnt_opts)
897 goto out_err;
898
899 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
900 if (!opts->mnt_opts_flags) {
901 kfree(opts->mnt_opts);
902 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500903 }
904
Eric Parise0007522008-03-05 10:31:54 -0500905 if (fscontext) {
906 opts->mnt_opts[num_mnt_opts] = fscontext;
907 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
908 }
909 if (context) {
910 opts->mnt_opts[num_mnt_opts] = context;
911 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
912 }
913 if (rootcontext) {
914 opts->mnt_opts[num_mnt_opts] = rootcontext;
915 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
916 }
917 if (defcontext) {
918 opts->mnt_opts[num_mnt_opts] = defcontext;
919 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
920 }
921
922 opts->num_mnt_opts = num_mnt_opts;
923 return 0;
924
Eric Parisc9180a52007-11-30 13:00:35 -0500925out_err:
926 kfree(context);
927 kfree(defcontext);
928 kfree(fscontext);
929 kfree(rootcontext);
930 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931}
Eric Parise0007522008-03-05 10:31:54 -0500932/*
933 * string mount options parsing and call set the sbsec
934 */
935static int superblock_doinit(struct super_block *sb, void *data)
936{
937 int rc = 0;
938 char *options = data;
939 struct security_mnt_opts opts;
940
941 security_init_mnt_opts(&opts);
942
943 if (!data)
944 goto out;
945
946 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
947
948 rc = selinux_parse_opts_str(options, &opts);
949 if (rc)
950 goto out_err;
951
952out:
953 rc = selinux_set_mnt_opts(sb, &opts);
954
955out_err:
956 security_free_mnt_opts(&opts);
957 return rc;
958}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Adrian Bunk3583a712008-07-22 20:21:23 +0300960static void selinux_write_opts(struct seq_file *m,
961 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000962{
963 int i;
964 char *prefix;
965
966 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -0500967 char *has_comma;
968
969 if (opts->mnt_opts[i])
970 has_comma = strchr(opts->mnt_opts[i], ',');
971 else
972 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +1000973
974 switch (opts->mnt_opts_flags[i]) {
975 case CONTEXT_MNT:
976 prefix = CONTEXT_STR;
977 break;
978 case FSCONTEXT_MNT:
979 prefix = FSCONTEXT_STR;
980 break;
981 case ROOTCONTEXT_MNT:
982 prefix = ROOTCONTEXT_STR;
983 break;
984 case DEFCONTEXT_MNT:
985 prefix = DEFCONTEXT_STR;
986 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500987 case SE_SBLABELSUPP:
988 seq_putc(m, ',');
989 seq_puts(m, LABELSUPP_STR);
990 continue;
Eric Paris2069f452008-07-04 09:47:13 +1000991 default:
992 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -0400993 return;
Eric Paris2069f452008-07-04 09:47:13 +1000994 };
995 /* we need a comma before each option */
996 seq_putc(m, ',');
997 seq_puts(m, prefix);
998 if (has_comma)
999 seq_putc(m, '\"');
1000 seq_puts(m, opts->mnt_opts[i]);
1001 if (has_comma)
1002 seq_putc(m, '\"');
1003 }
1004}
1005
1006static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1007{
1008 struct security_mnt_opts opts;
1009 int rc;
1010
1011 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001012 if (rc) {
1013 /* before policy load we may get EINVAL, don't show anything */
1014 if (rc == -EINVAL)
1015 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001016 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001017 }
Eric Paris2069f452008-07-04 09:47:13 +10001018
1019 selinux_write_opts(m, &opts);
1020
1021 security_free_mnt_opts(&opts);
1022
1023 return rc;
1024}
1025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026static inline u16 inode_mode_to_security_class(umode_t mode)
1027{
1028 switch (mode & S_IFMT) {
1029 case S_IFSOCK:
1030 return SECCLASS_SOCK_FILE;
1031 case S_IFLNK:
1032 return SECCLASS_LNK_FILE;
1033 case S_IFREG:
1034 return SECCLASS_FILE;
1035 case S_IFBLK:
1036 return SECCLASS_BLK_FILE;
1037 case S_IFDIR:
1038 return SECCLASS_DIR;
1039 case S_IFCHR:
1040 return SECCLASS_CHR_FILE;
1041 case S_IFIFO:
1042 return SECCLASS_FIFO_FILE;
1043
1044 }
1045
1046 return SECCLASS_FILE;
1047}
1048
James Morris13402582005-09-30 14:24:34 -04001049static inline int default_protocol_stream(int protocol)
1050{
1051 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1052}
1053
1054static inline int default_protocol_dgram(int protocol)
1055{
1056 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1057}
1058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1060{
1061 switch (family) {
1062 case PF_UNIX:
1063 switch (type) {
1064 case SOCK_STREAM:
1065 case SOCK_SEQPACKET:
1066 return SECCLASS_UNIX_STREAM_SOCKET;
1067 case SOCK_DGRAM:
1068 return SECCLASS_UNIX_DGRAM_SOCKET;
1069 }
1070 break;
1071 case PF_INET:
1072 case PF_INET6:
1073 switch (type) {
1074 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001075 if (default_protocol_stream(protocol))
1076 return SECCLASS_TCP_SOCKET;
1077 else
1078 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001080 if (default_protocol_dgram(protocol))
1081 return SECCLASS_UDP_SOCKET;
1082 else
1083 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001084 case SOCK_DCCP:
1085 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001086 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return SECCLASS_RAWIP_SOCKET;
1088 }
1089 break;
1090 case PF_NETLINK:
1091 switch (protocol) {
1092 case NETLINK_ROUTE:
1093 return SECCLASS_NETLINK_ROUTE_SOCKET;
1094 case NETLINK_FIREWALL:
1095 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001096 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1098 case NETLINK_NFLOG:
1099 return SECCLASS_NETLINK_NFLOG_SOCKET;
1100 case NETLINK_XFRM:
1101 return SECCLASS_NETLINK_XFRM_SOCKET;
1102 case NETLINK_SELINUX:
1103 return SECCLASS_NETLINK_SELINUX_SOCKET;
1104 case NETLINK_AUDIT:
1105 return SECCLASS_NETLINK_AUDIT_SOCKET;
1106 case NETLINK_IP6_FW:
1107 return SECCLASS_NETLINK_IP6FW_SOCKET;
1108 case NETLINK_DNRTMSG:
1109 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001110 case NETLINK_KOBJECT_UEVENT:
1111 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 default:
1113 return SECCLASS_NETLINK_SOCKET;
1114 }
1115 case PF_PACKET:
1116 return SECCLASS_PACKET_SOCKET;
1117 case PF_KEY:
1118 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001119 case PF_APPLETALK:
1120 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122
1123 return SECCLASS_SOCKET;
1124}
1125
1126#ifdef CONFIG_PROC_FS
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001127static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 u16 tclass,
1129 u32 *sid)
1130{
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001131 int rc;
1132 char *buffer, *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Eric Paris828dfe12008-04-17 13:17:49 -04001134 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if (!buffer)
1136 return -ENOMEM;
1137
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001138 path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
1139 if (IS_ERR(path))
1140 rc = PTR_ERR(path);
1141 else {
1142 /* each process gets a /proc/PID/ entry. Strip off the
1143 * PID part to get a valid selinux labeling.
1144 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
1145 while (path[1] >= '0' && path[1] <= '9') {
1146 path[1] = '/';
1147 path++;
1148 }
1149 rc = security_genfs_sid("proc", path, tclass, sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 free_page((unsigned long)buffer);
1152 return rc;
1153}
1154#else
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001155static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 u16 tclass,
1157 u32 *sid)
1158{
1159 return -EINVAL;
1160}
1161#endif
1162
1163/* The inode's security attributes must be initialized before first use. */
1164static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1165{
1166 struct superblock_security_struct *sbsec = NULL;
1167 struct inode_security_struct *isec = inode->i_security;
1168 u32 sid;
1169 struct dentry *dentry;
1170#define INITCONTEXTLEN 255
1171 char *context = NULL;
1172 unsigned len = 0;
1173 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 if (isec->initialized)
1176 goto out;
1177
Eric Paris23970742006-09-25 23:32:01 -07001178 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001180 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001183 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 /* Defer initialization until selinux_complete_init,
1185 after the initial policy is loaded and the security
1186 server is ready to handle calls. */
1187 spin_lock(&sbsec->isec_lock);
1188 if (list_empty(&isec->list))
1189 list_add(&isec->list, &sbsec->isec_head);
1190 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001191 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
1193
1194 switch (sbsec->behavior) {
1195 case SECURITY_FS_USE_XATTR:
1196 if (!inode->i_op->getxattr) {
1197 isec->sid = sbsec->def_sid;
1198 break;
1199 }
1200
1201 /* Need a dentry, since the xattr API requires one.
1202 Life would be simpler if we could just pass the inode. */
1203 if (opt_dentry) {
1204 /* Called from d_instantiate or d_splice_alias. */
1205 dentry = dget(opt_dentry);
1206 } else {
1207 /* Called from selinux_complete_init, try to find a dentry. */
1208 dentry = d_find_alias(inode);
1209 }
1210 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001211 /*
1212 * this is can be hit on boot when a file is accessed
1213 * before the policy is loaded. When we load policy we
1214 * may find inodes that have no dentry on the
1215 * sbsec->isec_head list. No reason to complain as these
1216 * will get fixed up the next time we go through
1217 * inode_doinit with a dentry, before these inodes could
1218 * be used again by userspace.
1219 */
Eric Paris23970742006-09-25 23:32:01 -07001220 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
1222
1223 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001224 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 if (!context) {
1226 rc = -ENOMEM;
1227 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001228 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001230 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1232 context, len);
1233 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001234 kfree(context);
1235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 /* Need a larger buffer. Query for the right size. */
1237 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1238 NULL, 0);
1239 if (rc < 0) {
1240 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001241 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001244 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 if (!context) {
1246 rc = -ENOMEM;
1247 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001248 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001250 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 rc = inode->i_op->getxattr(dentry,
1252 XATTR_NAME_SELINUX,
1253 context, len);
1254 }
1255 dput(dentry);
1256 if (rc < 0) {
1257 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001258 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001259 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 -rc, inode->i_sb->s_id, inode->i_ino);
1261 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001262 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
1264 /* Map ENODATA to the default file SID */
1265 sid = sbsec->def_sid;
1266 rc = 0;
1267 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001268 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001269 sbsec->def_sid,
1270 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001272 char *dev = inode->i_sb->s_id;
1273 unsigned long ino = inode->i_ino;
1274
1275 if (rc == -EINVAL) {
1276 if (printk_ratelimit())
1277 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1278 "context=%s. This indicates you may need to relabel the inode or the "
1279 "filesystem in question.\n", ino, dev, context);
1280 } else {
1281 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1282 "returned %d for dev=%s ino=%ld\n",
1283 __func__, context, -rc, dev, ino);
1284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 kfree(context);
1286 /* Leave with the unlabeled SID */
1287 rc = 0;
1288 break;
1289 }
1290 }
1291 kfree(context);
1292 isec->sid = sid;
1293 break;
1294 case SECURITY_FS_USE_TASK:
1295 isec->sid = isec->task_sid;
1296 break;
1297 case SECURITY_FS_USE_TRANS:
1298 /* Default to the fs SID. */
1299 isec->sid = sbsec->sid;
1300
1301 /* Try to obtain a transition SID. */
1302 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Eric Paris652bb9b2011-02-01 11:05:40 -05001303 rc = security_transition_sid(isec->task_sid, sbsec->sid,
1304 isec->sclass, NULL, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001306 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 isec->sid = sid;
1308 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001309 case SECURITY_FS_USE_MNTPOINT:
1310 isec->sid = sbsec->mntpoint_sid;
1311 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001313 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 isec->sid = sbsec->sid;
1315
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001316 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001317 if (opt_dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001319 rc = selinux_proc_get_sid(opt_dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 isec->sclass,
1321 &sid);
1322 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001323 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 isec->sid = sid;
1325 }
1326 }
1327 break;
1328 }
1329
1330 isec->initialized = 1;
1331
Eric Paris23970742006-09-25 23:32:01 -07001332out_unlock:
1333 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334out:
1335 if (isec->sclass == SECCLASS_FILE)
1336 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 return rc;
1338}
1339
1340/* Convert a Linux signal to an access vector. */
1341static inline u32 signal_to_av(int sig)
1342{
1343 u32 perm = 0;
1344
1345 switch (sig) {
1346 case SIGCHLD:
1347 /* Commonly granted from child to parent. */
1348 perm = PROCESS__SIGCHLD;
1349 break;
1350 case SIGKILL:
1351 /* Cannot be caught or ignored */
1352 perm = PROCESS__SIGKILL;
1353 break;
1354 case SIGSTOP:
1355 /* Cannot be caught or ignored */
1356 perm = PROCESS__SIGSTOP;
1357 break;
1358 default:
1359 /* All other signals. */
1360 perm = PROCESS__SIGNAL;
1361 break;
1362 }
1363
1364 return perm;
1365}
1366
David Howells275bb412008-11-14 10:39:19 +11001367/*
David Howellsd84f4f92008-11-14 10:39:23 +11001368 * Check permission between a pair of credentials
1369 * fork check, ptrace check, etc.
1370 */
1371static int cred_has_perm(const struct cred *actor,
1372 const struct cred *target,
1373 u32 perms)
1374{
1375 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1376
1377 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1378}
1379
1380/*
David Howells88e67f32008-11-14 10:39:21 +11001381 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001382 * fork check, ptrace check, etc.
1383 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001384 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001385 */
1386static int task_has_perm(const struct task_struct *tsk1,
1387 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 u32 perms)
1389{
David Howells275bb412008-11-14 10:39:19 +11001390 const struct task_security_struct *__tsec1, *__tsec2;
1391 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
David Howells275bb412008-11-14 10:39:19 +11001393 rcu_read_lock();
1394 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1395 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1396 rcu_read_unlock();
1397 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398}
1399
David Howells3b11a1d2008-11-14 10:39:26 +11001400/*
1401 * Check permission between current and another task, e.g. signal checks,
1402 * fork check, ptrace check, etc.
1403 * current is the actor and tsk2 is the target
1404 * - this uses current's subjective creds
1405 */
1406static int current_has_perm(const struct task_struct *tsk,
1407 u32 perms)
1408{
1409 u32 sid, tsid;
1410
1411 sid = current_sid();
1412 tsid = task_sid(tsk);
1413 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1414}
1415
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001416#if CAP_LAST_CAP > 63
1417#error Fix SELinux to handle capabilities > 63.
1418#endif
1419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420/* Check whether a task is allowed to use a capability. */
1421static int task_has_capability(struct task_struct *tsk,
David Howells3699c532009-01-06 22:27:01 +00001422 const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001423 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424{
Thomas Liu2bf49692009-07-14 12:14:09 -04001425 struct common_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001426 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001427 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001428 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001429 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001430 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
Thomas Liu2bf49692009-07-14 12:14:09 -04001432 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 ad.tsk = tsk;
1434 ad.u.cap = cap;
1435
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001436 switch (CAP_TO_INDEX(cap)) {
1437 case 0:
1438 sclass = SECCLASS_CAPABILITY;
1439 break;
1440 case 1:
1441 sclass = SECCLASS_CAPABILITY2;
1442 break;
1443 default:
1444 printk(KERN_ERR
1445 "SELinux: out of range capability %d\n", cap);
1446 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001447 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001448 }
Eric Paris06112162008-11-11 22:02:50 +11001449
David Howells275bb412008-11-14 10:39:19 +11001450 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001451 if (audit == SECURITY_CAP_AUDIT) {
1452 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1453 if (rc2)
1454 return rc2;
1455 }
Eric Paris06112162008-11-11 22:02:50 +11001456 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457}
1458
1459/* Check whether a task is allowed to use a system operation. */
1460static int task_has_system(struct task_struct *tsk,
1461 u32 perms)
1462{
David Howells275bb412008-11-14 10:39:19 +11001463 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
David Howells275bb412008-11-14 10:39:19 +11001465 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 SECCLASS_SYSTEM, perms, NULL);
1467}
1468
1469/* Check whether a task has a particular permission to an inode.
1470 The 'adp' parameter is optional and allows other audit
1471 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001472static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 struct inode *inode,
1474 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001475 struct common_audit_data *adp,
1476 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001479 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
David Howellse0e81732009-09-02 09:13:40 +01001481 validate_creds(cred);
1482
Eric Paris828dfe12008-04-17 13:17:49 -04001483 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001484 return 0;
1485
David Howells88e67f32008-11-14 10:39:21 +11001486 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 isec = inode->i_security;
1488
Eric Paris9ade0cf2011-04-25 16:26:29 -04001489 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490}
1491
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001492static int inode_has_perm_noadp(const struct cred *cred,
1493 struct inode *inode,
1494 u32 perms,
1495 unsigned flags)
1496{
1497 struct common_audit_data ad;
1498
1499 COMMON_AUDIT_DATA_INIT(&ad, INODE);
1500 ad.u.inode = inode;
1501 return inode_has_perm(cred, inode, perms, &ad, flags);
1502}
1503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504/* Same as inode_has_perm, but pass explicit audit data containing
1505 the dentry to help the auditing code to more easily generate the
1506 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001507static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 struct dentry *dentry,
1509 u32 av)
1510{
1511 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001512 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001513
Eric Paris2875fa02011-04-28 16:04:24 -04001514 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1515 ad.u.dentry = dentry;
1516 return inode_has_perm(cred, inode, av, &ad, 0);
1517}
1518
1519/* Same as inode_has_perm, but pass explicit audit data containing
1520 the path to help the auditing code to more easily generate the
1521 pathname if needed. */
1522static inline int path_has_perm(const struct cred *cred,
1523 struct path *path,
1524 u32 av)
1525{
1526 struct inode *inode = path->dentry->d_inode;
1527 struct common_audit_data ad;
1528
Eric Parisf48b7392011-04-25 12:54:27 -04001529 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001530 ad.u.path = *path;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001531 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532}
1533
1534/* Check whether a task can use an open file descriptor to
1535 access an inode in a given way. Check access to the
1536 descriptor itself, and then use dentry_has_perm to
1537 check a particular permission to the file.
1538 Access to the descriptor is implicitly granted if it
1539 has the same SID as the process. If av is zero, then
1540 access to the file is not checked, e.g. for cases
1541 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001542static int file_has_perm(const struct cred *cred,
1543 struct file *file,
1544 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001547 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001548 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001549 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 int rc;
1551
Eric Parisf48b7392011-04-25 12:54:27 -04001552 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1553 ad.u.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
David Howells275bb412008-11-14 10:39:19 +11001555 if (sid != fsec->sid) {
1556 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 SECCLASS_FD,
1558 FD__USE,
1559 &ad);
1560 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001561 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
1563
1564 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001565 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001567 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
David Howells88e67f32008-11-14 10:39:21 +11001569out:
1570 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571}
1572
1573/* Check whether a task can create a file. */
1574static int may_create(struct inode *dir,
1575 struct dentry *dentry,
1576 u16 tclass)
1577{
Paul Moore5fb49872010-04-22 14:46:19 -04001578 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 struct inode_security_struct *dsec;
1580 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001581 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001582 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 int rc;
1584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 dsec = dir->i_security;
1586 sbsec = dir->i_sb->s_security;
1587
David Howells275bb412008-11-14 10:39:19 +11001588 sid = tsec->sid;
1589 newsid = tsec->create_sid;
1590
Eric Parisa2694342011-04-25 13:10:27 -04001591 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1592 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
David Howells275bb412008-11-14 10:39:19 +11001594 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 DIR__ADD_NAME | DIR__SEARCH,
1596 &ad);
1597 if (rc)
1598 return rc;
1599
David P. Quigleycd895962009-01-16 09:22:04 -05001600 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001601 rc = security_transition_sid(sid, dsec->sid, tclass,
1602 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (rc)
1604 return rc;
1605 }
1606
David Howells275bb412008-11-14 10:39:19 +11001607 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (rc)
1609 return rc;
1610
1611 return avc_has_perm(newsid, sbsec->sid,
1612 SECCLASS_FILESYSTEM,
1613 FILESYSTEM__ASSOCIATE, &ad);
1614}
1615
Michael LeMay4eb582c2006-06-26 00:24:57 -07001616/* Check whether a task can create a key. */
1617static int may_create_key(u32 ksid,
1618 struct task_struct *ctx)
1619{
David Howells275bb412008-11-14 10:39:19 +11001620 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001621
David Howells275bb412008-11-14 10:39:19 +11001622 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001623}
1624
Eric Paris828dfe12008-04-17 13:17:49 -04001625#define MAY_LINK 0
1626#define MAY_UNLINK 1
1627#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629/* Check whether a task can link, unlink, or rmdir a file/directory. */
1630static int may_link(struct inode *dir,
1631 struct dentry *dentry,
1632 int kind)
1633
1634{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001636 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001637 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 u32 av;
1639 int rc;
1640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 dsec = dir->i_security;
1642 isec = dentry->d_inode->i_security;
1643
Eric Parisa2694342011-04-25 13:10:27 -04001644 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1645 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 av = DIR__SEARCH;
1648 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001649 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (rc)
1651 return rc;
1652
1653 switch (kind) {
1654 case MAY_LINK:
1655 av = FILE__LINK;
1656 break;
1657 case MAY_UNLINK:
1658 av = FILE__UNLINK;
1659 break;
1660 case MAY_RMDIR:
1661 av = DIR__RMDIR;
1662 break;
1663 default:
Eric Paris744ba352008-04-17 11:52:44 -04001664 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1665 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 return 0;
1667 }
1668
David Howells275bb412008-11-14 10:39:19 +11001669 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 return rc;
1671}
1672
1673static inline int may_rename(struct inode *old_dir,
1674 struct dentry *old_dentry,
1675 struct inode *new_dir,
1676 struct dentry *new_dentry)
1677{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001679 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001680 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 u32 av;
1682 int old_is_dir, new_is_dir;
1683 int rc;
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 old_dsec = old_dir->i_security;
1686 old_isec = old_dentry->d_inode->i_security;
1687 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1688 new_dsec = new_dir->i_security;
1689
Eric Parisa2694342011-04-25 13:10:27 -04001690 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Eric Parisa2694342011-04-25 13:10:27 -04001692 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001693 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1695 if (rc)
1696 return rc;
David Howells275bb412008-11-14 10:39:19 +11001697 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 old_isec->sclass, FILE__RENAME, &ad);
1699 if (rc)
1700 return rc;
1701 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001702 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 old_isec->sclass, DIR__REPARENT, &ad);
1704 if (rc)
1705 return rc;
1706 }
1707
Eric Parisa2694342011-04-25 13:10:27 -04001708 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 av = DIR__ADD_NAME | DIR__SEARCH;
1710 if (new_dentry->d_inode)
1711 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001712 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 if (rc)
1714 return rc;
1715 if (new_dentry->d_inode) {
1716 new_isec = new_dentry->d_inode->i_security;
1717 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001718 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 new_isec->sclass,
1720 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1721 if (rc)
1722 return rc;
1723 }
1724
1725 return 0;
1726}
1727
1728/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001729static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 struct super_block *sb,
1731 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001732 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001735 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001738 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739}
1740
1741/* Convert a Linux mode and permission mask to an access vector. */
1742static inline u32 file_mask_to_av(int mode, int mask)
1743{
1744 u32 av = 0;
1745
1746 if ((mode & S_IFMT) != S_IFDIR) {
1747 if (mask & MAY_EXEC)
1748 av |= FILE__EXECUTE;
1749 if (mask & MAY_READ)
1750 av |= FILE__READ;
1751
1752 if (mask & MAY_APPEND)
1753 av |= FILE__APPEND;
1754 else if (mask & MAY_WRITE)
1755 av |= FILE__WRITE;
1756
1757 } else {
1758 if (mask & MAY_EXEC)
1759 av |= DIR__SEARCH;
1760 if (mask & MAY_WRITE)
1761 av |= DIR__WRITE;
1762 if (mask & MAY_READ)
1763 av |= DIR__READ;
1764 }
1765
1766 return av;
1767}
1768
1769/* Convert a Linux file to an access vector. */
1770static inline u32 file_to_av(struct file *file)
1771{
1772 u32 av = 0;
1773
1774 if (file->f_mode & FMODE_READ)
1775 av |= FILE__READ;
1776 if (file->f_mode & FMODE_WRITE) {
1777 if (file->f_flags & O_APPEND)
1778 av |= FILE__APPEND;
1779 else
1780 av |= FILE__WRITE;
1781 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001782 if (!av) {
1783 /*
1784 * Special file opened with flags 3 for ioctl-only use.
1785 */
1786 av = FILE__IOCTL;
1787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
1789 return av;
1790}
1791
Eric Paris8b6a5a32008-10-29 17:06:46 -04001792/*
1793 * Convert a file to an access vector and include the correct open
1794 * open permission.
1795 */
1796static inline u32 open_file_to_av(struct file *file)
1797{
1798 u32 av = file_to_av(file);
1799
Eric Paris49b7b8d2010-07-23 11:44:09 -04001800 if (selinux_policycap_openperm)
1801 av |= FILE__OPEN;
1802
Eric Paris8b6a5a32008-10-29 17:06:46 -04001803 return av;
1804}
1805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806/* Hook functions begin here. */
1807
Ingo Molnar9e488582009-05-07 19:26:19 +10001808static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001809 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 int rc;
1812
Ingo Molnar9e488582009-05-07 19:26:19 +10001813 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 if (rc)
1815 return rc;
1816
Stephen Smalley006ebb42008-05-19 08:32:49 -04001817 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001818 u32 sid = current_sid();
1819 u32 csid = task_sid(child);
1820 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001821 }
1822
David Howells3b11a1d2008-11-14 10:39:26 +11001823 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001824}
1825
1826static int selinux_ptrace_traceme(struct task_struct *parent)
1827{
1828 int rc;
1829
Eric Paris200ac532009-02-12 15:01:04 -05001830 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001831 if (rc)
1832 return rc;
1833
1834 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835}
1836
1837static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001838 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839{
1840 int error;
1841
David Howells3b11a1d2008-11-14 10:39:26 +11001842 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 if (error)
1844 return error;
1845
Eric Paris200ac532009-02-12 15:01:04 -05001846 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847}
1848
David Howellsd84f4f92008-11-14 10:39:23 +11001849static int selinux_capset(struct cred *new, const struct cred *old,
1850 const kernel_cap_t *effective,
1851 const kernel_cap_t *inheritable,
1852 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853{
1854 int error;
1855
Eric Paris200ac532009-02-12 15:01:04 -05001856 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001857 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (error)
1859 return error;
1860
David Howellsd84f4f92008-11-14 10:39:23 +11001861 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
James Morris5626d3e2009-01-30 10:05:06 +11001864/*
1865 * (This comment used to live with the selinux_task_setuid hook,
1866 * which was removed).
1867 *
1868 * Since setuid only affects the current process, and since the SELinux
1869 * controls are not based on the Linux identity attributes, SELinux does not
1870 * need to control this operation. However, SELinux does control the use of
1871 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1872 */
1873
David Howells3699c532009-01-06 22:27:01 +00001874static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
Serge E. Hallyn3486740a2011-03-23 16:43:17 -07001875 struct user_namespace *ns, int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876{
1877 int rc;
1878
Serge E. Hallyn3486740a2011-03-23 16:43:17 -07001879 rc = cap_capable(tsk, cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 if (rc)
1881 return rc;
1882
David Howells3699c532009-01-06 22:27:01 +00001883 return task_has_capability(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884}
1885
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1887{
David Howells88e67f32008-11-14 10:39:21 +11001888 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 int rc = 0;
1890
1891 if (!sb)
1892 return 0;
1893
1894 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001895 case Q_SYNC:
1896 case Q_QUOTAON:
1897 case Q_QUOTAOFF:
1898 case Q_SETINFO:
1899 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001900 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001901 break;
1902 case Q_GETFMT:
1903 case Q_GETINFO:
1904 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001905 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001906 break;
1907 default:
1908 rc = 0; /* let the kernel handle invalid cmds */
1909 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 }
1911 return rc;
1912}
1913
1914static int selinux_quota_on(struct dentry *dentry)
1915{
David Howells88e67f32008-11-14 10:39:21 +11001916 const struct cred *cred = current_cred();
1917
Eric Paris2875fa02011-04-28 16:04:24 -04001918 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919}
1920
Eric Paris12b30522010-11-15 18:36:29 -05001921static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
1923 int rc;
1924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08001926 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
1927 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001928 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1929 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001930 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
1931 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
1932 /* Set level of messages printed to console */
1933 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04001934 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1935 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001936 case SYSLOG_ACTION_CLOSE: /* Close log */
1937 case SYSLOG_ACTION_OPEN: /* Open log */
1938 case SYSLOG_ACTION_READ: /* Read from log */
1939 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
1940 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001941 default:
1942 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1943 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 }
1945 return rc;
1946}
1947
1948/*
1949 * Check that a process has enough memory to allocate a new virtual
1950 * mapping. 0 means there is enough memory for the allocation to
1951 * succeed and -ENOMEM implies there is not.
1952 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 * Do not audit the selinux permission check, as this is applied to all
1954 * processes that allocate mappings.
1955 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001956static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957{
1958 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
Serge E. Hallyn3486740a2011-03-23 16:43:17 -07001960 rc = selinux_capable(current, current_cred(),
1961 &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00001962 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc == 0)
1964 cap_sys_admin = 1;
1965
Alan Cox34b4e4a2007-08-22 14:01:28 -07001966 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967}
1968
1969/* binprm security operations */
1970
David Howellsa6f76f22008-11-14 10:39:24 +11001971static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972{
David Howellsa6f76f22008-11-14 10:39:24 +11001973 const struct task_security_struct *old_tsec;
1974 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001976 struct common_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11001977 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 int rc;
1979
Eric Paris200ac532009-02-12 15:01:04 -05001980 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (rc)
1982 return rc;
1983
David Howellsa6f76f22008-11-14 10:39:24 +11001984 /* SELinux context only depends on initial program or script and not
1985 * the script interpreter */
1986 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 return 0;
1988
David Howellsa6f76f22008-11-14 10:39:24 +11001989 old_tsec = current_security();
1990 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 isec = inode->i_security;
1992
1993 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11001994 new_tsec->sid = old_tsec->sid;
1995 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Michael LeMay28eba5b2006-06-27 02:53:42 -07001997 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11001998 new_tsec->create_sid = 0;
1999 new_tsec->keycreate_sid = 0;
2000 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
David Howellsa6f76f22008-11-14 10:39:24 +11002002 if (old_tsec->exec_sid) {
2003 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002005 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 } else {
2007 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002008 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002009 SECCLASS_PROCESS, NULL,
2010 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if (rc)
2012 return rc;
2013 }
2014
Eric Parisf48b7392011-04-25 12:54:27 -04002015 COMMON_AUDIT_DATA_INIT(&ad, PATH);
2016 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Josef Sipek3d5ff522006-12-08 02:37:38 -08002018 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002019 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
David Howellsa6f76f22008-11-14 10:39:24 +11002021 if (new_tsec->sid == old_tsec->sid) {
2022 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2024 if (rc)
2025 return rc;
2026 } else {
2027 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002028 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2030 if (rc)
2031 return rc;
2032
David Howellsa6f76f22008-11-14 10:39:24 +11002033 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2035 if (rc)
2036 return rc;
2037
David Howellsa6f76f22008-11-14 10:39:24 +11002038 /* Check for shared state */
2039 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2040 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2041 SECCLASS_PROCESS, PROCESS__SHARE,
2042 NULL);
2043 if (rc)
2044 return -EPERM;
2045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
David Howellsa6f76f22008-11-14 10:39:24 +11002047 /* Make sure that anyone attempting to ptrace over a task that
2048 * changes its SID has the appropriate permit */
2049 if (bprm->unsafe &
2050 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2051 struct task_struct *tracer;
2052 struct task_security_struct *sec;
2053 u32 ptsid = 0;
2054
2055 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002056 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002057 if (likely(tracer != NULL)) {
2058 sec = __task_cred(tracer)->security;
2059 ptsid = sec->sid;
2060 }
2061 rcu_read_unlock();
2062
2063 if (ptsid != 0) {
2064 rc = avc_has_perm(ptsid, new_tsec->sid,
2065 SECCLASS_PROCESS,
2066 PROCESS__PTRACE, NULL);
2067 if (rc)
2068 return -EPERM;
2069 }
2070 }
2071
2072 /* Clear any possibly unsafe personality bits on exec: */
2073 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 }
2075
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 return 0;
2077}
2078
Eric Paris828dfe12008-04-17 13:17:49 -04002079static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080{
Paul Moore5fb49872010-04-22 14:46:19 -04002081 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002082 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 int atsecure = 0;
2084
David Howells275bb412008-11-14 10:39:19 +11002085 sid = tsec->sid;
2086 osid = tsec->osid;
2087
2088 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 /* Enable secure mode for SIDs transitions unless
2090 the noatsecure permission is granted between
2091 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002092 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002093 SECCLASS_PROCESS,
2094 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 }
2096
Eric Paris200ac532009-02-12 15:01:04 -05002097 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098}
2099
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002101static inline void flush_unauthorized_files(const struct cred *cred,
2102 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103{
Thomas Liu2bf49692009-07-14 12:14:09 -04002104 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002106 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002107 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002109 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002111 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002113 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002114 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002115 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002116 struct inode *inode;
2117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 /* Revalidate access to controlling tty.
2119 Use inode_has_perm on the tty inode directly rather
2120 than using file_has_perm, as this particular open
2121 file may belong to another process and we are only
2122 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002123 file_priv = list_first_entry(&tty->tty_files,
2124 struct tty_file_private, list);
2125 file = file_priv->file;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002126 inode = file->f_path.dentry->d_inode;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07002127 if (inode_has_perm_noadp(cred, inode,
2128 FILE__READ | FILE__WRITE, 0)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002129 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 }
2131 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002132 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002133 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002135 /* Reset controlling tty. */
2136 if (drop_tty)
2137 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
2139 /* Revalidate access to inherited open files. */
2140
Eric Parisf48b7392011-04-25 12:54:27 -04002141 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
2143 spin_lock(&files->file_lock);
2144 for (;;) {
2145 unsigned long set, i;
2146 int fd;
2147
2148 j++;
2149 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002150 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002151 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002153 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 if (!set)
2155 continue;
2156 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002157 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 if (set & 1) {
2159 file = fget(i);
2160 if (!file)
2161 continue;
David Howells88e67f32008-11-14 10:39:21 +11002162 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 file,
2164 file_to_av(file))) {
2165 sys_close(i);
2166 fd = get_unused_fd();
2167 if (fd != i) {
2168 if (fd >= 0)
2169 put_unused_fd(fd);
2170 fput(file);
2171 continue;
2172 }
2173 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002174 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 } else {
David Howells745ca242008-11-14 10:39:22 +11002176 devnull = dentry_open(
2177 dget(selinux_null),
2178 mntget(selinuxfs_mount),
2179 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002180 if (IS_ERR(devnull)) {
2181 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 put_unused_fd(fd);
2183 fput(file);
2184 continue;
2185 }
2186 }
2187 fd_install(fd, devnull);
2188 }
2189 fput(file);
2190 }
2191 }
2192 spin_lock(&files->file_lock);
2193
2194 }
2195 spin_unlock(&files->file_lock);
2196}
2197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198/*
David Howellsa6f76f22008-11-14 10:39:24 +11002199 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 */
David Howellsa6f76f22008-11-14 10:39:24 +11002201static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202{
David Howellsa6f76f22008-11-14 10:39:24 +11002203 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 int rc, i;
2206
David Howellsa6f76f22008-11-14 10:39:24 +11002207 new_tsec = bprm->cred->security;
2208 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 return;
2210
2211 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002212 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
David Howellsa6f76f22008-11-14 10:39:24 +11002214 /* Always clear parent death signal on SID transitions. */
2215 current->pdeath_signal = 0;
2216
2217 /* Check whether the new SID can inherit resource limits from the old
2218 * SID. If not, reset all soft limits to the lower of the current
2219 * task's hard limit and the init task's soft limit.
2220 *
2221 * Note that the setting of hard limits (even to lower them) can be
2222 * controlled by the setrlimit check. The inclusion of the init task's
2223 * soft limit into the computation is to avoid resetting soft limits
2224 * higher than the default soft limit for cases where the default is
2225 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2226 */
2227 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2228 PROCESS__RLIMITINH, NULL);
2229 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002230 /* protect against do_prlimit() */
2231 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002232 for (i = 0; i < RLIM_NLIMITS; i++) {
2233 rlim = current->signal->rlim + i;
2234 initrlim = init_task.signal->rlim + i;
2235 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2236 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002237 task_unlock(current);
2238 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002239 }
2240}
2241
2242/*
2243 * Clean up the process immediately after the installation of new credentials
2244 * due to exec
2245 */
2246static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2247{
2248 const struct task_security_struct *tsec = current_security();
2249 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002250 u32 osid, sid;
2251 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002252
David Howellsa6f76f22008-11-14 10:39:24 +11002253 osid = tsec->osid;
2254 sid = tsec->sid;
2255
2256 if (sid == osid)
2257 return;
2258
2259 /* Check whether the new SID can inherit signal state from the old SID.
2260 * If not, clear itimers to avoid subsequent signal generation and
2261 * flush and unblock signals.
2262 *
2263 * This must occur _after_ the task SID has been updated so that any
2264 * kill done after the flush will be checked against the new SID.
2265 */
2266 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 if (rc) {
2268 memset(&itimer, 0, sizeof itimer);
2269 for (i = 0; i < 3; i++)
2270 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002272 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2273 __flush_signals(current);
2274 flush_signal_handlers(current, 1);
2275 sigemptyset(&current->blocked);
2276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 spin_unlock_irq(&current->sighand->siglock);
2278 }
2279
David Howellsa6f76f22008-11-14 10:39:24 +11002280 /* Wake up the parent if it is waiting so that it can recheck
2281 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002282 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002283 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002284 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285}
2286
2287/* superblock security operations */
2288
2289static int selinux_sb_alloc_security(struct super_block *sb)
2290{
2291 return superblock_alloc_security(sb);
2292}
2293
2294static void selinux_sb_free_security(struct super_block *sb)
2295{
2296 superblock_free_security(sb);
2297}
2298
2299static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2300{
2301 if (plen > olen)
2302 return 0;
2303
2304 return !memcmp(prefix, option, plen);
2305}
2306
2307static inline int selinux_option(char *option, int len)
2308{
Eric Paris832cbd92008-04-01 13:24:09 -04002309 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2310 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2311 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002312 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2313 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314}
2315
2316static inline void take_option(char **to, char *from, int *first, int len)
2317{
2318 if (!*first) {
2319 **to = ',';
2320 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002321 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 *first = 0;
2323 memcpy(*to, from, len);
2324 *to += len;
2325}
2326
Eric Paris828dfe12008-04-17 13:17:49 -04002327static inline void take_selinux_option(char **to, char *from, int *first,
2328 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002329{
2330 int current_size = 0;
2331
2332 if (!*first) {
2333 **to = '|';
2334 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002335 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002336 *first = 0;
2337
2338 while (current_size < len) {
2339 if (*from != '"') {
2340 **to = *from;
2341 *to += 1;
2342 }
2343 from += 1;
2344 current_size += 1;
2345 }
2346}
2347
Eric Parise0007522008-03-05 10:31:54 -05002348static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349{
2350 int fnosec, fsec, rc = 0;
2351 char *in_save, *in_curr, *in_end;
2352 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002353 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
2355 in_curr = orig;
2356 sec_curr = copy;
2357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2359 if (!nosec) {
2360 rc = -ENOMEM;
2361 goto out;
2362 }
2363
2364 nosec_save = nosec;
2365 fnosec = fsec = 1;
2366 in_save = in_end = orig;
2367
2368 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002369 if (*in_end == '"')
2370 open_quote = !open_quote;
2371 if ((*in_end == ',' && open_quote == 0) ||
2372 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 int len = in_end - in_curr;
2374
2375 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002376 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 else
2378 take_option(&nosec, in_curr, &fnosec, len);
2379
2380 in_curr = in_end + 1;
2381 }
2382 } while (*in_end++);
2383
Eric Paris6931dfc2005-06-30 02:58:51 -07002384 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002385 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386out:
2387 return rc;
2388}
2389
Eric Paris026eb162011-03-03 16:09:14 -05002390static int selinux_sb_remount(struct super_block *sb, void *data)
2391{
2392 int rc, i, *flags;
2393 struct security_mnt_opts opts;
2394 char *secdata, **mount_options;
2395 struct superblock_security_struct *sbsec = sb->s_security;
2396
2397 if (!(sbsec->flags & SE_SBINITIALIZED))
2398 return 0;
2399
2400 if (!data)
2401 return 0;
2402
2403 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2404 return 0;
2405
2406 security_init_mnt_opts(&opts);
2407 secdata = alloc_secdata();
2408 if (!secdata)
2409 return -ENOMEM;
2410 rc = selinux_sb_copy_data(data, secdata);
2411 if (rc)
2412 goto out_free_secdata;
2413
2414 rc = selinux_parse_opts_str(secdata, &opts);
2415 if (rc)
2416 goto out_free_secdata;
2417
2418 mount_options = opts.mnt_opts;
2419 flags = opts.mnt_opts_flags;
2420
2421 for (i = 0; i < opts.num_mnt_opts; i++) {
2422 u32 sid;
2423 size_t len;
2424
2425 if (flags[i] == SE_SBLABELSUPP)
2426 continue;
2427 len = strlen(mount_options[i]);
2428 rc = security_context_to_sid(mount_options[i], len, &sid);
2429 if (rc) {
2430 printk(KERN_WARNING "SELinux: security_context_to_sid"
2431 "(%s) failed for (dev %s, type %s) errno=%d\n",
2432 mount_options[i], sb->s_id, sb->s_type->name, rc);
2433 goto out_free_opts;
2434 }
2435 rc = -EINVAL;
2436 switch (flags[i]) {
2437 case FSCONTEXT_MNT:
2438 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2439 goto out_bad_option;
2440 break;
2441 case CONTEXT_MNT:
2442 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2443 goto out_bad_option;
2444 break;
2445 case ROOTCONTEXT_MNT: {
2446 struct inode_security_struct *root_isec;
2447 root_isec = sb->s_root->d_inode->i_security;
2448
2449 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2450 goto out_bad_option;
2451 break;
2452 }
2453 case DEFCONTEXT_MNT:
2454 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2455 goto out_bad_option;
2456 break;
2457 default:
2458 goto out_free_opts;
2459 }
2460 }
2461
2462 rc = 0;
2463out_free_opts:
2464 security_free_mnt_opts(&opts);
2465out_free_secdata:
2466 free_secdata(secdata);
2467 return rc;
2468out_bad_option:
2469 printk(KERN_WARNING "SELinux: unable to change security options "
2470 "during remount (dev %s, type=%s)\n", sb->s_id,
2471 sb->s_type->name);
2472 goto out_free_opts;
2473}
2474
James Morris12204e22008-12-19 10:44:42 +11002475static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476{
David Howells88e67f32008-11-14 10:39:21 +11002477 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002478 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 int rc;
2480
2481 rc = superblock_doinit(sb, data);
2482 if (rc)
2483 return rc;
2484
James Morris74192242008-12-19 11:41:10 +11002485 /* Allow all mounts performed by the kernel */
2486 if (flags & MS_KERNMOUNT)
2487 return 0;
2488
Eric Parisa2694342011-04-25 13:10:27 -04002489 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
2490 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002491 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492}
2493
David Howells726c3342006-06-23 02:02:58 -07002494static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495{
David Howells88e67f32008-11-14 10:39:21 +11002496 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002497 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Eric Parisa2694342011-04-25 13:10:27 -04002499 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
2500 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002501 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502}
2503
Eric Paris828dfe12008-04-17 13:17:49 -04002504static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002505 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002506 char *type,
2507 unsigned long flags,
2508 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509{
David Howells88e67f32008-11-14 10:39:21 +11002510 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002513 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002514 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 else
Eric Paris2875fa02011-04-28 16:04:24 -04002516 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517}
2518
2519static int selinux_umount(struct vfsmount *mnt, int flags)
2520{
David Howells88e67f32008-11-14 10:39:21 +11002521 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
David Howells88e67f32008-11-14 10:39:21 +11002523 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002524 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525}
2526
2527/* inode security operations */
2528
2529static int selinux_inode_alloc_security(struct inode *inode)
2530{
2531 return inode_alloc_security(inode);
2532}
2533
2534static void selinux_inode_free_security(struct inode *inode)
2535{
2536 inode_free_security(inode);
2537}
2538
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002539static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002540 const struct qstr *qstr, char **name,
2541 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002542{
Paul Moore5fb49872010-04-22 14:46:19 -04002543 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002544 struct inode_security_struct *dsec;
2545 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002546 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002547 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002548 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002549
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002550 dsec = dir->i_security;
2551 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002552
David Howells275bb412008-11-14 10:39:19 +11002553 sid = tsec->sid;
2554 newsid = tsec->create_sid;
2555
Eric Paris415103f2010-12-02 16:13:40 -05002556 if ((sbsec->flags & SE_SBINITIALIZED) &&
2557 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2558 newsid = sbsec->mntpoint_sid;
2559 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002560 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002561 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002562 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002563 if (rc) {
2564 printk(KERN_WARNING "%s: "
2565 "security_transition_sid failed, rc=%d (dev=%s "
2566 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002567 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002568 -rc, inode->i_sb->s_id, inode->i_ino);
2569 return rc;
2570 }
2571 }
2572
Eric Paris296fddf2006-09-25 23:32:00 -07002573 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002574 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002575 struct inode_security_struct *isec = inode->i_security;
2576 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2577 isec->sid = newsid;
2578 isec->initialized = 1;
2579 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002580
David P. Quigleycd895962009-01-16 09:22:04 -05002581 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002582 return -EOPNOTSUPP;
2583
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002584 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002585 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002586 if (!namep)
2587 return -ENOMEM;
2588 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002589 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002590
2591 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002592 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002593 if (rc) {
2594 kfree(namep);
2595 return rc;
2596 }
2597 *value = context;
2598 *len = clen;
2599 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002600
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002601 return 0;
2602}
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2605{
2606 return may_create(dir, dentry, SECCLASS_FILE);
2607}
2608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2610{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 return may_link(dir, old_dentry, MAY_LINK);
2612}
2613
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2615{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 return may_link(dir, dentry, MAY_UNLINK);
2617}
2618
2619static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2620{
2621 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2622}
2623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2625{
2626 return may_create(dir, dentry, SECCLASS_DIR);
2627}
2628
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2630{
2631 return may_link(dir, dentry, MAY_RMDIR);
2632}
2633
2634static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2635{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2637}
2638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002640 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641{
2642 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2643}
2644
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645static int selinux_inode_readlink(struct dentry *dentry)
2646{
David Howells88e67f32008-11-14 10:39:21 +11002647 const struct cred *cred = current_cred();
2648
Eric Paris2875fa02011-04-28 16:04:24 -04002649 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650}
2651
2652static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2653{
David Howells88e67f32008-11-14 10:39:21 +11002654 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Eric Paris2875fa02011-04-28 16:04:24 -04002656 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657}
2658
Al Viroe74f71e2011-06-20 19:38:15 -04002659static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660{
David Howells88e67f32008-11-14 10:39:21 +11002661 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002662 struct common_audit_data ad;
2663 u32 perms;
2664 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002665 unsigned flags = mask & MAY_NOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Eric Parisb782e0a2010-07-23 11:44:03 -04002667 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002668 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2669
Eric Parisb782e0a2010-07-23 11:44:03 -04002670 /* No permission to check. Existence test. */
2671 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
Eric Parisf48b7392011-04-25 12:54:27 -04002674 COMMON_AUDIT_DATA_INIT(&ad, INODE);
2675 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002676
2677 if (from_access)
2678 ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
2679
2680 perms = file_mask_to_av(inode->i_mode, mask);
2681
Eric Paris9ade0cf2011-04-25 16:26:29 -04002682 return inode_has_perm(cred, inode, perms, &ad, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683}
2684
2685static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2686{
David Howells88e67f32008-11-14 10:39:21 +11002687 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002688 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002690 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2691 if (ia_valid & ATTR_FORCE) {
2692 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2693 ATTR_FORCE);
2694 if (!ia_valid)
2695 return 0;
2696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002698 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2699 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002700 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Eric Paris2875fa02011-04-28 16:04:24 -04002702 return dentry_has_perm(cred, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703}
2704
2705static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2706{
David Howells88e67f32008-11-14 10:39:21 +11002707 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002708 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002709
Eric Paris2875fa02011-04-28 16:04:24 -04002710 path.dentry = dentry;
2711 path.mnt = mnt;
2712
2713 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714}
2715
David Howells8f0cfa52008-04-29 00:59:41 -07002716static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002717{
David Howells88e67f32008-11-14 10:39:21 +11002718 const struct cred *cred = current_cred();
2719
Serge E. Hallynb5376772007-10-16 23:31:36 -07002720 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2721 sizeof XATTR_SECURITY_PREFIX - 1)) {
2722 if (!strcmp(name, XATTR_NAME_CAPS)) {
2723 if (!capable(CAP_SETFCAP))
2724 return -EPERM;
2725 } else if (!capable(CAP_SYS_ADMIN)) {
2726 /* A different attribute in the security namespace.
2727 Restrict to administrator. */
2728 return -EPERM;
2729 }
2730 }
2731
2732 /* Not an attribute we recognize, so just check the
2733 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002734 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002735}
2736
David Howells8f0cfa52008-04-29 00:59:41 -07002737static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2738 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 struct inode *inode = dentry->d_inode;
2741 struct inode_security_struct *isec = inode->i_security;
2742 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002743 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002744 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 int rc = 0;
2746
Serge E. Hallynb5376772007-10-16 23:31:36 -07002747 if (strcmp(name, XATTR_NAME_SELINUX))
2748 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
2750 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002751 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 return -EOPNOTSUPP;
2753
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002754 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return -EPERM;
2756
Eric Parisa2694342011-04-25 13:10:27 -04002757 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
2758 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
David Howells275bb412008-11-14 10:39:19 +11002760 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 FILE__RELABELFROM, &ad);
2762 if (rc)
2763 return rc;
2764
2765 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002766 if (rc == -EINVAL) {
2767 if (!capable(CAP_MAC_ADMIN))
2768 return rc;
2769 rc = security_context_to_sid_force(value, size, &newsid);
2770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 if (rc)
2772 return rc;
2773
David Howells275bb412008-11-14 10:39:19 +11002774 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 FILE__RELABELTO, &ad);
2776 if (rc)
2777 return rc;
2778
David Howells275bb412008-11-14 10:39:19 +11002779 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002780 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 if (rc)
2782 return rc;
2783
2784 return avc_has_perm(newsid,
2785 sbsec->sid,
2786 SECCLASS_FILESYSTEM,
2787 FILESYSTEM__ASSOCIATE,
2788 &ad);
2789}
2790
David Howells8f0cfa52008-04-29 00:59:41 -07002791static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002792 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002793 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794{
2795 struct inode *inode = dentry->d_inode;
2796 struct inode_security_struct *isec = inode->i_security;
2797 u32 newsid;
2798 int rc;
2799
2800 if (strcmp(name, XATTR_NAME_SELINUX)) {
2801 /* Not an attribute we recognize, so nothing to do. */
2802 return;
2803 }
2804
Stephen Smalley12b29f32008-05-07 13:03:20 -04002805 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002807 printk(KERN_ERR "SELinux: unable to map context to SID"
2808 "for (%s, %lu), rc=%d\n",
2809 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 return;
2811 }
2812
2813 isec->sid = newsid;
2814 return;
2815}
2816
David Howells8f0cfa52008-04-29 00:59:41 -07002817static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818{
David Howells88e67f32008-11-14 10:39:21 +11002819 const struct cred *cred = current_cred();
2820
Eric Paris2875fa02011-04-28 16:04:24 -04002821 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822}
2823
Eric Paris828dfe12008-04-17 13:17:49 -04002824static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825{
David Howells88e67f32008-11-14 10:39:21 +11002826 const struct cred *cred = current_cred();
2827
Eric Paris2875fa02011-04-28 16:04:24 -04002828 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829}
2830
David Howells8f0cfa52008-04-29 00:59:41 -07002831static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002833 if (strcmp(name, XATTR_NAME_SELINUX))
2834 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836 /* No one is allowed to remove a SELinux security label.
2837 You can change the label, but all data must be labeled. */
2838 return -EACCES;
2839}
2840
James Morrisd381d8a2005-10-30 14:59:22 -08002841/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002842 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002843 *
2844 * Permission check is handled by selinux_inode_getxattr hook.
2845 */
David P. Quigley42492592008-02-04 22:29:39 -08002846static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847{
David P. Quigley42492592008-02-04 22:29:39 -08002848 u32 size;
2849 int error;
2850 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002853 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2854 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002856 /*
2857 * If the caller has CAP_MAC_ADMIN, then get the raw context
2858 * value even if it is not defined by current policy; otherwise,
2859 * use the in-core value under current policy.
2860 * Use the non-auditing forms of the permission checks since
2861 * getxattr may be called by unprivileged processes commonly
2862 * and lack of permission just means that we fall back to the
2863 * in-core context value, not a denial.
2864 */
Serge E. Hallyn3486740a2011-03-23 16:43:17 -07002865 error = selinux_capable(current, current_cred(),
2866 &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002867 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002868 if (!error)
2869 error = security_sid_to_context_force(isec->sid, &context,
2870 &size);
2871 else
2872 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002873 if (error)
2874 return error;
2875 error = size;
2876 if (alloc) {
2877 *buffer = context;
2878 goto out_nofree;
2879 }
2880 kfree(context);
2881out_nofree:
2882 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883}
2884
2885static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002886 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887{
2888 struct inode_security_struct *isec = inode->i_security;
2889 u32 newsid;
2890 int rc;
2891
2892 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2893 return -EOPNOTSUPP;
2894
2895 if (!value || !size)
2896 return -EACCES;
2897
Eric Paris828dfe12008-04-17 13:17:49 -04002898 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 if (rc)
2900 return rc;
2901
2902 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002903 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 return 0;
2905}
2906
2907static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2908{
2909 const int len = sizeof(XATTR_NAME_SELINUX);
2910 if (buffer && len <= buffer_size)
2911 memcpy(buffer, XATTR_NAME_SELINUX, len);
2912 return len;
2913}
2914
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002915static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2916{
2917 struct inode_security_struct *isec = inode->i_security;
2918 *secid = isec->sid;
2919}
2920
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921/* file security operations */
2922
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002923static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924{
David Howells88e67f32008-11-14 10:39:21 +11002925 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002926 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2929 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2930 mask |= MAY_APPEND;
2931
Paul Moore389fb8002009-03-27 17:10:34 -04002932 return file_has_perm(cred, file,
2933 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934}
2935
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002936static int selinux_file_permission(struct file *file, int mask)
2937{
Stephen Smalley20dda182009-06-22 14:54:53 -04002938 struct inode *inode = file->f_path.dentry->d_inode;
2939 struct file_security_struct *fsec = file->f_security;
2940 struct inode_security_struct *isec = inode->i_security;
2941 u32 sid = current_sid();
2942
Paul Moore389fb8002009-03-27 17:10:34 -04002943 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002944 /* No permission to check. Existence test. */
2945 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002946
Stephen Smalley20dda182009-06-22 14:54:53 -04002947 if (sid == fsec->sid && fsec->isid == isec->sid &&
2948 fsec->pseqno == avc_policy_seqno())
2949 /* No change since dentry_open check. */
2950 return 0;
2951
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002952 return selinux_revalidate_file_permission(file, mask);
2953}
2954
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955static int selinux_file_alloc_security(struct file *file)
2956{
2957 return file_alloc_security(file);
2958}
2959
2960static void selinux_file_free_security(struct file *file)
2961{
2962 file_free_security(file);
2963}
2964
2965static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2966 unsigned long arg)
2967{
David Howells88e67f32008-11-14 10:39:21 +11002968 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05002969 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
Eric Paris0b24dcb2011-02-25 15:39:20 -05002971 switch (cmd) {
2972 case FIONREAD:
2973 /* fall through */
2974 case FIBMAP:
2975 /* fall through */
2976 case FIGETBSZ:
2977 /* fall through */
2978 case EXT2_IOC_GETFLAGS:
2979 /* fall through */
2980 case EXT2_IOC_GETVERSION:
2981 error = file_has_perm(cred, file, FILE__GETATTR);
2982 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
Eric Paris0b24dcb2011-02-25 15:39:20 -05002984 case EXT2_IOC_SETFLAGS:
2985 /* fall through */
2986 case EXT2_IOC_SETVERSION:
2987 error = file_has_perm(cred, file, FILE__SETATTR);
2988 break;
2989
2990 /* sys_ioctl() checks */
2991 case FIONBIO:
2992 /* fall through */
2993 case FIOASYNC:
2994 error = file_has_perm(cred, file, 0);
2995 break;
2996
2997 case KDSKBENT:
2998 case KDSKBSENT:
2999 error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG,
Serge E. Hallyn3486740a2011-03-23 16:43:17 -07003000 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003001 break;
3002
3003 /* default case assumes that the command will go
3004 * to the file's ioctl() function.
3005 */
3006 default:
3007 error = file_has_perm(cred, file, FILE__IOCTL);
3008 }
3009 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010}
3011
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003012static int default_noexec;
3013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3015{
David Howells88e67f32008-11-14 10:39:21 +11003016 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003017 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003018
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003019 if (default_noexec &&
3020 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 /*
3022 * We are making executable an anonymous mapping or a
3023 * private file mapping that will also be writable.
3024 * This has an additional check.
3025 */
David Howellsd84f4f92008-11-14 10:39:23 +11003026 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003028 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031 if (file) {
3032 /* read access is always possible with a mapping */
3033 u32 av = FILE__READ;
3034
3035 /* write access only matters if the mapping is shared */
3036 if (shared && (prot & PROT_WRITE))
3037 av |= FILE__WRITE;
3038
3039 if (prot & PROT_EXEC)
3040 av |= FILE__EXECUTE;
3041
David Howells88e67f32008-11-14 10:39:21 +11003042 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 }
David Howellsd84f4f92008-11-14 10:39:23 +11003044
3045error:
3046 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047}
3048
3049static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003050 unsigned long prot, unsigned long flags,
3051 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052{
Eric Parised032182007-06-28 15:55:21 -04003053 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003054 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055
Eric Paris84336d1a2009-07-31 12:54:05 -04003056 /*
3057 * notice that we are intentionally putting the SELinux check before
3058 * the secondary cap_file_mmap check. This is such a likely attempt
3059 * at bad behaviour/exploit that we always want to get the AVC, even
3060 * if DAC would have also denied the operation.
3061 */
Eric Parisa2551df2009-07-31 12:54:11 -04003062 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003063 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3064 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003065 if (rc)
3066 return rc;
3067 }
3068
3069 /* do DAC check on address space usage */
3070 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003071 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 return rc;
3073
3074 if (selinux_checkreqprot)
3075 prot = reqprot;
3076
3077 return file_map_prot_check(file, prot,
3078 (flags & MAP_TYPE) == MAP_SHARED);
3079}
3080
3081static int selinux_file_mprotect(struct vm_area_struct *vma,
3082 unsigned long reqprot,
3083 unsigned long prot)
3084{
David Howells88e67f32008-11-14 10:39:21 +11003085 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
3087 if (selinux_checkreqprot)
3088 prot = reqprot;
3089
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003090 if (default_noexec &&
3091 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003092 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003093 if (vma->vm_start >= vma->vm_mm->start_brk &&
3094 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003095 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003096 } else if (!vma->vm_file &&
3097 vma->vm_start <= vma->vm_mm->start_stack &&
3098 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003099 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003100 } else if (vma->vm_file && vma->anon_vma) {
3101 /*
3102 * We are making executable a file mapping that has
3103 * had some COW done. Since pages might have been
3104 * written, check ability to execute the possibly
3105 * modified content. This typically should only
3106 * occur for text relocations.
3107 */
David Howellsd84f4f92008-11-14 10:39:23 +11003108 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003109 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003110 if (rc)
3111 return rc;
3112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
3114 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3115}
3116
3117static int selinux_file_lock(struct file *file, unsigned int cmd)
3118{
David Howells88e67f32008-11-14 10:39:21 +11003119 const struct cred *cred = current_cred();
3120
3121 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122}
3123
3124static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3125 unsigned long arg)
3126{
David Howells88e67f32008-11-14 10:39:21 +11003127 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 int err = 0;
3129
3130 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003131 case F_SETFL:
3132 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3133 err = -EINVAL;
3134 break;
3135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136
Eric Paris828dfe12008-04-17 13:17:49 -04003137 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003138 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003140 }
3141 /* fall through */
3142 case F_SETOWN:
3143 case F_SETSIG:
3144 case F_GETFL:
3145 case F_GETOWN:
3146 case F_GETSIG:
3147 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003148 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003149 break;
3150 case F_GETLK:
3151 case F_SETLK:
3152 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003154 case F_GETLK64:
3155 case F_SETLK64:
3156 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003158 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3159 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003161 }
David Howells88e67f32008-11-14 10:39:21 +11003162 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003163 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 }
3165
3166 return err;
3167}
3168
3169static int selinux_file_set_fowner(struct file *file)
3170{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 struct file_security_struct *fsec;
3172
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003174 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176 return 0;
3177}
3178
3179static int selinux_file_send_sigiotask(struct task_struct *tsk,
3180 struct fown_struct *fown, int signum)
3181{
Eric Paris828dfe12008-04-17 13:17:49 -04003182 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003183 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 struct file_security_struct *fsec;
3186
3187 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003188 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 fsec = file->f_security;
3191
3192 if (!signum)
3193 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3194 else
3195 perm = signal_to_av(signum);
3196
David Howells275bb412008-11-14 10:39:19 +11003197 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 SECCLASS_PROCESS, perm, NULL);
3199}
3200
3201static int selinux_file_receive(struct file *file)
3202{
David Howells88e67f32008-11-14 10:39:21 +11003203 const struct cred *cred = current_cred();
3204
3205 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206}
3207
David Howells745ca242008-11-14 10:39:22 +11003208static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003209{
3210 struct file_security_struct *fsec;
3211 struct inode *inode;
3212 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003213
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003214 inode = file->f_path.dentry->d_inode;
3215 fsec = file->f_security;
3216 isec = inode->i_security;
3217 /*
3218 * Save inode label and policy sequence number
3219 * at open-time so that selinux_file_permission
3220 * can determine whether revalidation is necessary.
3221 * Task label is already saved in the file security
3222 * struct as its SID.
3223 */
3224 fsec->isid = isec->sid;
3225 fsec->pseqno = avc_policy_seqno();
3226 /*
3227 * Since the inode label or policy seqno may have changed
3228 * between the selinux_inode_permission check and the saving
3229 * of state above, recheck that access is still permitted.
3230 * Otherwise, access might never be revalidated against the
3231 * new inode label or new policy.
3232 * This check is not redundant - do not remove.
3233 */
Linus Torvalds95f4efb2011-06-08 15:11:56 -07003234 return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003235}
3236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237/* task security operations */
3238
3239static int selinux_task_create(unsigned long clone_flags)
3240{
David Howells3b11a1d2008-11-14 10:39:26 +11003241 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242}
3243
David Howellsf1752ee2008-11-14 10:39:17 +11003244/*
David Howellsee18d642009-09-02 09:14:21 +01003245 * allocate the SELinux part of blank credentials
3246 */
3247static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3248{
3249 struct task_security_struct *tsec;
3250
3251 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3252 if (!tsec)
3253 return -ENOMEM;
3254
3255 cred->security = tsec;
3256 return 0;
3257}
3258
3259/*
David Howellsf1752ee2008-11-14 10:39:17 +11003260 * detach and free the LSM part of a set of credentials
3261 */
3262static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263{
David Howellsf1752ee2008-11-14 10:39:17 +11003264 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003265
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003266 /*
3267 * cred->security == NULL if security_cred_alloc_blank() or
3268 * security_prepare_creds() returned an error.
3269 */
3270 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003271 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003272 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273}
3274
David Howellsd84f4f92008-11-14 10:39:23 +11003275/*
3276 * prepare a new set of credentials for modification
3277 */
3278static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3279 gfp_t gfp)
3280{
3281 const struct task_security_struct *old_tsec;
3282 struct task_security_struct *tsec;
3283
3284 old_tsec = old->security;
3285
3286 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3287 if (!tsec)
3288 return -ENOMEM;
3289
3290 new->security = tsec;
3291 return 0;
3292}
3293
3294/*
David Howellsee18d642009-09-02 09:14:21 +01003295 * transfer the SELinux data to a blank set of creds
3296 */
3297static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3298{
3299 const struct task_security_struct *old_tsec = old->security;
3300 struct task_security_struct *tsec = new->security;
3301
3302 *tsec = *old_tsec;
3303}
3304
3305/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003306 * set the security data for a kernel service
3307 * - all the creation contexts are set to unlabelled
3308 */
3309static int selinux_kernel_act_as(struct cred *new, u32 secid)
3310{
3311 struct task_security_struct *tsec = new->security;
3312 u32 sid = current_sid();
3313 int ret;
3314
3315 ret = avc_has_perm(sid, secid,
3316 SECCLASS_KERNEL_SERVICE,
3317 KERNEL_SERVICE__USE_AS_OVERRIDE,
3318 NULL);
3319 if (ret == 0) {
3320 tsec->sid = secid;
3321 tsec->create_sid = 0;
3322 tsec->keycreate_sid = 0;
3323 tsec->sockcreate_sid = 0;
3324 }
3325 return ret;
3326}
3327
3328/*
3329 * set the file creation context in a security record to the same as the
3330 * objective context of the specified inode
3331 */
3332static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3333{
3334 struct inode_security_struct *isec = inode->i_security;
3335 struct task_security_struct *tsec = new->security;
3336 u32 sid = current_sid();
3337 int ret;
3338
3339 ret = avc_has_perm(sid, isec->sid,
3340 SECCLASS_KERNEL_SERVICE,
3341 KERNEL_SERVICE__CREATE_FILES_AS,
3342 NULL);
3343
3344 if (ret == 0)
3345 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003346 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003347}
3348
Eric Parisdd8dbf22009-11-03 16:35:32 +11003349static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003350{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003351 u32 sid;
3352 struct common_audit_data ad;
3353
3354 sid = task_sid(current);
3355
3356 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
3357 ad.u.kmod_name = kmod_name;
3358
3359 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3360 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003361}
3362
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3364{
David Howells3b11a1d2008-11-14 10:39:26 +11003365 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366}
3367
3368static int selinux_task_getpgid(struct task_struct *p)
3369{
David Howells3b11a1d2008-11-14 10:39:26 +11003370 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371}
3372
3373static int selinux_task_getsid(struct task_struct *p)
3374{
David Howells3b11a1d2008-11-14 10:39:26 +11003375 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376}
3377
David Quigleyf9008e42006-06-30 01:55:46 -07003378static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3379{
David Howells275bb412008-11-14 10:39:19 +11003380 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003381}
3382
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383static int selinux_task_setnice(struct task_struct *p, int nice)
3384{
3385 int rc;
3386
Eric Paris200ac532009-02-12 15:01:04 -05003387 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 if (rc)
3389 return rc;
3390
David Howells3b11a1d2008-11-14 10:39:26 +11003391 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392}
3393
James Morris03e68062006-06-23 02:03:58 -07003394static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3395{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003396 int rc;
3397
Eric Paris200ac532009-02-12 15:01:04 -05003398 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003399 if (rc)
3400 return rc;
3401
David Howells3b11a1d2008-11-14 10:39:26 +11003402 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003403}
3404
David Quigleya1836a42006-06-30 01:55:49 -07003405static int selinux_task_getioprio(struct task_struct *p)
3406{
David Howells3b11a1d2008-11-14 10:39:26 +11003407 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003408}
3409
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003410static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3411 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003413 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
3415 /* Control the ability to change the hard limit (whether
3416 lowering or raising it), so that the hard limit can
3417 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003418 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003420 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 return 0;
3423}
3424
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003425static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003427 int rc;
3428
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003429 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003430 if (rc)
3431 return rc;
3432
David Howells3b11a1d2008-11-14 10:39:26 +11003433 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434}
3435
3436static int selinux_task_getscheduler(struct task_struct *p)
3437{
David Howells3b11a1d2008-11-14 10:39:26 +11003438 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439}
3440
David Quigley35601542006-06-23 02:04:01 -07003441static int selinux_task_movememory(struct task_struct *p)
3442{
David Howells3b11a1d2008-11-14 10:39:26 +11003443 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003444}
3445
David Quigleyf9008e42006-06-30 01:55:46 -07003446static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3447 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
3449 u32 perm;
3450 int rc;
3451
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 if (!sig)
3453 perm = PROCESS__SIGNULL; /* null signal; existence test */
3454 else
3455 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003456 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003457 rc = avc_has_perm(secid, task_sid(p),
3458 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003459 else
David Howells3b11a1d2008-11-14 10:39:26 +11003460 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003461 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462}
3463
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464static int selinux_task_wait(struct task_struct *p)
3465{
Eric Paris8a535142007-10-22 16:10:31 -04003466 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467}
3468
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469static void selinux_task_to_inode(struct task_struct *p,
3470 struct inode *inode)
3471{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003473 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474
David Howells275bb412008-11-14 10:39:19 +11003475 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477}
3478
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003480static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003481 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482{
3483 int offset, ihlen, ret = -EINVAL;
3484 struct iphdr _iph, *ih;
3485
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003486 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3488 if (ih == NULL)
3489 goto out;
3490
3491 ihlen = ih->ihl * 4;
3492 if (ihlen < sizeof(_iph))
3493 goto out;
3494
3495 ad->u.net.v4info.saddr = ih->saddr;
3496 ad->u.net.v4info.daddr = ih->daddr;
3497 ret = 0;
3498
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003499 if (proto)
3500 *proto = ih->protocol;
3501
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003503 case IPPROTO_TCP: {
3504 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
Eric Paris828dfe12008-04-17 13:17:49 -04003506 if (ntohs(ih->frag_off) & IP_OFFSET)
3507 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
3509 offset += ihlen;
3510 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3511 if (th == NULL)
3512 break;
3513
3514 ad->u.net.sport = th->source;
3515 ad->u.net.dport = th->dest;
3516 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
Eric Paris828dfe12008-04-17 13:17:49 -04003519 case IPPROTO_UDP: {
3520 struct udphdr _udph, *uh;
3521
3522 if (ntohs(ih->frag_off) & IP_OFFSET)
3523 break;
3524
3525 offset += ihlen;
3526 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3527 if (uh == NULL)
3528 break;
3529
3530 ad->u.net.sport = uh->source;
3531 ad->u.net.dport = uh->dest;
3532 break;
3533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
James Morris2ee92d42006-11-13 16:09:01 -08003535 case IPPROTO_DCCP: {
3536 struct dccp_hdr _dccph, *dh;
3537
3538 if (ntohs(ih->frag_off) & IP_OFFSET)
3539 break;
3540
3541 offset += ihlen;
3542 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3543 if (dh == NULL)
3544 break;
3545
3546 ad->u.net.sport = dh->dccph_sport;
3547 ad->u.net.dport = dh->dccph_dport;
3548 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003549 }
James Morris2ee92d42006-11-13 16:09:01 -08003550
Eric Paris828dfe12008-04-17 13:17:49 -04003551 default:
3552 break;
3553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554out:
3555 return ret;
3556}
3557
3558#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3559
3560/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003561static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003562 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563{
3564 u8 nexthdr;
3565 int ret = -EINVAL, offset;
3566 struct ipv6hdr _ipv6h, *ip6;
3567
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003568 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3570 if (ip6 == NULL)
3571 goto out;
3572
3573 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3574 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3575 ret = 0;
3576
3577 nexthdr = ip6->nexthdr;
3578 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003579 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 if (offset < 0)
3581 goto out;
3582
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003583 if (proto)
3584 *proto = nexthdr;
3585
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 switch (nexthdr) {
3587 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003588 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
3590 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3591 if (th == NULL)
3592 break;
3593
3594 ad->u.net.sport = th->source;
3595 ad->u.net.dport = th->dest;
3596 break;
3597 }
3598
3599 case IPPROTO_UDP: {
3600 struct udphdr _udph, *uh;
3601
3602 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3603 if (uh == NULL)
3604 break;
3605
3606 ad->u.net.sport = uh->source;
3607 ad->u.net.dport = uh->dest;
3608 break;
3609 }
3610
James Morris2ee92d42006-11-13 16:09:01 -08003611 case IPPROTO_DCCP: {
3612 struct dccp_hdr _dccph, *dh;
3613
3614 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3615 if (dh == NULL)
3616 break;
3617
3618 ad->u.net.sport = dh->dccph_sport;
3619 ad->u.net.dport = dh->dccph_dport;
3620 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003621 }
James Morris2ee92d42006-11-13 16:09:01 -08003622
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 /* includes fragments */
3624 default:
3625 break;
3626 }
3627out:
3628 return ret;
3629}
3630
3631#endif /* IPV6 */
3632
Thomas Liu2bf49692009-07-14 12:14:09 -04003633static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003634 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635{
David Howellscf9481e2008-07-27 21:31:07 +10003636 char *addrp;
3637 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
3639 switch (ad->u.net.family) {
3640 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003641 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003642 if (ret)
3643 goto parse_error;
3644 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3645 &ad->u.net.v4info.daddr);
3646 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3649 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003650 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003651 if (ret)
3652 goto parse_error;
3653 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3654 &ad->u.net.v6info.daddr);
3655 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656#endif /* IPV6 */
3657 default:
David Howellscf9481e2008-07-27 21:31:07 +10003658 addrp = NULL;
3659 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 }
3661
David Howellscf9481e2008-07-27 21:31:07 +10003662parse_error:
3663 printk(KERN_WARNING
3664 "SELinux: failure in selinux_parse_skb(),"
3665 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003667
3668okay:
3669 if (_addrp)
3670 *_addrp = addrp;
3671 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672}
3673
Paul Moore4f6a9932007-03-01 14:35:22 -05003674/**
Paul Moore220deb92008-01-29 08:38:23 -05003675 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003676 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003677 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003678 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003679 *
3680 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003681 * Check the various different forms of network peer labeling and determine
3682 * the peer label/SID for the packet; most of the magic actually occurs in
3683 * the security server function security_net_peersid_cmp(). The function
3684 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3685 * or -EACCES if @sid is invalid due to inconsistencies with the different
3686 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003687 *
3688 */
Paul Moore220deb92008-01-29 08:38:23 -05003689static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003690{
Paul Moore71f1cb02008-01-29 08:51:16 -05003691 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003692 u32 xfrm_sid;
3693 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003694 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003695
3696 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003697 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003698
Paul Moore71f1cb02008-01-29 08:51:16 -05003699 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3700 if (unlikely(err)) {
3701 printk(KERN_WARNING
3702 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3703 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003704 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003705 }
Paul Moore220deb92008-01-29 08:38:23 -05003706
3707 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003708}
3709
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003711
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003712static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3713 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003714{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003715 if (tsec->sockcreate_sid > SECSID_NULL) {
3716 *socksid = tsec->sockcreate_sid;
3717 return 0;
3718 }
3719
3720 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3721 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003722}
3723
Paul Moore253bfae2010-04-22 14:46:19 -04003724static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725{
Paul Moore253bfae2010-04-22 14:46:19 -04003726 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003727 struct common_audit_data ad;
Paul Moore253bfae2010-04-22 14:46:19 -04003728 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729
Paul Moore253bfae2010-04-22 14:46:19 -04003730 if (sksec->sid == SECINITSID_KERNEL)
3731 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
Thomas Liu2bf49692009-07-14 12:14:09 -04003733 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moore253bfae2010-04-22 14:46:19 -04003734 ad.u.net.sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735
Paul Moore253bfae2010-04-22 14:46:19 -04003736 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737}
3738
3739static int selinux_socket_create(int family, int type,
3740 int protocol, int kern)
3741{
Paul Moore5fb49872010-04-22 14:46:19 -04003742 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003743 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003744 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003745 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
3747 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003748 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
David Howells275bb412008-11-14 10:39:19 +11003750 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003751 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3752 if (rc)
3753 return rc;
3754
Paul Moored4f2d972010-04-22 14:46:18 -04003755 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756}
3757
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003758static int selinux_socket_post_create(struct socket *sock, int family,
3759 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760{
Paul Moore5fb49872010-04-22 14:46:19 -04003761 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003762 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003763 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003764 int err = 0;
3765
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003766 isec->sclass = socket_type_to_security_class(family, type, protocol);
3767
David Howells275bb412008-11-14 10:39:19 +11003768 if (kern)
3769 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003770 else {
3771 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3772 if (err)
3773 return err;
3774 }
David Howells275bb412008-11-14 10:39:19 +11003775
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 isec->initialized = 1;
3777
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003778 if (sock->sk) {
3779 sksec = sock->sk->sk_security;
3780 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003781 sksec->sclass = isec->sclass;
Paul Moore389fb8002009-03-27 17:10:34 -04003782 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003783 }
3784
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003785 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786}
3787
3788/* Range of port numbers used to automatically bind.
3789 Need to determine whether we should perform a name_bind
3790 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
3792static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3793{
Paul Moore253bfae2010-04-22 14:46:19 -04003794 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 u16 family;
3796 int err;
3797
Paul Moore253bfae2010-04-22 14:46:19 -04003798 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 if (err)
3800 goto out;
3801
3802 /*
3803 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003804 * Multiple address binding for SCTP is not supported yet: we just
3805 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 */
Paul Moore253bfae2010-04-22 14:46:19 -04003807 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 if (family == PF_INET || family == PF_INET6) {
3809 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003810 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003811 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 struct sockaddr_in *addr4 = NULL;
3813 struct sockaddr_in6 *addr6 = NULL;
3814 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003815 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 if (family == PF_INET) {
3818 addr4 = (struct sockaddr_in *)address;
3819 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 addrp = (char *)&addr4->sin_addr.s_addr;
3821 } else {
3822 addr6 = (struct sockaddr_in6 *)address;
3823 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 addrp = (char *)&addr6->sin6_addr.s6_addr;
3825 }
3826
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003827 if (snum) {
3828 int low, high;
3829
3830 inet_get_local_port_range(&low, &high);
3831
3832 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003833 err = sel_netport_sid(sk->sk_protocol,
3834 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003835 if (err)
3836 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003837 COMMON_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003838 ad.u.net.sport = htons(snum);
3839 ad.u.net.family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003840 err = avc_has_perm(sksec->sid, sid,
3841 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003842 SOCKET__NAME_BIND, &ad);
3843 if (err)
3844 goto out;
3845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 }
Eric Paris828dfe12008-04-17 13:17:49 -04003847
Paul Moore253bfae2010-04-22 14:46:19 -04003848 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003849 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 node_perm = TCP_SOCKET__NODE_BIND;
3851 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003852
James Morris13402582005-09-30 14:24:34 -04003853 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 node_perm = UDP_SOCKET__NODE_BIND;
3855 break;
James Morris2ee92d42006-11-13 16:09:01 -08003856
3857 case SECCLASS_DCCP_SOCKET:
3858 node_perm = DCCP_SOCKET__NODE_BIND;
3859 break;
3860
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 default:
3862 node_perm = RAWIP_SOCKET__NODE_BIND;
3863 break;
3864 }
Eric Paris828dfe12008-04-17 13:17:49 -04003865
Paul Moore224dfbd2008-01-29 08:38:13 -05003866 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 if (err)
3868 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003869
Thomas Liu2bf49692009-07-14 12:14:09 -04003870 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 ad.u.net.sport = htons(snum);
3872 ad.u.net.family = family;
3873
3874 if (family == PF_INET)
3875 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3876 else
3877 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3878
Paul Moore253bfae2010-04-22 14:46:19 -04003879 err = avc_has_perm(sksec->sid, sid,
3880 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 if (err)
3882 goto out;
3883 }
3884out:
3885 return err;
3886}
3887
3888static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3889{
Paul Moore014ab192008-10-10 10:16:33 -04003890 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003891 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 int err;
3893
Paul Moore253bfae2010-04-22 14:46:19 -04003894 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 if (err)
3896 return err;
3897
3898 /*
James Morris2ee92d42006-11-13 16:09:01 -08003899 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 */
Paul Moore253bfae2010-04-22 14:46:19 -04003901 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
3902 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003903 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 struct sockaddr_in *addr4 = NULL;
3905 struct sockaddr_in6 *addr6 = NULL;
3906 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003907 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909 if (sk->sk_family == PF_INET) {
3910 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003911 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 return -EINVAL;
3913 snum = ntohs(addr4->sin_port);
3914 } else {
3915 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003916 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 return -EINVAL;
3918 snum = ntohs(addr6->sin6_port);
3919 }
3920
Paul Moore3e112172008-04-10 10:48:14 -04003921 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 if (err)
3923 goto out;
3924
Paul Moore253bfae2010-04-22 14:46:19 -04003925 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08003926 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3927
Thomas Liu2bf49692009-07-14 12:14:09 -04003928 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 ad.u.net.dport = htons(snum);
3930 ad.u.net.family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04003931 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 if (err)
3933 goto out;
3934 }
3935
Paul Moore014ab192008-10-10 10:16:33 -04003936 err = selinux_netlbl_socket_connect(sk, address);
3937
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938out:
3939 return err;
3940}
3941
3942static int selinux_socket_listen(struct socket *sock, int backlog)
3943{
Paul Moore253bfae2010-04-22 14:46:19 -04003944 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945}
3946
3947static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3948{
3949 int err;
3950 struct inode_security_struct *isec;
3951 struct inode_security_struct *newisec;
3952
Paul Moore253bfae2010-04-22 14:46:19 -04003953 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 if (err)
3955 return err;
3956
3957 newisec = SOCK_INODE(newsock)->i_security;
3958
3959 isec = SOCK_INODE(sock)->i_security;
3960 newisec->sclass = isec->sclass;
3961 newisec->sid = isec->sid;
3962 newisec->initialized = 1;
3963
3964 return 0;
3965}
3966
3967static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003968 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969{
Paul Moore253bfae2010-04-22 14:46:19 -04003970 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971}
3972
3973static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3974 int size, int flags)
3975{
Paul Moore253bfae2010-04-22 14:46:19 -04003976 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977}
3978
3979static int selinux_socket_getsockname(struct socket *sock)
3980{
Paul Moore253bfae2010-04-22 14:46:19 -04003981 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982}
3983
3984static int selinux_socket_getpeername(struct socket *sock)
3985{
Paul Moore253bfae2010-04-22 14:46:19 -04003986 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987}
3988
Eric Paris828dfe12008-04-17 13:17:49 -04003989static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990{
Paul Mooref8687af2006-10-30 15:22:15 -08003991 int err;
3992
Paul Moore253bfae2010-04-22 14:46:19 -04003993 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08003994 if (err)
3995 return err;
3996
3997 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998}
3999
4000static int selinux_socket_getsockopt(struct socket *sock, int level,
4001 int optname)
4002{
Paul Moore253bfae2010-04-22 14:46:19 -04004003 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004}
4005
4006static int selinux_socket_shutdown(struct socket *sock, int how)
4007{
Paul Moore253bfae2010-04-22 14:46:19 -04004008 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009}
4010
David S. Miller3610cda2011-01-05 15:38:53 -08004011static int selinux_socket_unix_stream_connect(struct sock *sock,
4012 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 struct sock *newsk)
4014{
David S. Miller3610cda2011-01-05 15:38:53 -08004015 struct sk_security_struct *sksec_sock = sock->sk_security;
4016 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004017 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004018 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 int err;
4020
Thomas Liu2bf49692009-07-14 12:14:09 -04004021 COMMON_AUDIT_DATA_INIT(&ad, NET);
David S. Miller3610cda2011-01-05 15:38:53 -08004022 ad.u.net.sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023
Paul Moore4d1e2452010-04-22 14:46:18 -04004024 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4025 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4027 if (err)
4028 return err;
4029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004031 sksec_new->peer_sid = sksec_sock->sid;
4032 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4033 &sksec_new->sid);
4034 if (err)
4035 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004036
Paul Moore4d1e2452010-04-22 14:46:18 -04004037 /* connecting socket */
4038 sksec_sock->peer_sid = sksec_new->sid;
4039
4040 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041}
4042
4043static int selinux_socket_unix_may_send(struct socket *sock,
4044 struct socket *other)
4045{
Paul Moore253bfae2010-04-22 14:46:19 -04004046 struct sk_security_struct *ssec = sock->sk->sk_security;
4047 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004048 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049
Thomas Liu2bf49692009-07-14 12:14:09 -04004050 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 ad.u.net.sk = other->sk;
4052
Paul Moore253bfae2010-04-22 14:46:19 -04004053 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4054 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055}
4056
Paul Mooreeffad8d2008-01-29 08:49:27 -05004057static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4058 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004059 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004060{
4061 int err;
4062 u32 if_sid;
4063 u32 node_sid;
4064
4065 err = sel_netif_sid(ifindex, &if_sid);
4066 if (err)
4067 return err;
4068 err = avc_has_perm(peer_sid, if_sid,
4069 SECCLASS_NETIF, NETIF__INGRESS, ad);
4070 if (err)
4071 return err;
4072
4073 err = sel_netnode_sid(addrp, family, &node_sid);
4074 if (err)
4075 return err;
4076 return avc_has_perm(peer_sid, node_sid,
4077 SECCLASS_NODE, NODE__RECVFROM, ad);
4078}
4079
Paul Moore220deb92008-01-29 08:38:23 -05004080static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004081 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004082{
Paul Moore277d3422008-12-31 12:54:11 -05004083 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004084 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004085 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004086 struct common_audit_data ad;
Paul Moored8395c82008-10-10 10:16:30 -04004087 char *addrp;
4088
Thomas Liu2bf49692009-07-14 12:14:09 -04004089 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Dumazet8964be42009-11-20 15:35:04 -08004090 ad.u.net.netif = skb->skb_iif;
Paul Moored8395c82008-10-10 10:16:30 -04004091 ad.u.net.family = family;
4092 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4093 if (err)
4094 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004095
Paul Moore58bfbb52009-03-27 17:10:41 -04004096 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004097 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004098 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004099 if (err)
4100 return err;
4101 }
Paul Moore220deb92008-01-29 08:38:23 -05004102
Steffen Klassertb9679a72011-02-23 12:55:21 +01004103 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4104 if (err)
4105 return err;
4106 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004107
James Morris4e5ab4c2006-06-09 00:33:33 -07004108 return err;
4109}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004110
James Morris4e5ab4c2006-06-09 00:33:33 -07004111static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4112{
Paul Moore220deb92008-01-29 08:38:23 -05004113 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004114 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004115 u16 family = sk->sk_family;
4116 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004117 struct common_audit_data ad;
Paul Moore220deb92008-01-29 08:38:23 -05004118 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004119 u8 secmark_active;
4120 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004121
James Morris4e5ab4c2006-06-09 00:33:33 -07004122 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004123 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004124
4125 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004126 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004127 family = PF_INET;
4128
Paul Moored8395c82008-10-10 10:16:30 -04004129 /* If any sort of compatibility mode is enabled then handoff processing
4130 * to the selinux_sock_rcv_skb_compat() function to deal with the
4131 * special handling. We do this in an attempt to keep this function
4132 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004133 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004134 return selinux_sock_rcv_skb_compat(sk, skb, family);
4135
4136 secmark_active = selinux_secmark_enabled();
4137 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4138 if (!secmark_active && !peerlbl_active)
4139 return 0;
4140
Thomas Liu2bf49692009-07-14 12:14:09 -04004141 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Dumazet8964be42009-11-20 15:35:04 -08004142 ad.u.net.netif = skb->skb_iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004143 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004144 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004145 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004146 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004147
Paul Moored8395c82008-10-10 10:16:30 -04004148 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004149 u32 peer_sid;
4150
4151 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4152 if (err)
4153 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004154 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004155 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004156 if (err) {
4157 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004158 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004159 }
Paul Moored621d352008-01-29 08:43:36 -05004160 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4161 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004162 if (err)
4163 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004164 }
4165
Paul Moored8395c82008-10-10 10:16:30 -04004166 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004167 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4168 PACKET__RECV, &ad);
4169 if (err)
4170 return err;
4171 }
4172
Paul Moored621d352008-01-29 08:43:36 -05004173 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174}
4175
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004176static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4177 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178{
4179 int err = 0;
4180 char *scontext;
4181 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004182 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004183 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
Paul Moore253bfae2010-04-22 14:46:19 -04004185 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4186 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004187 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004188 if (peer_sid == SECSID_NULL)
4189 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004191 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004193 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
4195 if (scontext_len > len) {
4196 err = -ERANGE;
4197 goto out_len;
4198 }
4199
4200 if (copy_to_user(optval, scontext, scontext_len))
4201 err = -EFAULT;
4202
4203out_len:
4204 if (put_user(scontext_len, optlen))
4205 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 return err;
4208}
4209
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004210static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004211{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004212 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004213 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004214
Paul Mooreaa862902008-10-10 10:16:29 -04004215 if (skb && skb->protocol == htons(ETH_P_IP))
4216 family = PF_INET;
4217 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4218 family = PF_INET6;
4219 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004220 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004221 else
4222 goto out;
4223
4224 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004225 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004226 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004227 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004228
Paul Moore75e22912008-01-29 08:38:04 -05004229out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004230 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004231 if (peer_secid == SECSID_NULL)
4232 return -EINVAL;
4233 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004234}
4235
Al Viro7d877f32005-10-21 03:20:43 -04004236static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237{
Paul Moore84914b72010-04-22 14:46:18 -04004238 struct sk_security_struct *sksec;
4239
4240 sksec = kzalloc(sizeof(*sksec), priority);
4241 if (!sksec)
4242 return -ENOMEM;
4243
4244 sksec->peer_sid = SECINITSID_UNLABELED;
4245 sksec->sid = SECINITSID_UNLABELED;
4246 selinux_netlbl_sk_security_reset(sksec);
4247 sk->sk_security = sksec;
4248
4249 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250}
4251
4252static void selinux_sk_free_security(struct sock *sk)
4253{
Paul Moore84914b72010-04-22 14:46:18 -04004254 struct sk_security_struct *sksec = sk->sk_security;
4255
4256 sk->sk_security = NULL;
4257 selinux_netlbl_sk_security_free(sksec);
4258 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259}
4260
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004261static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4262{
Eric Parisdd3e7832010-04-07 15:08:46 -04004263 struct sk_security_struct *sksec = sk->sk_security;
4264 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004265
Eric Parisdd3e7832010-04-07 15:08:46 -04004266 newsksec->sid = sksec->sid;
4267 newsksec->peer_sid = sksec->peer_sid;
4268 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004269
Eric Parisdd3e7832010-04-07 15:08:46 -04004270 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004271}
4272
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004273static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004274{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004275 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004276 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004277 else {
4278 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004279
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004280 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004281 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004282}
4283
Eric Paris828dfe12008-04-17 13:17:49 -04004284static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004285{
4286 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4287 struct sk_security_struct *sksec = sk->sk_security;
4288
David Woodhouse2148ccc2006-09-29 15:50:25 -07004289 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4290 sk->sk_family == PF_UNIX)
4291 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004292 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004293}
4294
Adrian Bunk9a673e52006-08-15 00:03:53 -07004295static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4296 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004297{
4298 struct sk_security_struct *sksec = sk->sk_security;
4299 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004300 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004301 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004302 u32 peersid;
4303
Paul Mooreaa862902008-10-10 10:16:29 -04004304 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4305 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4306 family = PF_INET;
4307
4308 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004309 if (err)
4310 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004311 if (peersid == SECSID_NULL) {
4312 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004313 req->peer_secid = SECSID_NULL;
Paul Moore389fb8002009-03-27 17:10:34 -04004314 } else {
4315 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4316 if (err)
4317 return err;
4318 req->secid = newsid;
4319 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004320 }
4321
Paul Moore389fb8002009-03-27 17:10:34 -04004322 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004323}
4324
Adrian Bunk9a673e52006-08-15 00:03:53 -07004325static void selinux_inet_csk_clone(struct sock *newsk,
4326 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004327{
4328 struct sk_security_struct *newsksec = newsk->sk_security;
4329
4330 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004331 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004332 /* NOTE: Ideally, we should also get the isec->sid for the
4333 new socket in sync, but we don't have the isec available yet.
4334 So we will wait until sock_graft to do it, by which
4335 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004336
Paul Moore9f2ad662006-11-17 17:38:53 -05004337 /* We don't need to take any sort of lock here as we are the only
4338 * thread with access to newsksec */
Paul Moore389fb8002009-03-27 17:10:34 -04004339 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004340}
4341
Paul Moore014ab192008-10-10 10:16:33 -04004342static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004343{
Paul Mooreaa862902008-10-10 10:16:29 -04004344 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004345 struct sk_security_struct *sksec = sk->sk_security;
4346
Paul Mooreaa862902008-10-10 10:16:29 -04004347 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4348 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4349 family = PF_INET;
4350
4351 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004352}
4353
Eric Paris2606fd12010-10-13 16:24:41 -04004354static int selinux_secmark_relabel_packet(u32 sid)
4355{
4356 const struct task_security_struct *__tsec;
4357 u32 tsid;
4358
4359 __tsec = current_security();
4360 tsid = __tsec->sid;
4361
4362 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4363}
4364
4365static void selinux_secmark_refcount_inc(void)
4366{
4367 atomic_inc(&selinux_secmark_refcount);
4368}
4369
4370static void selinux_secmark_refcount_dec(void)
4371{
4372 atomic_dec(&selinux_secmark_refcount);
4373}
4374
Adrian Bunk9a673e52006-08-15 00:03:53 -07004375static void selinux_req_classify_flow(const struct request_sock *req,
4376 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004377{
David S. Miller1d28f422011-03-12 00:29:39 -05004378 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004379}
4380
Paul Mooreed6d76e2009-08-28 18:12:49 -04004381static int selinux_tun_dev_create(void)
4382{
4383 u32 sid = current_sid();
4384
4385 /* we aren't taking into account the "sockcreate" SID since the socket
4386 * that is being created here is not a socket in the traditional sense,
4387 * instead it is a private sock, accessible only to the kernel, and
4388 * representing a wide range of network traffic spanning multiple
4389 * connections unlike traditional sockets - check the TUN driver to
4390 * get a better understanding of why this socket is special */
4391
4392 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4393 NULL);
4394}
4395
4396static void selinux_tun_dev_post_create(struct sock *sk)
4397{
4398 struct sk_security_struct *sksec = sk->sk_security;
4399
4400 /* we don't currently perform any NetLabel based labeling here and it
4401 * isn't clear that we would want to do so anyway; while we could apply
4402 * labeling without the support of the TUN user the resulting labeled
4403 * traffic from the other end of the connection would almost certainly
4404 * cause confusion to the TUN user that had no idea network labeling
4405 * protocols were being used */
4406
4407 /* see the comments in selinux_tun_dev_create() about why we don't use
4408 * the sockcreate SID here */
4409
4410 sksec->sid = current_sid();
4411 sksec->sclass = SECCLASS_TUN_SOCKET;
4412}
4413
4414static int selinux_tun_dev_attach(struct sock *sk)
4415{
4416 struct sk_security_struct *sksec = sk->sk_security;
4417 u32 sid = current_sid();
4418 int err;
4419
4420 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4421 TUN_SOCKET__RELABELFROM, NULL);
4422 if (err)
4423 return err;
4424 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4425 TUN_SOCKET__RELABELTO, NULL);
4426 if (err)
4427 return err;
4428
4429 sksec->sid = sid;
4430
4431 return 0;
4432}
4433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4435{
4436 int err = 0;
4437 u32 perm;
4438 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004439 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004440
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 if (skb->len < NLMSG_SPACE(0)) {
4442 err = -EINVAL;
4443 goto out;
4444 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004445 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004446
Paul Moore253bfae2010-04-22 14:46:19 -04004447 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 if (err) {
4449 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004450 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 "SELinux: unrecognized netlink message"
4452 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004453 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004454 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 err = 0;
4456 }
4457
4458 /* Ignore */
4459 if (err == -ENOENT)
4460 err = 0;
4461 goto out;
4462 }
4463
Paul Moore253bfae2010-04-22 14:46:19 -04004464 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465out:
4466 return err;
4467}
4468
4469#ifdef CONFIG_NETFILTER
4470
Paul Mooreeffad8d2008-01-29 08:49:27 -05004471static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4472 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473{
Paul Mooredfaebe92008-10-10 10:16:31 -04004474 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004475 char *addrp;
4476 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004477 struct common_audit_data ad;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004478 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004479 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004480 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004481
Paul Mooreeffad8d2008-01-29 08:49:27 -05004482 if (!selinux_policycap_netpeer)
4483 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004484
Paul Mooreeffad8d2008-01-29 08:49:27 -05004485 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004486 netlbl_active = netlbl_enabled();
4487 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004488 if (!secmark_active && !peerlbl_active)
4489 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004490
Paul Moored8395c82008-10-10 10:16:30 -04004491 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4492 return NF_DROP;
4493
Thomas Liu2bf49692009-07-14 12:14:09 -04004494 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004495 ad.u.net.netif = ifindex;
4496 ad.u.net.family = family;
4497 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4498 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
Paul Mooredfaebe92008-10-10 10:16:31 -04004500 if (peerlbl_active) {
4501 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4502 peer_sid, &ad);
4503 if (err) {
4504 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004505 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004506 }
4507 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004508
4509 if (secmark_active)
4510 if (avc_has_perm(peer_sid, skb->secmark,
4511 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4512 return NF_DROP;
4513
Paul Moore948bf852008-10-10 10:16:32 -04004514 if (netlbl_active)
4515 /* we do this in the FORWARD path and not the POST_ROUTING
4516 * path because we want to make sure we apply the necessary
4517 * labeling before IPsec is applied so we can leverage AH
4518 * protection */
4519 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4520 return NF_DROP;
4521
Paul Mooreeffad8d2008-01-29 08:49:27 -05004522 return NF_ACCEPT;
4523}
4524
4525static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4526 struct sk_buff *skb,
4527 const struct net_device *in,
4528 const struct net_device *out,
4529 int (*okfn)(struct sk_buff *))
4530{
4531 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4532}
4533
4534#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4535static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4536 struct sk_buff *skb,
4537 const struct net_device *in,
4538 const struct net_device *out,
4539 int (*okfn)(struct sk_buff *))
4540{
4541 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4542}
4543#endif /* IPV6 */
4544
Paul Moore948bf852008-10-10 10:16:32 -04004545static unsigned int selinux_ip_output(struct sk_buff *skb,
4546 u16 family)
4547{
4548 u32 sid;
4549
4550 if (!netlbl_enabled())
4551 return NF_ACCEPT;
4552
4553 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4554 * because we want to make sure we apply the necessary labeling
4555 * before IPsec is applied so we can leverage AH protection */
4556 if (skb->sk) {
4557 struct sk_security_struct *sksec = skb->sk->sk_security;
4558 sid = sksec->sid;
4559 } else
4560 sid = SECINITSID_KERNEL;
4561 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4562 return NF_DROP;
4563
4564 return NF_ACCEPT;
4565}
4566
4567static unsigned int selinux_ipv4_output(unsigned int hooknum,
4568 struct sk_buff *skb,
4569 const struct net_device *in,
4570 const struct net_device *out,
4571 int (*okfn)(struct sk_buff *))
4572{
4573 return selinux_ip_output(skb, PF_INET);
4574}
4575
Paul Mooreeffad8d2008-01-29 08:49:27 -05004576static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4577 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004578 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004579{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004580 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004581 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004582 struct common_audit_data ad;
Paul Moored8395c82008-10-10 10:16:30 -04004583 char *addrp;
4584 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004585
Paul Mooreeffad8d2008-01-29 08:49:27 -05004586 if (sk == NULL)
4587 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004588 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004589
Thomas Liu2bf49692009-07-14 12:14:09 -04004590 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004591 ad.u.net.netif = ifindex;
4592 ad.u.net.family = family;
4593 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4594 return NF_DROP;
4595
Paul Moore58bfbb52009-03-27 17:10:41 -04004596 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004597 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004598 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004599 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004600
Steffen Klassertb9679a72011-02-23 12:55:21 +01004601 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4602 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004603
Paul Mooreeffad8d2008-01-29 08:49:27 -05004604 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605}
4606
Paul Mooreeffad8d2008-01-29 08:49:27 -05004607static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4608 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004610 u32 secmark_perm;
4611 u32 peer_sid;
4612 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004613 struct common_audit_data ad;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004614 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004615 u8 secmark_active;
4616 u8 peerlbl_active;
4617
Paul Mooreeffad8d2008-01-29 08:49:27 -05004618 /* If any sort of compatibility mode is enabled then handoff processing
4619 * to the selinux_ip_postroute_compat() function to deal with the
4620 * special handling. We do this in an attempt to keep this function
4621 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004622 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004623 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004624#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004625 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4626 * packet transformation so allow the packet to pass without any checks
4627 * since we'll have another chance to perform access control checks
4628 * when the packet is on it's final way out.
4629 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4630 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004631 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004632 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004633#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004634 secmark_active = selinux_secmark_enabled();
4635 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4636 if (!secmark_active && !peerlbl_active)
4637 return NF_ACCEPT;
4638
Paul Moored8395c82008-10-10 10:16:30 -04004639 /* if the packet is being forwarded then get the peer label from the
4640 * packet itself; otherwise check to see if it is from a local
4641 * application or the kernel, if from an application get the peer label
4642 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004643 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004644 if (sk == NULL) {
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004645 if (skb->skb_iif) {
4646 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004647 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004648 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004649 } else {
4650 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004651 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004652 }
Paul Moored8395c82008-10-10 10:16:30 -04004653 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004654 struct sk_security_struct *sksec = sk->sk_security;
4655 peer_sid = sksec->sid;
4656 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004657 }
4658
Thomas Liu2bf49692009-07-14 12:14:09 -04004659 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004660 ad.u.net.netif = ifindex;
4661 ad.u.net.family = family;
4662 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004663 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004664
Paul Mooreeffad8d2008-01-29 08:49:27 -05004665 if (secmark_active)
4666 if (avc_has_perm(peer_sid, skb->secmark,
4667 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004668 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004669
4670 if (peerlbl_active) {
4671 u32 if_sid;
4672 u32 node_sid;
4673
4674 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004675 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004676 if (avc_has_perm(peer_sid, if_sid,
4677 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004678 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004679
4680 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004681 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004682 if (avc_has_perm(peer_sid, node_sid,
4683 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004684 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004685 }
4686
4687 return NF_ACCEPT;
4688}
4689
4690static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4691 struct sk_buff *skb,
4692 const struct net_device *in,
4693 const struct net_device *out,
4694 int (*okfn)(struct sk_buff *))
4695{
4696 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697}
4698
4699#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004700static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4701 struct sk_buff *skb,
4702 const struct net_device *in,
4703 const struct net_device *out,
4704 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708#endif /* IPV6 */
4709
4710#endif /* CONFIG_NETFILTER */
4711
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4713{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 int err;
4715
Eric Paris200ac532009-02-12 15:01:04 -05004716 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 if (err)
4718 return err;
4719
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004720 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721}
4722
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004723static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004725 int err;
Thomas Liu2bf49692009-07-14 12:14:09 -04004726 struct common_audit_data ad;
Patrick McHardyc53fa1e2011-03-03 10:55:40 -08004727 u32 sid;
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004728
Eric Paris200ac532009-02-12 15:01:04 -05004729 err = cap_netlink_recv(skb, capability);
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004730 if (err)
4731 return err;
4732
Thomas Liu2bf49692009-07-14 12:14:09 -04004733 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004734 ad.u.cap = capability;
4735
Patrick McHardyc53fa1e2011-03-03 10:55:40 -08004736 security_task_getsecid(current, &sid);
4737 return avc_has_perm(sid, sid, SECCLASS_CAPABILITY,
4738 CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739}
4740
4741static int ipc_alloc_security(struct task_struct *task,
4742 struct kern_ipc_perm *perm,
4743 u16 sclass)
4744{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004746 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747
James Morris89d155e2005-10-30 14:59:21 -08004748 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 if (!isec)
4750 return -ENOMEM;
4751
David Howells275bb412008-11-14 10:39:19 +11004752 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004754 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 perm->security = isec;
4756
4757 return 0;
4758}
4759
4760static void ipc_free_security(struct kern_ipc_perm *perm)
4761{
4762 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 perm->security = NULL;
4764 kfree(isec);
4765}
4766
4767static int msg_msg_alloc_security(struct msg_msg *msg)
4768{
4769 struct msg_security_struct *msec;
4770
James Morris89d155e2005-10-30 14:59:21 -08004771 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 if (!msec)
4773 return -ENOMEM;
4774
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 msec->sid = SECINITSID_UNLABELED;
4776 msg->security = msec;
4777
4778 return 0;
4779}
4780
4781static void msg_msg_free_security(struct msg_msg *msg)
4782{
4783 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
4785 msg->security = NULL;
4786 kfree(msec);
4787}
4788
4789static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004790 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004793 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004794 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 isec = ipc_perms->security;
4797
Thomas Liu2bf49692009-07-14 12:14:09 -04004798 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 ad.u.ipc_id = ipc_perms->key;
4800
David Howells275bb412008-11-14 10:39:19 +11004801 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802}
4803
4804static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4805{
4806 return msg_msg_alloc_security(msg);
4807}
4808
4809static void selinux_msg_msg_free_security(struct msg_msg *msg)
4810{
4811 msg_msg_free_security(msg);
4812}
4813
4814/* message queue security operations */
4815static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4816{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004818 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004819 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 int rc;
4821
4822 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4823 if (rc)
4824 return rc;
4825
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 isec = msq->q_perm.security;
4827
Thomas Liu2bf49692009-07-14 12:14:09 -04004828 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004829 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
David Howells275bb412008-11-14 10:39:19 +11004831 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 MSGQ__CREATE, &ad);
4833 if (rc) {
4834 ipc_free_security(&msq->q_perm);
4835 return rc;
4836 }
4837 return 0;
4838}
4839
4840static void selinux_msg_queue_free_security(struct msg_queue *msq)
4841{
4842 ipc_free_security(&msq->q_perm);
4843}
4844
4845static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4846{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004848 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004849 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 isec = msq->q_perm.security;
4852
Thomas Liu2bf49692009-07-14 12:14:09 -04004853 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 ad.u.ipc_id = msq->q_perm.key;
4855
David Howells275bb412008-11-14 10:39:19 +11004856 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 MSGQ__ASSOCIATE, &ad);
4858}
4859
4860static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4861{
4862 int err;
4863 int perms;
4864
Eric Paris828dfe12008-04-17 13:17:49 -04004865 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 case IPC_INFO:
4867 case MSG_INFO:
4868 /* No specific object, just general system-wide information. */
4869 return task_has_system(current, SYSTEM__IPC_INFO);
4870 case IPC_STAT:
4871 case MSG_STAT:
4872 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4873 break;
4874 case IPC_SET:
4875 perms = MSGQ__SETATTR;
4876 break;
4877 case IPC_RMID:
4878 perms = MSGQ__DESTROY;
4879 break;
4880 default:
4881 return 0;
4882 }
4883
Stephen Smalley6af963f2005-05-01 08:58:39 -07004884 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 return err;
4886}
4887
4888static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4889{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 struct ipc_security_struct *isec;
4891 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004892 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004893 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 int rc;
4895
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 isec = msq->q_perm.security;
4897 msec = msg->security;
4898
4899 /*
4900 * First time through, need to assign label to the message
4901 */
4902 if (msec->sid == SECINITSID_UNLABELED) {
4903 /*
4904 * Compute new sid based on current process and
4905 * message queue this message will be stored in
4906 */
David Howells275bb412008-11-14 10:39:19 +11004907 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05004908 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 if (rc)
4910 return rc;
4911 }
4912
Thomas Liu2bf49692009-07-14 12:14:09 -04004913 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 ad.u.ipc_id = msq->q_perm.key;
4915
4916 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004917 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 MSGQ__WRITE, &ad);
4919 if (!rc)
4920 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11004921 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
4922 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 if (!rc)
4924 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11004925 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
4926 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927
4928 return rc;
4929}
4930
4931static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
4932 struct task_struct *target,
4933 long type, int mode)
4934{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 struct ipc_security_struct *isec;
4936 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004937 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004938 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 int rc;
4940
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 isec = msq->q_perm.security;
4942 msec = msg->security;
4943
Thomas Liu2bf49692009-07-14 12:14:09 -04004944 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004945 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946
David Howells275bb412008-11-14 10:39:19 +11004947 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 SECCLASS_MSGQ, MSGQ__READ, &ad);
4949 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11004950 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 SECCLASS_MSG, MSG__RECEIVE, &ad);
4952 return rc;
4953}
4954
4955/* Shared Memory security operations */
4956static int selinux_shm_alloc_security(struct shmid_kernel *shp)
4957{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004959 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004960 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 int rc;
4962
4963 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
4964 if (rc)
4965 return rc;
4966
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 isec = shp->shm_perm.security;
4968
Thomas Liu2bf49692009-07-14 12:14:09 -04004969 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004970 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971
David Howells275bb412008-11-14 10:39:19 +11004972 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 SHM__CREATE, &ad);
4974 if (rc) {
4975 ipc_free_security(&shp->shm_perm);
4976 return rc;
4977 }
4978 return 0;
4979}
4980
4981static void selinux_shm_free_security(struct shmid_kernel *shp)
4982{
4983 ipc_free_security(&shp->shm_perm);
4984}
4985
4986static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
4987{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004989 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004990 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 isec = shp->shm_perm.security;
4993
Thomas Liu2bf49692009-07-14 12:14:09 -04004994 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 ad.u.ipc_id = shp->shm_perm.key;
4996
David Howells275bb412008-11-14 10:39:19 +11004997 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 SHM__ASSOCIATE, &ad);
4999}
5000
5001/* Note, at this point, shp is locked down */
5002static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5003{
5004 int perms;
5005 int err;
5006
Eric Paris828dfe12008-04-17 13:17:49 -04005007 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 case IPC_INFO:
5009 case SHM_INFO:
5010 /* No specific object, just general system-wide information. */
5011 return task_has_system(current, SYSTEM__IPC_INFO);
5012 case IPC_STAT:
5013 case SHM_STAT:
5014 perms = SHM__GETATTR | SHM__ASSOCIATE;
5015 break;
5016 case IPC_SET:
5017 perms = SHM__SETATTR;
5018 break;
5019 case SHM_LOCK:
5020 case SHM_UNLOCK:
5021 perms = SHM__LOCK;
5022 break;
5023 case IPC_RMID:
5024 perms = SHM__DESTROY;
5025 break;
5026 default:
5027 return 0;
5028 }
5029
Stephen Smalley6af963f2005-05-01 08:58:39 -07005030 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 return err;
5032}
5033
5034static int selinux_shm_shmat(struct shmid_kernel *shp,
5035 char __user *shmaddr, int shmflg)
5036{
5037 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038
5039 if (shmflg & SHM_RDONLY)
5040 perms = SHM__READ;
5041 else
5042 perms = SHM__READ | SHM__WRITE;
5043
Stephen Smalley6af963f2005-05-01 08:58:39 -07005044 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045}
5046
5047/* Semaphore security operations */
5048static int selinux_sem_alloc_security(struct sem_array *sma)
5049{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005051 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005052 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 int rc;
5054
5055 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5056 if (rc)
5057 return rc;
5058
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 isec = sma->sem_perm.security;
5060
Thomas Liu2bf49692009-07-14 12:14:09 -04005061 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005062 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063
David Howells275bb412008-11-14 10:39:19 +11005064 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 SEM__CREATE, &ad);
5066 if (rc) {
5067 ipc_free_security(&sma->sem_perm);
5068 return rc;
5069 }
5070 return 0;
5071}
5072
5073static void selinux_sem_free_security(struct sem_array *sma)
5074{
5075 ipc_free_security(&sma->sem_perm);
5076}
5077
5078static int selinux_sem_associate(struct sem_array *sma, int semflg)
5079{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005081 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005082 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 isec = sma->sem_perm.security;
5085
Thomas Liu2bf49692009-07-14 12:14:09 -04005086 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 ad.u.ipc_id = sma->sem_perm.key;
5088
David Howells275bb412008-11-14 10:39:19 +11005089 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 SEM__ASSOCIATE, &ad);
5091}
5092
5093/* Note, at this point, sma is locked down */
5094static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5095{
5096 int err;
5097 u32 perms;
5098
Eric Paris828dfe12008-04-17 13:17:49 -04005099 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 case IPC_INFO:
5101 case SEM_INFO:
5102 /* No specific object, just general system-wide information. */
5103 return task_has_system(current, SYSTEM__IPC_INFO);
5104 case GETPID:
5105 case GETNCNT:
5106 case GETZCNT:
5107 perms = SEM__GETATTR;
5108 break;
5109 case GETVAL:
5110 case GETALL:
5111 perms = SEM__READ;
5112 break;
5113 case SETVAL:
5114 case SETALL:
5115 perms = SEM__WRITE;
5116 break;
5117 case IPC_RMID:
5118 perms = SEM__DESTROY;
5119 break;
5120 case IPC_SET:
5121 perms = SEM__SETATTR;
5122 break;
5123 case IPC_STAT:
5124 case SEM_STAT:
5125 perms = SEM__GETATTR | SEM__ASSOCIATE;
5126 break;
5127 default:
5128 return 0;
5129 }
5130
Stephen Smalley6af963f2005-05-01 08:58:39 -07005131 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 return err;
5133}
5134
5135static int selinux_sem_semop(struct sem_array *sma,
5136 struct sembuf *sops, unsigned nsops, int alter)
5137{
5138 u32 perms;
5139
5140 if (alter)
5141 perms = SEM__READ | SEM__WRITE;
5142 else
5143 perms = SEM__READ;
5144
Stephen Smalley6af963f2005-05-01 08:58:39 -07005145 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146}
5147
5148static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5149{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 u32 av = 0;
5151
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 av = 0;
5153 if (flag & S_IRUGO)
5154 av |= IPC__UNIX_READ;
5155 if (flag & S_IWUGO)
5156 av |= IPC__UNIX_WRITE;
5157
5158 if (av == 0)
5159 return 0;
5160
Stephen Smalley6af963f2005-05-01 08:58:39 -07005161 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162}
5163
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005164static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5165{
5166 struct ipc_security_struct *isec = ipcp->security;
5167 *secid = isec->sid;
5168}
5169
Eric Paris828dfe12008-04-17 13:17:49 -04005170static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171{
5172 if (inode)
5173 inode_doinit_with_dentry(inode, dentry);
5174}
5175
5176static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005177 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178{
David Howells275bb412008-11-14 10:39:19 +11005179 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005180 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005182 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183
5184 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005185 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 if (error)
5187 return error;
5188 }
5189
David Howells275bb412008-11-14 10:39:19 +11005190 rcu_read_lock();
5191 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192
5193 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005194 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005196 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005198 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005200 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005201 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005202 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005203 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005204 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 else
David Howells275bb412008-11-14 10:39:19 +11005206 goto invalid;
5207 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208
5209 if (!sid)
5210 return 0;
5211
Al Viro04ff9702007-03-12 16:17:58 +00005212 error = security_sid_to_context(sid, value, &len);
5213 if (error)
5214 return error;
5215 return len;
David Howells275bb412008-11-14 10:39:19 +11005216
5217invalid:
5218 rcu_read_unlock();
5219 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220}
5221
5222static int selinux_setprocattr(struct task_struct *p,
5223 char *name, void *value, size_t size)
5224{
5225 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005226 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005227 struct cred *new;
5228 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 int error;
5230 char *str = value;
5231
5232 if (current != p) {
5233 /* SELinux only allows a process to change its own
5234 security attributes. */
5235 return -EACCES;
5236 }
5237
5238 /*
5239 * Basic control over ability to set these attributes at all.
5240 * current == p, but we'll pass them separately in case the
5241 * above restriction is ever removed.
5242 */
5243 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005244 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005246 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005247 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005248 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005249 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005250 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005252 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 else
5254 error = -EINVAL;
5255 if (error)
5256 return error;
5257
5258 /* Obtain a SID for the context, if one was specified. */
5259 if (size && str[1] && str[1] != '\n') {
5260 if (str[size-1] == '\n') {
5261 str[size-1] = 0;
5262 size--;
5263 }
5264 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005265 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5266 if (!capable(CAP_MAC_ADMIN))
5267 return error;
5268 error = security_context_to_sid_force(value, size,
5269 &sid);
5270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 if (error)
5272 return error;
5273 }
5274
David Howellsd84f4f92008-11-14 10:39:23 +11005275 new = prepare_creds();
5276 if (!new)
5277 return -ENOMEM;
5278
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 /* Permission checking based on the specified context is
5280 performed during the actual operation (execve,
5281 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005282 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 checks and may_create for the file creation checks. The
5284 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005285 tsec = new->security;
5286 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005288 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005290 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005291 error = may_create_key(sid, p);
5292 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005293 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005294 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005295 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005296 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005297 } else if (!strcmp(name, "current")) {
5298 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005300 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005301
David Howellsd84f4f92008-11-14 10:39:23 +11005302 /* Only allow single threaded processes to change context */
5303 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005304 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005305 error = security_bounded_transition(tsec->sid, sid);
5306 if (error)
5307 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
5310 /* Check permissions for the transition. */
5311 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005312 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005314 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
5316 /* Check for ptracing, and update the task SID if ok.
5317 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005318 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 task_lock(p);
Tejun Heo06d98472011-06-17 16:50:40 +02005320 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005321 if (tracer)
5322 ptsid = task_sid(tracer);
5323 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324
David Howellsd84f4f92008-11-14 10:39:23 +11005325 if (tracer) {
5326 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5327 PROCESS__PTRACE, NULL);
5328 if (error)
5329 goto abort_change;
5330 }
5331
5332 tsec->sid = sid;
5333 } else {
5334 error = -EINVAL;
5335 goto abort_change;
5336 }
5337
5338 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005340
5341abort_change:
5342 abort_creds(new);
5343 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344}
5345
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005346static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5347{
5348 return security_sid_to_context(secid, secdata, seclen);
5349}
5350
David Howells7bf570d2008-04-29 20:52:51 +01005351static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005352{
5353 return security_context_to_sid(secdata, seclen, secid);
5354}
5355
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005356static void selinux_release_secctx(char *secdata, u32 seclen)
5357{
Paul Moore088999e2007-08-01 11:12:58 -04005358 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005359}
5360
David P. Quigley1ee65e32009-09-03 14:25:57 -04005361/*
5362 * called with inode->i_mutex locked
5363 */
5364static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5365{
5366 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5367}
5368
5369/*
5370 * called with inode->i_mutex locked
5371 */
5372static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5373{
5374 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5375}
5376
5377static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5378{
5379 int len = 0;
5380 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5381 ctx, true);
5382 if (len < 0)
5383 return len;
5384 *ctxlen = len;
5385 return 0;
5386}
Michael LeMayd7200242006-06-22 14:47:17 -07005387#ifdef CONFIG_KEYS
5388
David Howellsd84f4f92008-11-14 10:39:23 +11005389static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005390 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005391{
David Howellsd84f4f92008-11-14 10:39:23 +11005392 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005393 struct key_security_struct *ksec;
5394
5395 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5396 if (!ksec)
5397 return -ENOMEM;
5398
David Howellsd84f4f92008-11-14 10:39:23 +11005399 tsec = cred->security;
5400 if (tsec->keycreate_sid)
5401 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005402 else
David Howellsd84f4f92008-11-14 10:39:23 +11005403 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005404
David Howells275bb412008-11-14 10:39:19 +11005405 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005406 return 0;
5407}
5408
5409static void selinux_key_free(struct key *k)
5410{
5411 struct key_security_struct *ksec = k->security;
5412
5413 k->security = NULL;
5414 kfree(ksec);
5415}
5416
5417static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005418 const struct cred *cred,
5419 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005420{
5421 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005422 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005423 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005424
5425 /* if no specific permissions are requested, we skip the
5426 permission check. No serious, additional covert channels
5427 appear to be created. */
5428 if (perm == 0)
5429 return 0;
5430
David Howellsd84f4f92008-11-14 10:39:23 +11005431 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005432
5433 key = key_ref_to_ptr(key_ref);
5434 ksec = key->security;
5435
5436 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005437}
5438
David Howells70a5bb72008-04-29 01:01:26 -07005439static int selinux_key_getsecurity(struct key *key, char **_buffer)
5440{
5441 struct key_security_struct *ksec = key->security;
5442 char *context = NULL;
5443 unsigned len;
5444 int rc;
5445
5446 rc = security_sid_to_context(ksec->sid, &context, &len);
5447 if (!rc)
5448 rc = len;
5449 *_buffer = context;
5450 return rc;
5451}
5452
Michael LeMayd7200242006-06-22 14:47:17 -07005453#endif
5454
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005456 .name = "selinux",
5457
Ingo Molnar9e488582009-05-07 19:26:19 +10005458 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005459 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005461 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 .capable = selinux_capable,
5463 .quotactl = selinux_quotactl,
5464 .quota_on = selinux_quota_on,
5465 .syslog = selinux_syslog,
5466 .vm_enough_memory = selinux_vm_enough_memory,
5467
5468 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005469 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
David Howellsa6f76f22008-11-14 10:39:24 +11005471 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005472 .bprm_committing_creds = selinux_bprm_committing_creds,
5473 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 .bprm_secureexec = selinux_bprm_secureexec,
5475
5476 .sb_alloc_security = selinux_sb_alloc_security,
5477 .sb_free_security = selinux_sb_free_security,
5478 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005479 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005480 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005481 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 .sb_statfs = selinux_sb_statfs,
5483 .sb_mount = selinux_mount,
5484 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005485 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005486 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005487 .sb_parse_opts_str = selinux_parse_opts_str,
5488
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489
5490 .inode_alloc_security = selinux_inode_alloc_security,
5491 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005492 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 .inode_unlink = selinux_inode_unlink,
5496 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 .inode_rmdir = selinux_inode_rmdir,
5499 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 .inode_readlink = selinux_inode_readlink,
5502 .inode_follow_link = selinux_inode_follow_link,
5503 .inode_permission = selinux_inode_permission,
5504 .inode_setattr = selinux_inode_setattr,
5505 .inode_getattr = selinux_inode_getattr,
5506 .inode_setxattr = selinux_inode_setxattr,
5507 .inode_post_setxattr = selinux_inode_post_setxattr,
5508 .inode_getxattr = selinux_inode_getxattr,
5509 .inode_listxattr = selinux_inode_listxattr,
5510 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005511 .inode_getsecurity = selinux_inode_getsecurity,
5512 .inode_setsecurity = selinux_inode_setsecurity,
5513 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005514 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
5516 .file_permission = selinux_file_permission,
5517 .file_alloc_security = selinux_file_alloc_security,
5518 .file_free_security = selinux_file_free_security,
5519 .file_ioctl = selinux_file_ioctl,
5520 .file_mmap = selinux_file_mmap,
5521 .file_mprotect = selinux_file_mprotect,
5522 .file_lock = selinux_file_lock,
5523 .file_fcntl = selinux_file_fcntl,
5524 .file_set_fowner = selinux_file_set_fowner,
5525 .file_send_sigiotask = selinux_file_send_sigiotask,
5526 .file_receive = selinux_file_receive,
5527
Eric Paris828dfe12008-04-17 13:17:49 -04005528 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005529
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005531 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005532 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005533 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005534 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005535 .kernel_act_as = selinux_kernel_act_as,
5536 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005537 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 .task_setpgid = selinux_task_setpgid,
5539 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005540 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005541 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005543 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005544 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 .task_setrlimit = selinux_task_setrlimit,
5546 .task_setscheduler = selinux_task_setscheduler,
5547 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005548 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 .task_kill = selinux_task_kill,
5550 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005551 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552
5553 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005554 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555
5556 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5557 .msg_msg_free_security = selinux_msg_msg_free_security,
5558
5559 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5560 .msg_queue_free_security = selinux_msg_queue_free_security,
5561 .msg_queue_associate = selinux_msg_queue_associate,
5562 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5563 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5564 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5565
5566 .shm_alloc_security = selinux_shm_alloc_security,
5567 .shm_free_security = selinux_shm_free_security,
5568 .shm_associate = selinux_shm_associate,
5569 .shm_shmctl = selinux_shm_shmctl,
5570 .shm_shmat = selinux_shm_shmat,
5571
Eric Paris828dfe12008-04-17 13:17:49 -04005572 .sem_alloc_security = selinux_sem_alloc_security,
5573 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 .sem_associate = selinux_sem_associate,
5575 .sem_semctl = selinux_sem_semctl,
5576 .sem_semop = selinux_sem_semop,
5577
Eric Paris828dfe12008-04-17 13:17:49 -04005578 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579
Eric Paris828dfe12008-04-17 13:17:49 -04005580 .getprocattr = selinux_getprocattr,
5581 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005583 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005584 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005585 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005586 .inode_notifysecctx = selinux_inode_notifysecctx,
5587 .inode_setsecctx = selinux_inode_setsecctx,
5588 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005589
Eric Paris828dfe12008-04-17 13:17:49 -04005590 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 .unix_may_send = selinux_socket_unix_may_send,
5592
5593 .socket_create = selinux_socket_create,
5594 .socket_post_create = selinux_socket_post_create,
5595 .socket_bind = selinux_socket_bind,
5596 .socket_connect = selinux_socket_connect,
5597 .socket_listen = selinux_socket_listen,
5598 .socket_accept = selinux_socket_accept,
5599 .socket_sendmsg = selinux_socket_sendmsg,
5600 .socket_recvmsg = selinux_socket_recvmsg,
5601 .socket_getsockname = selinux_socket_getsockname,
5602 .socket_getpeername = selinux_socket_getpeername,
5603 .socket_getsockopt = selinux_socket_getsockopt,
5604 .socket_setsockopt = selinux_socket_setsockopt,
5605 .socket_shutdown = selinux_socket_shutdown,
5606 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005607 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5608 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 .sk_alloc_security = selinux_sk_alloc_security,
5610 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005611 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005612 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005613 .sock_graft = selinux_sock_graft,
5614 .inet_conn_request = selinux_inet_conn_request,
5615 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005616 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005617 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5618 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5619 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005620 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005621 .tun_dev_create = selinux_tun_dev_create,
5622 .tun_dev_post_create = selinux_tun_dev_post_create,
5623 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005624
5625#ifdef CONFIG_SECURITY_NETWORK_XFRM
5626 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5627 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5628 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005629 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005630 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5631 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005632 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005633 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005634 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005635 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005637
5638#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005639 .key_alloc = selinux_key_alloc,
5640 .key_free = selinux_key_free,
5641 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005642 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005643#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005644
5645#ifdef CONFIG_AUDIT
5646 .audit_rule_init = selinux_audit_rule_init,
5647 .audit_rule_known = selinux_audit_rule_known,
5648 .audit_rule_match = selinux_audit_rule_match,
5649 .audit_rule_free = selinux_audit_rule_free,
5650#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651};
5652
5653static __init int selinux_init(void)
5654{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005655 if (!security_module_enable(&selinux_ops)) {
5656 selinux_enabled = 0;
5657 return 0;
5658 }
5659
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 if (!selinux_enabled) {
5661 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5662 return 0;
5663 }
5664
5665 printk(KERN_INFO "SELinux: Initializing.\n");
5666
5667 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005668 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005670 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5671
James Morris7cae7e22006-03-22 00:09:22 -08005672 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5673 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005674 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 avc_init();
5676
Eric Paris828dfe12008-04-17 13:17:49 -04005677 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 panic("SELinux: Unable to register with kernel.\n");
5679
Eric Paris828dfe12008-04-17 13:17:49 -04005680 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005681 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005682 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005683 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005684
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 return 0;
5686}
5687
Al Viroe8c26252010-03-23 06:36:54 -04005688static void delayed_superblock_init(struct super_block *sb, void *unused)
5689{
5690 superblock_doinit(sb, NULL);
5691}
5692
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693void selinux_complete_init(void)
5694{
Eric Parisfadcdb42007-02-22 18:11:31 -05005695 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696
5697 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005698 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005699 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700}
5701
5702/* SELinux requires early initialization in order to label
5703 all processes and objects when they are created. */
5704security_initcall(selinux_init);
5705
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005706#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
Paul Mooreeffad8d2008-01-29 08:49:27 -05005708static struct nf_hook_ops selinux_ipv4_ops[] = {
5709 {
5710 .hook = selinux_ipv4_postroute,
5711 .owner = THIS_MODULE,
5712 .pf = PF_INET,
5713 .hooknum = NF_INET_POST_ROUTING,
5714 .priority = NF_IP_PRI_SELINUX_LAST,
5715 },
5716 {
5717 .hook = selinux_ipv4_forward,
5718 .owner = THIS_MODULE,
5719 .pf = PF_INET,
5720 .hooknum = NF_INET_FORWARD,
5721 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005722 },
5723 {
5724 .hook = selinux_ipv4_output,
5725 .owner = THIS_MODULE,
5726 .pf = PF_INET,
5727 .hooknum = NF_INET_LOCAL_OUT,
5728 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730};
5731
5732#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5733
Paul Mooreeffad8d2008-01-29 08:49:27 -05005734static struct nf_hook_ops selinux_ipv6_ops[] = {
5735 {
5736 .hook = selinux_ipv6_postroute,
5737 .owner = THIS_MODULE,
5738 .pf = PF_INET6,
5739 .hooknum = NF_INET_POST_ROUTING,
5740 .priority = NF_IP6_PRI_SELINUX_LAST,
5741 },
5742 {
5743 .hook = selinux_ipv6_forward,
5744 .owner = THIS_MODULE,
5745 .pf = PF_INET6,
5746 .hooknum = NF_INET_FORWARD,
5747 .priority = NF_IP6_PRI_SELINUX_FIRST,
5748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749};
5750
5751#endif /* IPV6 */
5752
5753static int __init selinux_nf_ip_init(void)
5754{
5755 int err = 0;
5756
5757 if (!selinux_enabled)
5758 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005759
5760 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5761
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005762 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5763 if (err)
5764 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765
5766#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005767 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5768 if (err)
5769 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005771
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772out:
5773 return err;
5774}
5775
5776__initcall(selinux_nf_ip_init);
5777
5778#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5779static void selinux_nf_ip_exit(void)
5780{
Eric Parisfadcdb42007-02-22 18:11:31 -05005781 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005783 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005785 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786#endif /* IPV6 */
5787}
5788#endif
5789
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005790#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5793#define selinux_nf_ip_exit()
5794#endif
5795
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005796#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797
5798#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005799static int selinux_disabled;
5800
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801int selinux_disable(void)
5802{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803 if (ss_initialized) {
5804 /* Not permitted after initial policy load. */
5805 return -EINVAL;
5806 }
5807
5808 if (selinux_disabled) {
5809 /* Only do this once. */
5810 return -EINVAL;
5811 }
5812
5813 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5814
5815 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005816 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08005818 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819
Eric Parisaf8ff042009-09-20 21:23:01 -04005820 /* Try to destroy the avc node cache */
5821 avc_disable();
5822
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 /* Unregister netfilter hooks. */
5824 selinux_nf_ip_exit();
5825
5826 /* Unregister selinuxfs. */
5827 exit_sel_fs();
5828
5829 return 0;
5830}
5831#endif