blob: 421c990a20b280d6ff67c0cbfa33ad706cb71baf [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 Sharma60063492011-07-26 16:09:06 -070060#include <linux/atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/bitops.h>
62#include <linux/interrupt.h>
63#include <linux/netdevice.h> /* for network interface checks */
64#include <linux/netlink.h>
65#include <linux/tcp.h>
66#include <linux/udp.h>
James Morris2ee92d42006-11-13 16:09:01 -080067#include <linux/dccp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <linux/quota.h>
69#include <linux/un.h> /* for Unix socket types */
70#include <net/af_unix.h> /* for Unix socket types */
71#include <linux/parser.h>
72#include <linux/nfs_mount.h>
73#include <net/ipv6.h>
74#include <linux/hugetlb.h>
75#include <linux/personality.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#include <linux/audit.h>
Eric Paris6931dfc2005-06-30 02:58:51 -070077#include <linux/string.h>
Catherine Zhang877ce7c2006-06-29 12:27:47 -070078#include <linux/selinux.h>
Eric Paris23970742006-09-25 23:32:01 -070079#include <linux/mutex.h>
Frank Mayharf06febc2008-09-12 09:54:39 -070080#include <linux/posix-timers.h>
Kees Cook00234592010-02-03 15:36:43 -080081#include <linux/syslog.h>
Serge E. Hallyn34867402011-03-23 16:43:17 -070082#include <linux/user_namespace.h>
Paul Gortmaker44fc7ea2011-05-26 20:52:10 -040083#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85#include "avc.h"
86#include "objsec.h"
87#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050088#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040089#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080090#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050091#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020092#include "audit.h"
James Morris7b98a582011-08-30 12:52:32 +100093#include "avc_ss.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
David P. Quigley11689d42009-01-16 09:22:03 -050095#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050096
James Morris20510f22007-10-16 23:31:32 -070097extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Paul Moored621d352008-01-29 08:43:36 -050099/* SECMARK reference count */
James Morris56a4ca92011-08-17 11:08:43 +1000100static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
Paul Moored621d352008-01-29 08:43:36 -0500101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400103int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105static int __init enforcing_setup(char *str)
106{
Eric Parisf5269712008-05-14 11:27:45 -0400107 unsigned long enforcing;
108 if (!strict_strtoul(str, 0, &enforcing))
109 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 return 1;
111}
112__setup("enforcing=", enforcing_setup);
113#endif
114
115#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
116int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
117
118static int __init selinux_enabled_setup(char *str)
119{
Eric Parisf5269712008-05-14 11:27:45 -0400120 unsigned long enabled;
121 if (!strict_strtoul(str, 0, &enabled))
122 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return 1;
124}
125__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400126#else
127int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#endif
129
Christoph Lametere18b8902006-12-06 20:33:20 -0800130static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800131
Paul Moored621d352008-01-29 08:43:36 -0500132/**
133 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
134 *
135 * Description:
136 * This function checks the SECMARK reference counter to see if any SECMARK
137 * targets are currently configured, if the reference counter is greater than
138 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
139 * enabled, false (0) if SECMARK is disabled.
140 *
141 */
142static int selinux_secmark_enabled(void)
143{
144 return (atomic_read(&selinux_secmark_refcount) > 0);
145}
146
David Howellsd84f4f92008-11-14 10:39:23 +1100147/*
148 * initialise the security for the init task
149 */
150static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
David Howells3b11a1d2008-11-14 10:39:26 +1100152 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 struct task_security_struct *tsec;
154
James Morris89d155e2005-10-30 14:59:21 -0800155 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100157 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
David Howellsd84f4f92008-11-14 10:39:23 +1100159 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100160 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}
162
David Howells275bb412008-11-14 10:39:19 +1100163/*
David Howells88e67f32008-11-14 10:39:21 +1100164 * get the security ID of a set of credentials
165 */
166static inline u32 cred_sid(const struct cred *cred)
167{
168 const struct task_security_struct *tsec;
169
170 tsec = cred->security;
171 return tsec->sid;
172}
173
174/*
David Howells3b11a1d2008-11-14 10:39:26 +1100175 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100176 */
177static inline u32 task_sid(const struct task_struct *task)
178{
David Howells275bb412008-11-14 10:39:19 +1100179 u32 sid;
180
181 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100182 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100183 rcu_read_unlock();
184 return sid;
185}
186
187/*
David Howells3b11a1d2008-11-14 10:39:26 +1100188 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100189 */
190static inline u32 current_sid(void)
191{
Paul Moore5fb49872010-04-22 14:46:19 -0400192 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +1100193
194 return tsec->sid;
195}
196
David Howells88e67f32008-11-14 10:39:21 +1100197/* Allocate and free functions for each kind of security blob. */
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199static int inode_alloc_security(struct inode *inode)
200{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100202 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Josef Bacika02fe132008-04-04 09:35:05 +1100204 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 if (!isec)
206 return -ENOMEM;
207
Eric Paris23970742006-09-25 23:32:01 -0700208 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 isec->inode = inode;
211 isec->sid = SECINITSID_UNLABELED;
212 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100213 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 inode->i_security = isec;
215
216 return 0;
217}
218
219static void inode_free_security(struct inode *inode)
220{
221 struct inode_security_struct *isec = inode->i_security;
222 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 spin_lock(&sbsec->isec_lock);
225 if (!list_empty(&isec->list))
226 list_del_init(&isec->list);
227 spin_unlock(&sbsec->isec_lock);
228
229 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800230 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
232
233static int file_alloc_security(struct file *file)
234{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100236 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800238 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if (!fsec)
240 return -ENOMEM;
241
David Howells275bb412008-11-14 10:39:19 +1100242 fsec->sid = sid;
243 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 file->f_security = fsec;
245
246 return 0;
247}
248
249static void file_free_security(struct file *file)
250{
251 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 file->f_security = NULL;
253 kfree(fsec);
254}
255
256static int superblock_alloc_security(struct super_block *sb)
257{
258 struct superblock_security_struct *sbsec;
259
James Morris89d155e2005-10-30 14:59:21 -0800260 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 if (!sbsec)
262 return -ENOMEM;
263
Eric Parisbc7e9822006-09-25 23:32:02 -0700264 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 INIT_LIST_HEAD(&sbsec->isec_head);
266 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 sbsec->sb = sb;
268 sbsec->sid = SECINITSID_UNLABELED;
269 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700270 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sb->s_security = sbsec;
272
273 return 0;
274}
275
276static void superblock_free_security(struct super_block *sb)
277{
278 struct superblock_security_struct *sbsec = sb->s_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 sb->s_security = NULL;
280 kfree(sbsec);
281}
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283/* The file system's label must be initialized prior to use. */
284
Stephen Hemminger634a5392010-03-04 21:59:03 -0800285static const char *labeling_behaviors[6] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 "uses xattr",
287 "uses transition SIDs",
288 "uses task SIDs",
289 "uses genfs_contexts",
290 "not configured for labeling",
291 "uses mountpoint labeling",
292};
293
294static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
295
296static inline int inode_doinit(struct inode *inode)
297{
298 return inode_doinit_with_dentry(inode, NULL);
299}
300
301enum {
Eric Paris31e87932007-09-19 17:19:12 -0400302 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 Opt_context = 1,
304 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500305 Opt_defcontext = 3,
306 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500307 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308};
309
Steven Whitehousea447c092008-10-13 10:46:57 +0100310static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400311 {Opt_context, CONTEXT_STR "%s"},
312 {Opt_fscontext, FSCONTEXT_STR "%s"},
313 {Opt_defcontext, DEFCONTEXT_STR "%s"},
314 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500315 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400316 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317};
318
319#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
320
Eric Parisc312feb2006-07-10 04:43:53 -0700321static int may_context_mount_sb_relabel(u32 sid,
322 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100323 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700324{
David Howells275bb412008-11-14 10:39:19 +1100325 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700326 int rc;
327
328 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
329 FILESYSTEM__RELABELFROM, NULL);
330 if (rc)
331 return rc;
332
333 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
334 FILESYSTEM__RELABELTO, NULL);
335 return rc;
336}
337
Eric Paris08089252006-07-10 04:43:55 -0700338static int may_context_mount_inode_relabel(u32 sid,
339 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100340 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700341{
David Howells275bb412008-11-14 10:39:19 +1100342 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700343 int rc;
344 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
345 FILESYSTEM__RELABELFROM, NULL);
346 if (rc)
347 return rc;
348
349 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
350 FILESYSTEM__ASSOCIATE, NULL);
351 return rc;
352}
353
Eric Parisc9180a52007-11-30 13:00:35 -0500354static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356 struct superblock_security_struct *sbsec = sb->s_security;
357 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500358 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 int rc = 0;
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
362 /* Make sure that the xattr handler exists and that no
363 error other than -ENODATA is returned by getxattr on
364 the root directory. -ENODATA is ok, as this may be
365 the first boot of the SELinux kernel before we have
366 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500367 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
369 "xattr support\n", sb->s_id, sb->s_type->name);
370 rc = -EOPNOTSUPP;
371 goto out;
372 }
Eric Parisc9180a52007-11-30 13:00:35 -0500373 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 if (rc < 0 && rc != -ENODATA) {
375 if (rc == -EOPNOTSUPP)
376 printk(KERN_WARNING "SELinux: (dev %s, type "
377 "%s) has no security xattr handler\n",
378 sb->s_id, sb->s_type->name);
379 else
380 printk(KERN_WARNING "SELinux: (dev %s, type "
381 "%s) getxattr errno %d\n", sb->s_id,
382 sb->s_type->name, -rc);
383 goto out;
384 }
385 }
386
David P. Quigley11689d42009-01-16 09:22:03 -0500387 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Eric Parisc9180a52007-11-30 13:00:35 -0500389 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500390 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500392 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500393 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 sb->s_id, sb->s_type->name,
395 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
David P. Quigley11689d42009-01-16 09:22:03 -0500397 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
398 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
399 sbsec->behavior == SECURITY_FS_USE_NONE ||
400 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
401 sbsec->flags &= ~SE_SBLABELSUPP;
402
David P. Quigleyddd29ec2009-09-09 14:25:37 -0400403 /* Special handling for sysfs. Is genfs but also has setxattr handler*/
404 if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
405 sbsec->flags |= SE_SBLABELSUPP;
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500408 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
410 /* Initialize any other inodes associated with the superblock, e.g.
411 inodes created prior to initial policy load or inodes created
412 during get_sb by a pseudo filesystem that directly
413 populates itself. */
414 spin_lock(&sbsec->isec_lock);
415next_inode:
416 if (!list_empty(&sbsec->isec_head)) {
417 struct inode_security_struct *isec =
418 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500419 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 struct inode *inode = isec->inode;
421 spin_unlock(&sbsec->isec_lock);
422 inode = igrab(inode);
423 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500424 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 inode_doinit(inode);
426 iput(inode);
427 }
428 spin_lock(&sbsec->isec_lock);
429 list_del_init(&isec->list);
430 goto next_inode;
431 }
432 spin_unlock(&sbsec->isec_lock);
433out:
Eric Parisc9180a52007-11-30 13:00:35 -0500434 return rc;
435}
436
437/*
438 * This function should allow an FS to ask what it's mount security
439 * options were so it can use those later for submounts, displaying
440 * mount options, or whatever.
441 */
442static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500443 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500444{
445 int rc = 0, i;
446 struct superblock_security_struct *sbsec = sb->s_security;
447 char *context = NULL;
448 u32 len;
449 char tmp;
450
Eric Parise0007522008-03-05 10:31:54 -0500451 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500452
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500453 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500454 return -EINVAL;
455
456 if (!ss_initialized)
457 return -EINVAL;
458
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500459 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500460 /* count the number of mount options for this sb */
461 for (i = 0; i < 8; i++) {
462 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500463 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500464 tmp >>= 1;
465 }
David P. Quigley11689d42009-01-16 09:22:03 -0500466 /* Check if the Label support flag is set */
467 if (sbsec->flags & SE_SBLABELSUPP)
468 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500469
Eric Parise0007522008-03-05 10:31:54 -0500470 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
471 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500472 rc = -ENOMEM;
473 goto out_free;
474 }
475
Eric Parise0007522008-03-05 10:31:54 -0500476 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
477 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500478 rc = -ENOMEM;
479 goto out_free;
480 }
481
482 i = 0;
483 if (sbsec->flags & FSCONTEXT_MNT) {
484 rc = security_sid_to_context(sbsec->sid, &context, &len);
485 if (rc)
486 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500487 opts->mnt_opts[i] = context;
488 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500489 }
490 if (sbsec->flags & CONTEXT_MNT) {
491 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
492 if (rc)
493 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500494 opts->mnt_opts[i] = context;
495 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500496 }
497 if (sbsec->flags & DEFCONTEXT_MNT) {
498 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
499 if (rc)
500 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500501 opts->mnt_opts[i] = context;
502 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500503 }
504 if (sbsec->flags & ROOTCONTEXT_MNT) {
505 struct inode *root = sbsec->sb->s_root->d_inode;
506 struct inode_security_struct *isec = root->i_security;
507
508 rc = security_sid_to_context(isec->sid, &context, &len);
509 if (rc)
510 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500511 opts->mnt_opts[i] = context;
512 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500513 }
David P. Quigley11689d42009-01-16 09:22:03 -0500514 if (sbsec->flags & SE_SBLABELSUPP) {
515 opts->mnt_opts[i] = NULL;
516 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
517 }
Eric Parisc9180a52007-11-30 13:00:35 -0500518
Eric Parise0007522008-03-05 10:31:54 -0500519 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500520
521 return 0;
522
523out_free:
Eric Parise0007522008-03-05 10:31:54 -0500524 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500525 return rc;
526}
527
528static int bad_option(struct superblock_security_struct *sbsec, char flag,
529 u32 old_sid, u32 new_sid)
530{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500531 char mnt_flags = sbsec->flags & SE_MNTMASK;
532
Eric Parisc9180a52007-11-30 13:00:35 -0500533 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500534 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500535 if (!(sbsec->flags & flag) ||
536 (old_sid != new_sid))
537 return 1;
538
539 /* check if we were passed the same options twice,
540 * aka someone passed context=a,context=b
541 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500542 if (!(sbsec->flags & SE_SBINITIALIZED))
543 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500544 return 1;
545 return 0;
546}
Eric Parise0007522008-03-05 10:31:54 -0500547
Eric Parisc9180a52007-11-30 13:00:35 -0500548/*
549 * Allow filesystems with binary mount data to explicitly set mount point
550 * labeling information.
551 */
Eric Parise0007522008-03-05 10:31:54 -0500552static int selinux_set_mnt_opts(struct super_block *sb,
553 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500554{
David Howells275bb412008-11-14 10:39:19 +1100555 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500556 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500557 struct superblock_security_struct *sbsec = sb->s_security;
558 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000559 struct inode *inode = sbsec->sb->s_root->d_inode;
560 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500561 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
562 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500563 char **mount_options = opts->mnt_opts;
564 int *flags = opts->mnt_opts_flags;
565 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500566
567 mutex_lock(&sbsec->lock);
568
569 if (!ss_initialized) {
570 if (!num_opts) {
571 /* Defer initialization until selinux_complete_init,
572 after the initial policy is loaded and the security
573 server is ready to handle calls. */
Eric Parisc9180a52007-11-30 13:00:35 -0500574 goto out;
575 }
576 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400577 printk(KERN_WARNING "SELinux: Unable to set superblock options "
578 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500579 goto out;
580 }
581
582 /*
Eric Parise0007522008-03-05 10:31:54 -0500583 * Binary mount data FS will come through this function twice. Once
584 * from an explicit call and once from the generic calls from the vfs.
585 * Since the generic VFS calls will not contain any security mount data
586 * we need to skip the double mount verification.
587 *
588 * This does open a hole in which we will not notice if the first
589 * mount using this sb set explict options and a second mount using
590 * this sb does not set any security options. (The first options
591 * will be used for both mounts)
592 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500593 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500594 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400595 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500596
597 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500598 * parse the mount options, check if they are valid sids.
599 * also check if someone is trying to mount the same sb more
600 * than once with different security options.
601 */
602 for (i = 0; i < num_opts; i++) {
603 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500604
605 if (flags[i] == SE_SBLABELSUPP)
606 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500607 rc = security_context_to_sid(mount_options[i],
608 strlen(mount_options[i]), &sid);
609 if (rc) {
610 printk(KERN_WARNING "SELinux: security_context_to_sid"
611 "(%s) failed for (dev %s, type %s) errno=%d\n",
612 mount_options[i], sb->s_id, name, rc);
613 goto out;
614 }
615 switch (flags[i]) {
616 case FSCONTEXT_MNT:
617 fscontext_sid = sid;
618
619 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
620 fscontext_sid))
621 goto out_double_mount;
622
623 sbsec->flags |= FSCONTEXT_MNT;
624 break;
625 case CONTEXT_MNT:
626 context_sid = sid;
627
628 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
629 context_sid))
630 goto out_double_mount;
631
632 sbsec->flags |= CONTEXT_MNT;
633 break;
634 case ROOTCONTEXT_MNT:
635 rootcontext_sid = sid;
636
637 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
638 rootcontext_sid))
639 goto out_double_mount;
640
641 sbsec->flags |= ROOTCONTEXT_MNT;
642
643 break;
644 case DEFCONTEXT_MNT:
645 defcontext_sid = sid;
646
647 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
648 defcontext_sid))
649 goto out_double_mount;
650
651 sbsec->flags |= DEFCONTEXT_MNT;
652
653 break;
654 default:
655 rc = -EINVAL;
656 goto out;
657 }
658 }
659
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500660 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500661 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500662 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500663 goto out_double_mount;
664 rc = 0;
665 goto out;
666 }
667
James Morris089be432008-07-15 18:32:49 +1000668 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500669 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500670
671 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500672 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500673 if (rc) {
674 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000675 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500676 goto out;
677 }
678
679 /* sets the context of the superblock for the fs being mounted. */
680 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100681 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500682 if (rc)
683 goto out;
684
685 sbsec->sid = fscontext_sid;
686 }
687
688 /*
689 * Switch to using mount point labeling behavior.
690 * sets the label used on all file below the mountpoint, and will set
691 * the superblock context if not already set.
692 */
693 if (context_sid) {
694 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100695 rc = may_context_mount_sb_relabel(context_sid, sbsec,
696 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500697 if (rc)
698 goto out;
699 sbsec->sid = context_sid;
700 } else {
David Howells275bb412008-11-14 10:39:19 +1100701 rc = may_context_mount_inode_relabel(context_sid, sbsec,
702 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500703 if (rc)
704 goto out;
705 }
706 if (!rootcontext_sid)
707 rootcontext_sid = context_sid;
708
709 sbsec->mntpoint_sid = context_sid;
710 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
711 }
712
713 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100714 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
715 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500716 if (rc)
717 goto out;
718
719 root_isec->sid = rootcontext_sid;
720 root_isec->initialized = 1;
721 }
722
723 if (defcontext_sid) {
724 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
725 rc = -EINVAL;
726 printk(KERN_WARNING "SELinux: defcontext option is "
727 "invalid for this filesystem type\n");
728 goto out;
729 }
730
731 if (defcontext_sid != sbsec->def_sid) {
732 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100733 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500734 if (rc)
735 goto out;
736 }
737
738 sbsec->def_sid = defcontext_sid;
739 }
740
741 rc = sb_finish_set_opts(sb);
742out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700743 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500745out_double_mount:
746 rc = -EINVAL;
747 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
748 "security settings for (dev %s, type %s)\n", sb->s_id, name);
749 goto out;
750}
751
752static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
753 struct super_block *newsb)
754{
755 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
756 struct superblock_security_struct *newsbsec = newsb->s_security;
757
758 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
759 int set_context = (oldsbsec->flags & CONTEXT_MNT);
760 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
761
Eric Paris0f5e6422008-04-21 16:24:11 -0400762 /*
763 * if the parent was able to be mounted it clearly had no special lsm
Al Viroe8c26252010-03-23 06:36:54 -0400764 * mount options. thus we can safely deal with this superblock later
Eric Paris0f5e6422008-04-21 16:24:11 -0400765 */
Al Viroe8c26252010-03-23 06:36:54 -0400766 if (!ss_initialized)
Eric Paris0f5e6422008-04-21 16:24:11 -0400767 return;
Eric Parisc9180a52007-11-30 13:00:35 -0500768
Eric Parisc9180a52007-11-30 13:00:35 -0500769 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500770 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500771
Eric Paris5a552612008-04-09 14:08:35 -0400772 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500773 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400774 return;
775
Eric Parisc9180a52007-11-30 13:00:35 -0500776 mutex_lock(&newsbsec->lock);
777
778 newsbsec->flags = oldsbsec->flags;
779
780 newsbsec->sid = oldsbsec->sid;
781 newsbsec->def_sid = oldsbsec->def_sid;
782 newsbsec->behavior = oldsbsec->behavior;
783
784 if (set_context) {
785 u32 sid = oldsbsec->mntpoint_sid;
786
787 if (!set_fscontext)
788 newsbsec->sid = sid;
789 if (!set_rootcontext) {
790 struct inode *newinode = newsb->s_root->d_inode;
791 struct inode_security_struct *newisec = newinode->i_security;
792 newisec->sid = sid;
793 }
794 newsbsec->mntpoint_sid = sid;
795 }
796 if (set_rootcontext) {
797 const struct inode *oldinode = oldsb->s_root->d_inode;
798 const struct inode_security_struct *oldisec = oldinode->i_security;
799 struct inode *newinode = newsb->s_root->d_inode;
800 struct inode_security_struct *newisec = newinode->i_security;
801
802 newisec->sid = oldisec->sid;
803 }
804
805 sb_finish_set_opts(newsb);
806 mutex_unlock(&newsbsec->lock);
807}
808
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200809static int selinux_parse_opts_str(char *options,
810 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500811{
Eric Parise0007522008-03-05 10:31:54 -0500812 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500813 char *context = NULL, *defcontext = NULL;
814 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500815 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500816
Eric Parise0007522008-03-05 10:31:54 -0500817 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500818
819 /* Standard string-based options. */
820 while ((p = strsep(&options, "|")) != NULL) {
821 int token;
822 substring_t args[MAX_OPT_ARGS];
823
824 if (!*p)
825 continue;
826
827 token = match_token(p, tokens, args);
828
829 switch (token) {
830 case Opt_context:
831 if (context || defcontext) {
832 rc = -EINVAL;
833 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
834 goto out_err;
835 }
836 context = match_strdup(&args[0]);
837 if (!context) {
838 rc = -ENOMEM;
839 goto out_err;
840 }
841 break;
842
843 case Opt_fscontext:
844 if (fscontext) {
845 rc = -EINVAL;
846 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
847 goto out_err;
848 }
849 fscontext = match_strdup(&args[0]);
850 if (!fscontext) {
851 rc = -ENOMEM;
852 goto out_err;
853 }
854 break;
855
856 case Opt_rootcontext:
857 if (rootcontext) {
858 rc = -EINVAL;
859 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
860 goto out_err;
861 }
862 rootcontext = match_strdup(&args[0]);
863 if (!rootcontext) {
864 rc = -ENOMEM;
865 goto out_err;
866 }
867 break;
868
869 case Opt_defcontext:
870 if (context || defcontext) {
871 rc = -EINVAL;
872 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
873 goto out_err;
874 }
875 defcontext = match_strdup(&args[0]);
876 if (!defcontext) {
877 rc = -ENOMEM;
878 goto out_err;
879 }
880 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500881 case Opt_labelsupport:
882 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500883 default:
884 rc = -EINVAL;
885 printk(KERN_WARNING "SELinux: unknown mount option\n");
886 goto out_err;
887
888 }
889 }
890
Eric Parise0007522008-03-05 10:31:54 -0500891 rc = -ENOMEM;
892 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
893 if (!opts->mnt_opts)
894 goto out_err;
895
896 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
897 if (!opts->mnt_opts_flags) {
898 kfree(opts->mnt_opts);
899 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500900 }
901
Eric Parise0007522008-03-05 10:31:54 -0500902 if (fscontext) {
903 opts->mnt_opts[num_mnt_opts] = fscontext;
904 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
905 }
906 if (context) {
907 opts->mnt_opts[num_mnt_opts] = context;
908 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
909 }
910 if (rootcontext) {
911 opts->mnt_opts[num_mnt_opts] = rootcontext;
912 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
913 }
914 if (defcontext) {
915 opts->mnt_opts[num_mnt_opts] = defcontext;
916 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
917 }
918
919 opts->num_mnt_opts = num_mnt_opts;
920 return 0;
921
Eric Parisc9180a52007-11-30 13:00:35 -0500922out_err:
923 kfree(context);
924 kfree(defcontext);
925 kfree(fscontext);
926 kfree(rootcontext);
927 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928}
Eric Parise0007522008-03-05 10:31:54 -0500929/*
930 * string mount options parsing and call set the sbsec
931 */
932static int superblock_doinit(struct super_block *sb, void *data)
933{
934 int rc = 0;
935 char *options = data;
936 struct security_mnt_opts opts;
937
938 security_init_mnt_opts(&opts);
939
940 if (!data)
941 goto out;
942
943 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
944
945 rc = selinux_parse_opts_str(options, &opts);
946 if (rc)
947 goto out_err;
948
949out:
950 rc = selinux_set_mnt_opts(sb, &opts);
951
952out_err:
953 security_free_mnt_opts(&opts);
954 return rc;
955}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Adrian Bunk3583a712008-07-22 20:21:23 +0300957static void selinux_write_opts(struct seq_file *m,
958 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000959{
960 int i;
961 char *prefix;
962
963 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -0500964 char *has_comma;
965
966 if (opts->mnt_opts[i])
967 has_comma = strchr(opts->mnt_opts[i], ',');
968 else
969 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +1000970
971 switch (opts->mnt_opts_flags[i]) {
972 case CONTEXT_MNT:
973 prefix = CONTEXT_STR;
974 break;
975 case FSCONTEXT_MNT:
976 prefix = FSCONTEXT_STR;
977 break;
978 case ROOTCONTEXT_MNT:
979 prefix = ROOTCONTEXT_STR;
980 break;
981 case DEFCONTEXT_MNT:
982 prefix = DEFCONTEXT_STR;
983 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500984 case SE_SBLABELSUPP:
985 seq_putc(m, ',');
986 seq_puts(m, LABELSUPP_STR);
987 continue;
Eric Paris2069f452008-07-04 09:47:13 +1000988 default:
989 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -0400990 return;
Eric Paris2069f452008-07-04 09:47:13 +1000991 };
992 /* we need a comma before each option */
993 seq_putc(m, ',');
994 seq_puts(m, prefix);
995 if (has_comma)
996 seq_putc(m, '\"');
997 seq_puts(m, opts->mnt_opts[i]);
998 if (has_comma)
999 seq_putc(m, '\"');
1000 }
1001}
1002
1003static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1004{
1005 struct security_mnt_opts opts;
1006 int rc;
1007
1008 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001009 if (rc) {
1010 /* before policy load we may get EINVAL, don't show anything */
1011 if (rc == -EINVAL)
1012 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001013 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001014 }
Eric Paris2069f452008-07-04 09:47:13 +10001015
1016 selinux_write_opts(m, &opts);
1017
1018 security_free_mnt_opts(&opts);
1019
1020 return rc;
1021}
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023static inline u16 inode_mode_to_security_class(umode_t mode)
1024{
1025 switch (mode & S_IFMT) {
1026 case S_IFSOCK:
1027 return SECCLASS_SOCK_FILE;
1028 case S_IFLNK:
1029 return SECCLASS_LNK_FILE;
1030 case S_IFREG:
1031 return SECCLASS_FILE;
1032 case S_IFBLK:
1033 return SECCLASS_BLK_FILE;
1034 case S_IFDIR:
1035 return SECCLASS_DIR;
1036 case S_IFCHR:
1037 return SECCLASS_CHR_FILE;
1038 case S_IFIFO:
1039 return SECCLASS_FIFO_FILE;
1040
1041 }
1042
1043 return SECCLASS_FILE;
1044}
1045
James Morris13402582005-09-30 14:24:34 -04001046static inline int default_protocol_stream(int protocol)
1047{
1048 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1049}
1050
1051static inline int default_protocol_dgram(int protocol)
1052{
1053 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1054}
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1057{
1058 switch (family) {
1059 case PF_UNIX:
1060 switch (type) {
1061 case SOCK_STREAM:
1062 case SOCK_SEQPACKET:
1063 return SECCLASS_UNIX_STREAM_SOCKET;
1064 case SOCK_DGRAM:
1065 return SECCLASS_UNIX_DGRAM_SOCKET;
1066 }
1067 break;
1068 case PF_INET:
1069 case PF_INET6:
1070 switch (type) {
1071 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001072 if (default_protocol_stream(protocol))
1073 return SECCLASS_TCP_SOCKET;
1074 else
1075 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001077 if (default_protocol_dgram(protocol))
1078 return SECCLASS_UDP_SOCKET;
1079 else
1080 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001081 case SOCK_DCCP:
1082 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001083 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return SECCLASS_RAWIP_SOCKET;
1085 }
1086 break;
1087 case PF_NETLINK:
1088 switch (protocol) {
1089 case NETLINK_ROUTE:
1090 return SECCLASS_NETLINK_ROUTE_SOCKET;
1091 case NETLINK_FIREWALL:
1092 return SECCLASS_NETLINK_FIREWALL_SOCKET;
Pavel Emelyanov7f1fb602011-12-06 07:56:43 +00001093 case NETLINK_SOCK_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1095 case NETLINK_NFLOG:
1096 return SECCLASS_NETLINK_NFLOG_SOCKET;
1097 case NETLINK_XFRM:
1098 return SECCLASS_NETLINK_XFRM_SOCKET;
1099 case NETLINK_SELINUX:
1100 return SECCLASS_NETLINK_SELINUX_SOCKET;
1101 case NETLINK_AUDIT:
1102 return SECCLASS_NETLINK_AUDIT_SOCKET;
1103 case NETLINK_IP6_FW:
1104 return SECCLASS_NETLINK_IP6FW_SOCKET;
1105 case NETLINK_DNRTMSG:
1106 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001107 case NETLINK_KOBJECT_UEVENT:
1108 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 default:
1110 return SECCLASS_NETLINK_SOCKET;
1111 }
1112 case PF_PACKET:
1113 return SECCLASS_PACKET_SOCKET;
1114 case PF_KEY:
1115 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001116 case PF_APPLETALK:
1117 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119
1120 return SECCLASS_SOCKET;
1121}
1122
1123#ifdef CONFIG_PROC_FS
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001124static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 u16 tclass,
1126 u32 *sid)
1127{
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001128 int rc;
1129 char *buffer, *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Eric Paris828dfe12008-04-17 13:17:49 -04001131 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 if (!buffer)
1133 return -ENOMEM;
1134
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001135 path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
1136 if (IS_ERR(path))
1137 rc = PTR_ERR(path);
1138 else {
1139 /* each process gets a /proc/PID/ entry. Strip off the
1140 * PID part to get a valid selinux labeling.
1141 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
1142 while (path[1] >= '0' && path[1] <= '9') {
1143 path[1] = '/';
1144 path++;
1145 }
1146 rc = security_genfs_sid("proc", path, tclass, sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 free_page((unsigned long)buffer);
1149 return rc;
1150}
1151#else
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001152static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 u16 tclass,
1154 u32 *sid)
1155{
1156 return -EINVAL;
1157}
1158#endif
1159
1160/* The inode's security attributes must be initialized before first use. */
1161static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1162{
1163 struct superblock_security_struct *sbsec = NULL;
1164 struct inode_security_struct *isec = inode->i_security;
1165 u32 sid;
1166 struct dentry *dentry;
1167#define INITCONTEXTLEN 255
1168 char *context = NULL;
1169 unsigned len = 0;
1170 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 if (isec->initialized)
1173 goto out;
1174
Eric Paris23970742006-09-25 23:32:01 -07001175 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001177 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
1179 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001180 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 /* Defer initialization until selinux_complete_init,
1182 after the initial policy is loaded and the security
1183 server is ready to handle calls. */
1184 spin_lock(&sbsec->isec_lock);
1185 if (list_empty(&isec->list))
1186 list_add(&isec->list, &sbsec->isec_head);
1187 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001188 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190
1191 switch (sbsec->behavior) {
1192 case SECURITY_FS_USE_XATTR:
1193 if (!inode->i_op->getxattr) {
1194 isec->sid = sbsec->def_sid;
1195 break;
1196 }
1197
1198 /* Need a dentry, since the xattr API requires one.
1199 Life would be simpler if we could just pass the inode. */
1200 if (opt_dentry) {
1201 /* Called from d_instantiate or d_splice_alias. */
1202 dentry = dget(opt_dentry);
1203 } else {
1204 /* Called from selinux_complete_init, try to find a dentry. */
1205 dentry = d_find_alias(inode);
1206 }
1207 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001208 /*
1209 * this is can be hit on boot when a file is accessed
1210 * before the policy is loaded. When we load policy we
1211 * may find inodes that have no dentry on the
1212 * sbsec->isec_head list. No reason to complain as these
1213 * will get fixed up the next time we go through
1214 * inode_doinit with a dentry, before these inodes could
1215 * be used again by userspace.
1216 */
Eric Paris23970742006-09-25 23:32:01 -07001217 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 }
1219
1220 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001221 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 if (!context) {
1223 rc = -ENOMEM;
1224 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001225 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001227 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1229 context, len);
1230 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001231 kfree(context);
1232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 /* Need a larger buffer. Query for the right size. */
1234 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1235 NULL, 0);
1236 if (rc < 0) {
1237 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001238 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001241 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 if (!context) {
1243 rc = -ENOMEM;
1244 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001245 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001247 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 rc = inode->i_op->getxattr(dentry,
1249 XATTR_NAME_SELINUX,
1250 context, len);
1251 }
1252 dput(dentry);
1253 if (rc < 0) {
1254 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001255 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001256 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 -rc, inode->i_sb->s_id, inode->i_ino);
1258 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001259 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
1261 /* Map ENODATA to the default file SID */
1262 sid = sbsec->def_sid;
1263 rc = 0;
1264 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001265 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001266 sbsec->def_sid,
1267 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001269 char *dev = inode->i_sb->s_id;
1270 unsigned long ino = inode->i_ino;
1271
1272 if (rc == -EINVAL) {
1273 if (printk_ratelimit())
1274 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1275 "context=%s. This indicates you may need to relabel the inode or the "
1276 "filesystem in question.\n", ino, dev, context);
1277 } else {
1278 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1279 "returned %d for dev=%s ino=%ld\n",
1280 __func__, context, -rc, dev, ino);
1281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 kfree(context);
1283 /* Leave with the unlabeled SID */
1284 rc = 0;
1285 break;
1286 }
1287 }
1288 kfree(context);
1289 isec->sid = sid;
1290 break;
1291 case SECURITY_FS_USE_TASK:
1292 isec->sid = isec->task_sid;
1293 break;
1294 case SECURITY_FS_USE_TRANS:
1295 /* Default to the fs SID. */
1296 isec->sid = sbsec->sid;
1297
1298 /* Try to obtain a transition SID. */
1299 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Eric Paris652bb9b2011-02-01 11:05:40 -05001300 rc = security_transition_sid(isec->task_sid, sbsec->sid,
1301 isec->sclass, NULL, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001303 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 isec->sid = sid;
1305 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001306 case SECURITY_FS_USE_MNTPOINT:
1307 isec->sid = sbsec->mntpoint_sid;
1308 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001310 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 isec->sid = sbsec->sid;
1312
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001313 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001314 if (opt_dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001316 rc = selinux_proc_get_sid(opt_dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 isec->sclass,
1318 &sid);
1319 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001320 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 isec->sid = sid;
1322 }
1323 }
1324 break;
1325 }
1326
1327 isec->initialized = 1;
1328
Eric Paris23970742006-09-25 23:32:01 -07001329out_unlock:
1330 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331out:
1332 if (isec->sclass == SECCLASS_FILE)
1333 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 return rc;
1335}
1336
1337/* Convert a Linux signal to an access vector. */
1338static inline u32 signal_to_av(int sig)
1339{
1340 u32 perm = 0;
1341
1342 switch (sig) {
1343 case SIGCHLD:
1344 /* Commonly granted from child to parent. */
1345 perm = PROCESS__SIGCHLD;
1346 break;
1347 case SIGKILL:
1348 /* Cannot be caught or ignored */
1349 perm = PROCESS__SIGKILL;
1350 break;
1351 case SIGSTOP:
1352 /* Cannot be caught or ignored */
1353 perm = PROCESS__SIGSTOP;
1354 break;
1355 default:
1356 /* All other signals. */
1357 perm = PROCESS__SIGNAL;
1358 break;
1359 }
1360
1361 return perm;
1362}
1363
David Howells275bb412008-11-14 10:39:19 +11001364/*
David Howellsd84f4f92008-11-14 10:39:23 +11001365 * Check permission between a pair of credentials
1366 * fork check, ptrace check, etc.
1367 */
1368static int cred_has_perm(const struct cred *actor,
1369 const struct cred *target,
1370 u32 perms)
1371{
1372 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1373
1374 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1375}
1376
1377/*
David Howells88e67f32008-11-14 10:39:21 +11001378 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001379 * fork check, ptrace check, etc.
1380 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001381 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001382 */
1383static int task_has_perm(const struct task_struct *tsk1,
1384 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 u32 perms)
1386{
David Howells275bb412008-11-14 10:39:19 +11001387 const struct task_security_struct *__tsec1, *__tsec2;
1388 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
David Howells275bb412008-11-14 10:39:19 +11001390 rcu_read_lock();
1391 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1392 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1393 rcu_read_unlock();
1394 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395}
1396
David Howells3b11a1d2008-11-14 10:39:26 +11001397/*
1398 * Check permission between current and another task, e.g. signal checks,
1399 * fork check, ptrace check, etc.
1400 * current is the actor and tsk2 is the target
1401 * - this uses current's subjective creds
1402 */
1403static int current_has_perm(const struct task_struct *tsk,
1404 u32 perms)
1405{
1406 u32 sid, tsid;
1407
1408 sid = current_sid();
1409 tsid = task_sid(tsk);
1410 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1411}
1412
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001413#if CAP_LAST_CAP > 63
1414#error Fix SELinux to handle capabilities > 63.
1415#endif
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417/* Check whether a task is allowed to use a capability. */
Eric Paris6a9de492012-01-03 12:25:14 -05001418static int cred_has_capability(const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001419 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420{
Thomas Liu2bf49692009-07-14 12:14:09 -04001421 struct common_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001422 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001423 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001424 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001425 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001426 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Thomas Liu2bf49692009-07-14 12:14:09 -04001428 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Eric Paris6a9de492012-01-03 12:25:14 -05001429 ad.tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 ad.u.cap = cap;
1431
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001432 switch (CAP_TO_INDEX(cap)) {
1433 case 0:
1434 sclass = SECCLASS_CAPABILITY;
1435 break;
1436 case 1:
1437 sclass = SECCLASS_CAPABILITY2;
1438 break;
1439 default:
1440 printk(KERN_ERR
1441 "SELinux: out of range capability %d\n", cap);
1442 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001443 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001444 }
Eric Paris06112162008-11-11 22:02:50 +11001445
David Howells275bb412008-11-14 10:39:19 +11001446 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001447 if (audit == SECURITY_CAP_AUDIT) {
1448 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1449 if (rc2)
1450 return rc2;
1451 }
Eric Paris06112162008-11-11 22:02:50 +11001452 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453}
1454
1455/* Check whether a task is allowed to use a system operation. */
1456static int task_has_system(struct task_struct *tsk,
1457 u32 perms)
1458{
David Howells275bb412008-11-14 10:39:19 +11001459 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
David Howells275bb412008-11-14 10:39:19 +11001461 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 SECCLASS_SYSTEM, perms, NULL);
1463}
1464
1465/* Check whether a task has a particular permission to an inode.
1466 The 'adp' parameter is optional and allows other audit
1467 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001468static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 struct inode *inode,
1470 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001471 struct common_audit_data *adp,
1472 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001475 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
David Howellse0e81732009-09-02 09:13:40 +01001477 validate_creds(cred);
1478
Eric Paris828dfe12008-04-17 13:17:49 -04001479 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001480 return 0;
1481
David Howells88e67f32008-11-14 10:39:21 +11001482 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 isec = inode->i_security;
1484
Eric Paris9ade0cf2011-04-25 16:26:29 -04001485 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486}
1487
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001488static int inode_has_perm_noadp(const struct cred *cred,
1489 struct inode *inode,
1490 u32 perms,
1491 unsigned flags)
1492{
1493 struct common_audit_data ad;
1494
1495 COMMON_AUDIT_DATA_INIT(&ad, INODE);
1496 ad.u.inode = inode;
1497 return inode_has_perm(cred, inode, perms, &ad, flags);
1498}
1499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500/* Same as inode_has_perm, but pass explicit audit data containing
1501 the dentry to help the auditing code to more easily generate the
1502 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001503static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 struct dentry *dentry,
1505 u32 av)
1506{
1507 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001508 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001509
Eric Paris2875fa02011-04-28 16:04:24 -04001510 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1511 ad.u.dentry = dentry;
1512 return inode_has_perm(cred, inode, av, &ad, 0);
1513}
1514
1515/* Same as inode_has_perm, but pass explicit audit data containing
1516 the path to help the auditing code to more easily generate the
1517 pathname if needed. */
1518static inline int path_has_perm(const struct cred *cred,
1519 struct path *path,
1520 u32 av)
1521{
1522 struct inode *inode = path->dentry->d_inode;
1523 struct common_audit_data ad;
1524
Eric Parisf48b7392011-04-25 12:54:27 -04001525 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001526 ad.u.path = *path;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001527 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528}
1529
1530/* Check whether a task can use an open file descriptor to
1531 access an inode in a given way. Check access to the
1532 descriptor itself, and then use dentry_has_perm to
1533 check a particular permission to the file.
1534 Access to the descriptor is implicitly granted if it
1535 has the same SID as the process. If av is zero, then
1536 access to the file is not checked, e.g. for cases
1537 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001538static int file_has_perm(const struct cred *cred,
1539 struct file *file,
1540 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001543 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001544 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001545 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 int rc;
1547
Eric Parisf48b7392011-04-25 12:54:27 -04001548 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1549 ad.u.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
David Howells275bb412008-11-14 10:39:19 +11001551 if (sid != fsec->sid) {
1552 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 SECCLASS_FD,
1554 FD__USE,
1555 &ad);
1556 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001557 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 }
1559
1560 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001561 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001563 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
David Howells88e67f32008-11-14 10:39:21 +11001565out:
1566 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567}
1568
1569/* Check whether a task can create a file. */
1570static int may_create(struct inode *dir,
1571 struct dentry *dentry,
1572 u16 tclass)
1573{
Paul Moore5fb49872010-04-22 14:46:19 -04001574 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 struct inode_security_struct *dsec;
1576 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001577 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001578 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 int rc;
1580
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 dsec = dir->i_security;
1582 sbsec = dir->i_sb->s_security;
1583
David Howells275bb412008-11-14 10:39:19 +11001584 sid = tsec->sid;
1585 newsid = tsec->create_sid;
1586
Eric Parisa2694342011-04-25 13:10:27 -04001587 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1588 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
David Howells275bb412008-11-14 10:39:19 +11001590 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 DIR__ADD_NAME | DIR__SEARCH,
1592 &ad);
1593 if (rc)
1594 return rc;
1595
David P. Quigleycd895962009-01-16 09:22:04 -05001596 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001597 rc = security_transition_sid(sid, dsec->sid, tclass,
1598 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc)
1600 return rc;
1601 }
1602
David Howells275bb412008-11-14 10:39:19 +11001603 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 if (rc)
1605 return rc;
1606
1607 return avc_has_perm(newsid, sbsec->sid,
1608 SECCLASS_FILESYSTEM,
1609 FILESYSTEM__ASSOCIATE, &ad);
1610}
1611
Michael LeMay4eb582c2006-06-26 00:24:57 -07001612/* Check whether a task can create a key. */
1613static int may_create_key(u32 ksid,
1614 struct task_struct *ctx)
1615{
David Howells275bb412008-11-14 10:39:19 +11001616 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001617
David Howells275bb412008-11-14 10:39:19 +11001618 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001619}
1620
Eric Paris828dfe12008-04-17 13:17:49 -04001621#define MAY_LINK 0
1622#define MAY_UNLINK 1
1623#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
1625/* Check whether a task can link, unlink, or rmdir a file/directory. */
1626static int may_link(struct inode *dir,
1627 struct dentry *dentry,
1628 int kind)
1629
1630{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001632 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001633 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 u32 av;
1635 int rc;
1636
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 dsec = dir->i_security;
1638 isec = dentry->d_inode->i_security;
1639
Eric Parisa2694342011-04-25 13:10:27 -04001640 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1641 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 av = DIR__SEARCH;
1644 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001645 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 if (rc)
1647 return rc;
1648
1649 switch (kind) {
1650 case MAY_LINK:
1651 av = FILE__LINK;
1652 break;
1653 case MAY_UNLINK:
1654 av = FILE__UNLINK;
1655 break;
1656 case MAY_RMDIR:
1657 av = DIR__RMDIR;
1658 break;
1659 default:
Eric Paris744ba352008-04-17 11:52:44 -04001660 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1661 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 return 0;
1663 }
1664
David Howells275bb412008-11-14 10:39:19 +11001665 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 return rc;
1667}
1668
1669static inline int may_rename(struct inode *old_dir,
1670 struct dentry *old_dentry,
1671 struct inode *new_dir,
1672 struct dentry *new_dentry)
1673{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001675 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001676 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 u32 av;
1678 int old_is_dir, new_is_dir;
1679 int rc;
1680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 old_dsec = old_dir->i_security;
1682 old_isec = old_dentry->d_inode->i_security;
1683 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1684 new_dsec = new_dir->i_security;
1685
Eric Parisa2694342011-04-25 13:10:27 -04001686 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Eric Parisa2694342011-04-25 13:10:27 -04001688 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001689 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1691 if (rc)
1692 return rc;
David Howells275bb412008-11-14 10:39:19 +11001693 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 old_isec->sclass, FILE__RENAME, &ad);
1695 if (rc)
1696 return rc;
1697 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001698 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 old_isec->sclass, DIR__REPARENT, &ad);
1700 if (rc)
1701 return rc;
1702 }
1703
Eric Parisa2694342011-04-25 13:10:27 -04001704 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 av = DIR__ADD_NAME | DIR__SEARCH;
1706 if (new_dentry->d_inode)
1707 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001708 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 if (rc)
1710 return rc;
1711 if (new_dentry->d_inode) {
1712 new_isec = new_dentry->d_inode->i_security;
1713 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001714 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 new_isec->sclass,
1716 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1717 if (rc)
1718 return rc;
1719 }
1720
1721 return 0;
1722}
1723
1724/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001725static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 struct super_block *sb,
1727 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001728 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001731 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001734 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735}
1736
1737/* Convert a Linux mode and permission mask to an access vector. */
1738static inline u32 file_mask_to_av(int mode, int mask)
1739{
1740 u32 av = 0;
1741
Al Virodba19c62011-07-25 20:49:29 -04001742 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if (mask & MAY_EXEC)
1744 av |= FILE__EXECUTE;
1745 if (mask & MAY_READ)
1746 av |= FILE__READ;
1747
1748 if (mask & MAY_APPEND)
1749 av |= FILE__APPEND;
1750 else if (mask & MAY_WRITE)
1751 av |= FILE__WRITE;
1752
1753 } else {
1754 if (mask & MAY_EXEC)
1755 av |= DIR__SEARCH;
1756 if (mask & MAY_WRITE)
1757 av |= DIR__WRITE;
1758 if (mask & MAY_READ)
1759 av |= DIR__READ;
1760 }
1761
1762 return av;
1763}
1764
1765/* Convert a Linux file to an access vector. */
1766static inline u32 file_to_av(struct file *file)
1767{
1768 u32 av = 0;
1769
1770 if (file->f_mode & FMODE_READ)
1771 av |= FILE__READ;
1772 if (file->f_mode & FMODE_WRITE) {
1773 if (file->f_flags & O_APPEND)
1774 av |= FILE__APPEND;
1775 else
1776 av |= FILE__WRITE;
1777 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001778 if (!av) {
1779 /*
1780 * Special file opened with flags 3 for ioctl-only use.
1781 */
1782 av = FILE__IOCTL;
1783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 return av;
1786}
1787
Eric Paris8b6a5a32008-10-29 17:06:46 -04001788/*
1789 * Convert a file to an access vector and include the correct open
1790 * open permission.
1791 */
1792static inline u32 open_file_to_av(struct file *file)
1793{
1794 u32 av = file_to_av(file);
1795
Eric Paris49b7b8d2010-07-23 11:44:09 -04001796 if (selinux_policycap_openperm)
1797 av |= FILE__OPEN;
1798
Eric Paris8b6a5a32008-10-29 17:06:46 -04001799 return av;
1800}
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802/* Hook functions begin here. */
1803
Ingo Molnar9e488582009-05-07 19:26:19 +10001804static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001805 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 int rc;
1808
Ingo Molnar9e488582009-05-07 19:26:19 +10001809 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 if (rc)
1811 return rc;
1812
Eric Paris69f594a2012-01-03 12:25:15 -05001813 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001814 u32 sid = current_sid();
1815 u32 csid = task_sid(child);
1816 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001817 }
1818
David Howells3b11a1d2008-11-14 10:39:26 +11001819 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001820}
1821
1822static int selinux_ptrace_traceme(struct task_struct *parent)
1823{
1824 int rc;
1825
Eric Paris200ac532009-02-12 15:01:04 -05001826 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001827 if (rc)
1828 return rc;
1829
1830 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831}
1832
1833static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001834 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835{
1836 int error;
1837
David Howells3b11a1d2008-11-14 10:39:26 +11001838 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 if (error)
1840 return error;
1841
Eric Paris200ac532009-02-12 15:01:04 -05001842 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843}
1844
David Howellsd84f4f92008-11-14 10:39:23 +11001845static int selinux_capset(struct cred *new, const struct cred *old,
1846 const kernel_cap_t *effective,
1847 const kernel_cap_t *inheritable,
1848 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
1850 int error;
1851
Eric Paris200ac532009-02-12 15:01:04 -05001852 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001853 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 if (error)
1855 return error;
1856
David Howellsd84f4f92008-11-14 10:39:23 +11001857 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858}
1859
James Morris5626d3e2009-01-30 10:05:06 +11001860/*
1861 * (This comment used to live with the selinux_task_setuid hook,
1862 * which was removed).
1863 *
1864 * Since setuid only affects the current process, and since the SELinux
1865 * controls are not based on the Linux identity attributes, SELinux does not
1866 * need to control this operation. However, SELinux does control the use of
1867 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1868 */
1869
Eric Paris6a9de492012-01-03 12:25:14 -05001870static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1871 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872{
1873 int rc;
1874
Eric Paris6a9de492012-01-03 12:25:14 -05001875 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (rc)
1877 return rc;
1878
Eric Paris6a9de492012-01-03 12:25:14 -05001879 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880}
1881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1883{
David Howells88e67f32008-11-14 10:39:21 +11001884 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 int rc = 0;
1886
1887 if (!sb)
1888 return 0;
1889
1890 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001891 case Q_SYNC:
1892 case Q_QUOTAON:
1893 case Q_QUOTAOFF:
1894 case Q_SETINFO:
1895 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001896 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001897 break;
1898 case Q_GETFMT:
1899 case Q_GETINFO:
1900 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001901 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001902 break;
1903 default:
1904 rc = 0; /* let the kernel handle invalid cmds */
1905 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907 return rc;
1908}
1909
1910static int selinux_quota_on(struct dentry *dentry)
1911{
David Howells88e67f32008-11-14 10:39:21 +11001912 const struct cred *cred = current_cred();
1913
Eric Paris2875fa02011-04-28 16:04:24 -04001914 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915}
1916
Eric Paris12b30522010-11-15 18:36:29 -05001917static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
1919 int rc;
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08001922 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
1923 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001924 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1925 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001926 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
1927 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
1928 /* Set level of messages printed to console */
1929 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04001930 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1931 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001932 case SYSLOG_ACTION_CLOSE: /* Close log */
1933 case SYSLOG_ACTION_OPEN: /* Open log */
1934 case SYSLOG_ACTION_READ: /* Read from log */
1935 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
1936 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001937 default:
1938 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1939 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941 return rc;
1942}
1943
1944/*
1945 * Check that a process has enough memory to allocate a new virtual
1946 * mapping. 0 means there is enough memory for the allocation to
1947 * succeed and -ENOMEM implies there is not.
1948 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 * Do not audit the selinux permission check, as this is applied to all
1950 * processes that allocate mappings.
1951 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001952static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953{
1954 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Eric Paris6a9de492012-01-03 12:25:14 -05001956 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00001957 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (rc == 0)
1959 cap_sys_admin = 1;
1960
Alan Cox34b4e4a2007-08-22 14:01:28 -07001961 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962}
1963
1964/* binprm security operations */
1965
David Howellsa6f76f22008-11-14 10:39:24 +11001966static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967{
David Howellsa6f76f22008-11-14 10:39:24 +11001968 const struct task_security_struct *old_tsec;
1969 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001971 struct common_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11001972 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 int rc;
1974
Eric Paris200ac532009-02-12 15:01:04 -05001975 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 if (rc)
1977 return rc;
1978
David Howellsa6f76f22008-11-14 10:39:24 +11001979 /* SELinux context only depends on initial program or script and not
1980 * the script interpreter */
1981 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return 0;
1983
David Howellsa6f76f22008-11-14 10:39:24 +11001984 old_tsec = current_security();
1985 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 isec = inode->i_security;
1987
1988 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11001989 new_tsec->sid = old_tsec->sid;
1990 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
Michael LeMay28eba5b2006-06-27 02:53:42 -07001992 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11001993 new_tsec->create_sid = 0;
1994 new_tsec->keycreate_sid = 0;
1995 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
David Howellsa6f76f22008-11-14 10:39:24 +11001997 if (old_tsec->exec_sid) {
1998 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002000 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 } else {
2002 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002003 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002004 SECCLASS_PROCESS, NULL,
2005 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 if (rc)
2007 return rc;
2008 }
2009
Eric Parisf48b7392011-04-25 12:54:27 -04002010 COMMON_AUDIT_DATA_INIT(&ad, PATH);
2011 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Josef Sipek3d5ff522006-12-08 02:37:38 -08002013 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002014 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
David Howellsa6f76f22008-11-14 10:39:24 +11002016 if (new_tsec->sid == old_tsec->sid) {
2017 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2019 if (rc)
2020 return rc;
2021 } else {
2022 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002023 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2025 if (rc)
2026 return rc;
2027
David Howellsa6f76f22008-11-14 10:39:24 +11002028 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2030 if (rc)
2031 return rc;
2032
David Howellsa6f76f22008-11-14 10:39:24 +11002033 /* Check for shared state */
2034 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2035 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2036 SECCLASS_PROCESS, PROCESS__SHARE,
2037 NULL);
2038 if (rc)
2039 return -EPERM;
2040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
David Howellsa6f76f22008-11-14 10:39:24 +11002042 /* Make sure that anyone attempting to ptrace over a task that
2043 * changes its SID has the appropriate permit */
2044 if (bprm->unsafe &
2045 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2046 struct task_struct *tracer;
2047 struct task_security_struct *sec;
2048 u32 ptsid = 0;
2049
2050 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002051 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002052 if (likely(tracer != NULL)) {
2053 sec = __task_cred(tracer)->security;
2054 ptsid = sec->sid;
2055 }
2056 rcu_read_unlock();
2057
2058 if (ptsid != 0) {
2059 rc = avc_has_perm(ptsid, new_tsec->sid,
2060 SECCLASS_PROCESS,
2061 PROCESS__PTRACE, NULL);
2062 if (rc)
2063 return -EPERM;
2064 }
2065 }
2066
2067 /* Clear any possibly unsafe personality bits on exec: */
2068 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 }
2070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 return 0;
2072}
2073
Eric Paris828dfe12008-04-17 13:17:49 -04002074static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
Paul Moore5fb49872010-04-22 14:46:19 -04002076 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002077 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 int atsecure = 0;
2079
David Howells275bb412008-11-14 10:39:19 +11002080 sid = tsec->sid;
2081 osid = tsec->osid;
2082
2083 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 /* Enable secure mode for SIDs transitions unless
2085 the noatsecure permission is granted between
2086 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002087 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002088 SECCLASS_PROCESS,
2089 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 }
2091
Eric Paris200ac532009-02-12 15:01:04 -05002092 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093}
2094
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002096static inline void flush_unauthorized_files(const struct cred *cred,
2097 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098{
Thomas Liu2bf49692009-07-14 12:14:09 -04002099 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002101 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002102 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002104 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002106 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002108 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002109 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002110 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002111 struct inode *inode;
2112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 /* Revalidate access to controlling tty.
2114 Use inode_has_perm on the tty inode directly rather
2115 than using file_has_perm, as this particular open
2116 file may belong to another process and we are only
2117 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002118 file_priv = list_first_entry(&tty->tty_files,
2119 struct tty_file_private, list);
2120 file = file_priv->file;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002121 inode = file->f_path.dentry->d_inode;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07002122 if (inode_has_perm_noadp(cred, inode,
2123 FILE__READ | FILE__WRITE, 0)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002124 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002127 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002128 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002130 /* Reset controlling tty. */
2131 if (drop_tty)
2132 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
2134 /* Revalidate access to inherited open files. */
2135
Eric Parisf48b7392011-04-25 12:54:27 -04002136 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
2138 spin_lock(&files->file_lock);
2139 for (;;) {
2140 unsigned long set, i;
2141 int fd;
2142
2143 j++;
2144 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002145 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002146 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 break;
David Howells1fd36ad2012-02-16 17:49:54 +00002148 set = fdt->open_fds[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 if (!set)
2150 continue;
2151 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002152 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 if (set & 1) {
2154 file = fget(i);
2155 if (!file)
2156 continue;
David Howells88e67f32008-11-14 10:39:21 +11002157 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 file,
2159 file_to_av(file))) {
2160 sys_close(i);
2161 fd = get_unused_fd();
2162 if (fd != i) {
2163 if (fd >= 0)
2164 put_unused_fd(fd);
2165 fput(file);
2166 continue;
2167 }
2168 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002169 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 } else {
David Howells745ca242008-11-14 10:39:22 +11002171 devnull = dentry_open(
2172 dget(selinux_null),
2173 mntget(selinuxfs_mount),
2174 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002175 if (IS_ERR(devnull)) {
2176 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 put_unused_fd(fd);
2178 fput(file);
2179 continue;
2180 }
2181 }
2182 fd_install(fd, devnull);
2183 }
2184 fput(file);
2185 }
2186 }
2187 spin_lock(&files->file_lock);
2188
2189 }
2190 spin_unlock(&files->file_lock);
2191}
2192
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193/*
David Howellsa6f76f22008-11-14 10:39:24 +11002194 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 */
David Howellsa6f76f22008-11-14 10:39:24 +11002196static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197{
David Howellsa6f76f22008-11-14 10:39:24 +11002198 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 int rc, i;
2201
David Howellsa6f76f22008-11-14 10:39:24 +11002202 new_tsec = bprm->cred->security;
2203 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 return;
2205
2206 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002207 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
David Howellsa6f76f22008-11-14 10:39:24 +11002209 /* Always clear parent death signal on SID transitions. */
2210 current->pdeath_signal = 0;
2211
2212 /* Check whether the new SID can inherit resource limits from the old
2213 * SID. If not, reset all soft limits to the lower of the current
2214 * task's hard limit and the init task's soft limit.
2215 *
2216 * Note that the setting of hard limits (even to lower them) can be
2217 * controlled by the setrlimit check. The inclusion of the init task's
2218 * soft limit into the computation is to avoid resetting soft limits
2219 * higher than the default soft limit for cases where the default is
2220 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2221 */
2222 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2223 PROCESS__RLIMITINH, NULL);
2224 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002225 /* protect against do_prlimit() */
2226 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002227 for (i = 0; i < RLIM_NLIMITS; i++) {
2228 rlim = current->signal->rlim + i;
2229 initrlim = init_task.signal->rlim + i;
2230 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2231 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002232 task_unlock(current);
2233 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002234 }
2235}
2236
2237/*
2238 * Clean up the process immediately after the installation of new credentials
2239 * due to exec
2240 */
2241static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2242{
2243 const struct task_security_struct *tsec = current_security();
2244 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002245 u32 osid, sid;
2246 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002247
David Howellsa6f76f22008-11-14 10:39:24 +11002248 osid = tsec->osid;
2249 sid = tsec->sid;
2250
2251 if (sid == osid)
2252 return;
2253
2254 /* Check whether the new SID can inherit signal state from the old SID.
2255 * If not, clear itimers to avoid subsequent signal generation and
2256 * flush and unblock signals.
2257 *
2258 * This must occur _after_ the task SID has been updated so that any
2259 * kill done after the flush will be checked against the new SID.
2260 */
2261 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 if (rc) {
2263 memset(&itimer, 0, sizeof itimer);
2264 for (i = 0; i < 3; i++)
2265 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002267 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2268 __flush_signals(current);
2269 flush_signal_handlers(current, 1);
2270 sigemptyset(&current->blocked);
2271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 spin_unlock_irq(&current->sighand->siglock);
2273 }
2274
David Howellsa6f76f22008-11-14 10:39:24 +11002275 /* Wake up the parent if it is waiting so that it can recheck
2276 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002277 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002278 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002279 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280}
2281
2282/* superblock security operations */
2283
2284static int selinux_sb_alloc_security(struct super_block *sb)
2285{
2286 return superblock_alloc_security(sb);
2287}
2288
2289static void selinux_sb_free_security(struct super_block *sb)
2290{
2291 superblock_free_security(sb);
2292}
2293
2294static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2295{
2296 if (plen > olen)
2297 return 0;
2298
2299 return !memcmp(prefix, option, plen);
2300}
2301
2302static inline int selinux_option(char *option, int len)
2303{
Eric Paris832cbd92008-04-01 13:24:09 -04002304 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2305 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2306 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002307 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2308 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309}
2310
2311static inline void take_option(char **to, char *from, int *first, int len)
2312{
2313 if (!*first) {
2314 **to = ',';
2315 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002316 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 *first = 0;
2318 memcpy(*to, from, len);
2319 *to += len;
2320}
2321
Eric Paris828dfe12008-04-17 13:17:49 -04002322static inline void take_selinux_option(char **to, char *from, int *first,
2323 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002324{
2325 int current_size = 0;
2326
2327 if (!*first) {
2328 **to = '|';
2329 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002330 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002331 *first = 0;
2332
2333 while (current_size < len) {
2334 if (*from != '"') {
2335 **to = *from;
2336 *to += 1;
2337 }
2338 from += 1;
2339 current_size += 1;
2340 }
2341}
2342
Eric Parise0007522008-03-05 10:31:54 -05002343static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344{
2345 int fnosec, fsec, rc = 0;
2346 char *in_save, *in_curr, *in_end;
2347 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002348 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
2350 in_curr = orig;
2351 sec_curr = copy;
2352
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2354 if (!nosec) {
2355 rc = -ENOMEM;
2356 goto out;
2357 }
2358
2359 nosec_save = nosec;
2360 fnosec = fsec = 1;
2361 in_save = in_end = orig;
2362
2363 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002364 if (*in_end == '"')
2365 open_quote = !open_quote;
2366 if ((*in_end == ',' && open_quote == 0) ||
2367 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 int len = in_end - in_curr;
2369
2370 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002371 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 else
2373 take_option(&nosec, in_curr, &fnosec, len);
2374
2375 in_curr = in_end + 1;
2376 }
2377 } while (*in_end++);
2378
Eric Paris6931dfc2005-06-30 02:58:51 -07002379 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002380 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381out:
2382 return rc;
2383}
2384
Eric Paris026eb162011-03-03 16:09:14 -05002385static int selinux_sb_remount(struct super_block *sb, void *data)
2386{
2387 int rc, i, *flags;
2388 struct security_mnt_opts opts;
2389 char *secdata, **mount_options;
2390 struct superblock_security_struct *sbsec = sb->s_security;
2391
2392 if (!(sbsec->flags & SE_SBINITIALIZED))
2393 return 0;
2394
2395 if (!data)
2396 return 0;
2397
2398 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2399 return 0;
2400
2401 security_init_mnt_opts(&opts);
2402 secdata = alloc_secdata();
2403 if (!secdata)
2404 return -ENOMEM;
2405 rc = selinux_sb_copy_data(data, secdata);
2406 if (rc)
2407 goto out_free_secdata;
2408
2409 rc = selinux_parse_opts_str(secdata, &opts);
2410 if (rc)
2411 goto out_free_secdata;
2412
2413 mount_options = opts.mnt_opts;
2414 flags = opts.mnt_opts_flags;
2415
2416 for (i = 0; i < opts.num_mnt_opts; i++) {
2417 u32 sid;
2418 size_t len;
2419
2420 if (flags[i] == SE_SBLABELSUPP)
2421 continue;
2422 len = strlen(mount_options[i]);
2423 rc = security_context_to_sid(mount_options[i], len, &sid);
2424 if (rc) {
2425 printk(KERN_WARNING "SELinux: security_context_to_sid"
2426 "(%s) failed for (dev %s, type %s) errno=%d\n",
2427 mount_options[i], sb->s_id, sb->s_type->name, rc);
2428 goto out_free_opts;
2429 }
2430 rc = -EINVAL;
2431 switch (flags[i]) {
2432 case FSCONTEXT_MNT:
2433 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2434 goto out_bad_option;
2435 break;
2436 case CONTEXT_MNT:
2437 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2438 goto out_bad_option;
2439 break;
2440 case ROOTCONTEXT_MNT: {
2441 struct inode_security_struct *root_isec;
2442 root_isec = sb->s_root->d_inode->i_security;
2443
2444 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2445 goto out_bad_option;
2446 break;
2447 }
2448 case DEFCONTEXT_MNT:
2449 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2450 goto out_bad_option;
2451 break;
2452 default:
2453 goto out_free_opts;
2454 }
2455 }
2456
2457 rc = 0;
2458out_free_opts:
2459 security_free_mnt_opts(&opts);
2460out_free_secdata:
2461 free_secdata(secdata);
2462 return rc;
2463out_bad_option:
2464 printk(KERN_WARNING "SELinux: unable to change security options "
2465 "during remount (dev %s, type=%s)\n", sb->s_id,
2466 sb->s_type->name);
2467 goto out_free_opts;
2468}
2469
James Morris12204e22008-12-19 10:44:42 +11002470static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471{
David Howells88e67f32008-11-14 10:39:21 +11002472 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002473 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 int rc;
2475
2476 rc = superblock_doinit(sb, data);
2477 if (rc)
2478 return rc;
2479
James Morris74192242008-12-19 11:41:10 +11002480 /* Allow all mounts performed by the kernel */
2481 if (flags & MS_KERNMOUNT)
2482 return 0;
2483
Eric Parisa2694342011-04-25 13:10:27 -04002484 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
2485 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002486 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487}
2488
David Howells726c3342006-06-23 02:02:58 -07002489static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490{
David Howells88e67f32008-11-14 10:39:21 +11002491 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002492 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Eric Parisa2694342011-04-25 13:10:27 -04002494 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
2495 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002496 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497}
2498
Eric Paris828dfe12008-04-17 13:17:49 -04002499static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002500 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002501 char *type,
2502 unsigned long flags,
2503 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504{
David Howells88e67f32008-11-14 10:39:21 +11002505 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
2507 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002508 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002509 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 else
Eric Paris2875fa02011-04-28 16:04:24 -04002511 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512}
2513
2514static int selinux_umount(struct vfsmount *mnt, int flags)
2515{
David Howells88e67f32008-11-14 10:39:21 +11002516 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
David Howells88e67f32008-11-14 10:39:21 +11002518 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002519 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520}
2521
2522/* inode security operations */
2523
2524static int selinux_inode_alloc_security(struct inode *inode)
2525{
2526 return inode_alloc_security(inode);
2527}
2528
2529static void selinux_inode_free_security(struct inode *inode)
2530{
2531 inode_free_security(inode);
2532}
2533
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002534static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002535 const struct qstr *qstr, char **name,
2536 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002537{
Paul Moore5fb49872010-04-22 14:46:19 -04002538 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002539 struct inode_security_struct *dsec;
2540 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002541 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002542 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002543 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002544
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002545 dsec = dir->i_security;
2546 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002547
David Howells275bb412008-11-14 10:39:19 +11002548 sid = tsec->sid;
2549 newsid = tsec->create_sid;
2550
Eric Paris415103f2010-12-02 16:13:40 -05002551 if ((sbsec->flags & SE_SBINITIALIZED) &&
2552 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2553 newsid = sbsec->mntpoint_sid;
2554 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002555 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002556 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002557 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002558 if (rc) {
2559 printk(KERN_WARNING "%s: "
2560 "security_transition_sid failed, rc=%d (dev=%s "
2561 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002562 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002563 -rc, inode->i_sb->s_id, inode->i_ino);
2564 return rc;
2565 }
2566 }
2567
Eric Paris296fddf2006-09-25 23:32:00 -07002568 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002569 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002570 struct inode_security_struct *isec = inode->i_security;
2571 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2572 isec->sid = newsid;
2573 isec->initialized = 1;
2574 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002575
David P. Quigleycd895962009-01-16 09:22:04 -05002576 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002577 return -EOPNOTSUPP;
2578
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002579 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002580 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002581 if (!namep)
2582 return -ENOMEM;
2583 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002584 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002585
2586 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002587 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002588 if (rc) {
2589 kfree(namep);
2590 return rc;
2591 }
2592 *value = context;
2593 *len = clen;
2594 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002595
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002596 return 0;
2597}
2598
Al Viro4acdaf22011-07-26 01:42:34 -04002599static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600{
2601 return may_create(dir, dentry, SECCLASS_FILE);
2602}
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2605{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return may_link(dir, old_dentry, MAY_LINK);
2607}
2608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2610{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 return may_link(dir, dentry, MAY_UNLINK);
2612}
2613
2614static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2615{
2616 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2617}
2618
Al Viro18bb1db2011-07-26 01:41:39 -04002619static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620{
2621 return may_create(dir, dentry, SECCLASS_DIR);
2622}
2623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2625{
2626 return may_link(dir, dentry, MAY_RMDIR);
2627}
2628
Al Viro1a67aaf2011-07-26 01:52:52 -04002629static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2632}
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002635 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636{
2637 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2638}
2639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640static int selinux_inode_readlink(struct dentry *dentry)
2641{
David Howells88e67f32008-11-14 10:39:21 +11002642 const struct cred *cred = current_cred();
2643
Eric Paris2875fa02011-04-28 16:04:24 -04002644 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645}
2646
2647static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2648{
David Howells88e67f32008-11-14 10:39:21 +11002649 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
Eric Paris2875fa02011-04-28 16:04:24 -04002651 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652}
2653
Al Viroe74f71e2011-06-20 19:38:15 -04002654static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
David Howells88e67f32008-11-14 10:39:21 +11002656 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002657 struct common_audit_data ad;
2658 u32 perms;
2659 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002660 unsigned flags = mask & MAY_NOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Eric Parisb782e0a2010-07-23 11:44:03 -04002662 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002663 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2664
Eric Parisb782e0a2010-07-23 11:44:03 -04002665 /* No permission to check. Existence test. */
2666 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
Eric Parisf48b7392011-04-25 12:54:27 -04002669 COMMON_AUDIT_DATA_INIT(&ad, INODE);
2670 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002671
2672 if (from_access)
2673 ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
2674
2675 perms = file_mask_to_av(inode->i_mode, mask);
2676
Eric Paris9ade0cf2011-04-25 16:26:29 -04002677 return inode_has_perm(cred, inode, perms, &ad, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678}
2679
2680static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2681{
David Howells88e67f32008-11-14 10:39:21 +11002682 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002683 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002685 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2686 if (ia_valid & ATTR_FORCE) {
2687 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2688 ATTR_FORCE);
2689 if (!ia_valid)
2690 return 0;
2691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002693 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2694 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002695 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Eric Paris2875fa02011-04-28 16:04:24 -04002697 return dentry_has_perm(cred, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698}
2699
2700static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2701{
David Howells88e67f32008-11-14 10:39:21 +11002702 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002703 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002704
Eric Paris2875fa02011-04-28 16:04:24 -04002705 path.dentry = dentry;
2706 path.mnt = mnt;
2707
2708 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709}
2710
David Howells8f0cfa52008-04-29 00:59:41 -07002711static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002712{
David Howells88e67f32008-11-14 10:39:21 +11002713 const struct cred *cred = current_cred();
2714
Serge E. Hallynb5376772007-10-16 23:31:36 -07002715 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2716 sizeof XATTR_SECURITY_PREFIX - 1)) {
2717 if (!strcmp(name, XATTR_NAME_CAPS)) {
2718 if (!capable(CAP_SETFCAP))
2719 return -EPERM;
2720 } else if (!capable(CAP_SYS_ADMIN)) {
2721 /* A different attribute in the security namespace.
2722 Restrict to administrator. */
2723 return -EPERM;
2724 }
2725 }
2726
2727 /* Not an attribute we recognize, so just check the
2728 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002729 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002730}
2731
David Howells8f0cfa52008-04-29 00:59:41 -07002732static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2733 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 struct inode *inode = dentry->d_inode;
2736 struct inode_security_struct *isec = inode->i_security;
2737 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002738 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002739 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 int rc = 0;
2741
Serge E. Hallynb5376772007-10-16 23:31:36 -07002742 if (strcmp(name, XATTR_NAME_SELINUX))
2743 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
2745 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002746 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 return -EOPNOTSUPP;
2748
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002749 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 return -EPERM;
2751
Eric Parisa2694342011-04-25 13:10:27 -04002752 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
2753 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
David Howells275bb412008-11-14 10:39:19 +11002755 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 FILE__RELABELFROM, &ad);
2757 if (rc)
2758 return rc;
2759
2760 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002761 if (rc == -EINVAL) {
2762 if (!capable(CAP_MAC_ADMIN))
2763 return rc;
2764 rc = security_context_to_sid_force(value, size, &newsid);
2765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 if (rc)
2767 return rc;
2768
David Howells275bb412008-11-14 10:39:19 +11002769 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 FILE__RELABELTO, &ad);
2771 if (rc)
2772 return rc;
2773
David Howells275bb412008-11-14 10:39:19 +11002774 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002775 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 if (rc)
2777 return rc;
2778
2779 return avc_has_perm(newsid,
2780 sbsec->sid,
2781 SECCLASS_FILESYSTEM,
2782 FILESYSTEM__ASSOCIATE,
2783 &ad);
2784}
2785
David Howells8f0cfa52008-04-29 00:59:41 -07002786static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002787 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002788 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789{
2790 struct inode *inode = dentry->d_inode;
2791 struct inode_security_struct *isec = inode->i_security;
2792 u32 newsid;
2793 int rc;
2794
2795 if (strcmp(name, XATTR_NAME_SELINUX)) {
2796 /* Not an attribute we recognize, so nothing to do. */
2797 return;
2798 }
2799
Stephen Smalley12b29f32008-05-07 13:03:20 -04002800 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002802 printk(KERN_ERR "SELinux: unable to map context to SID"
2803 "for (%s, %lu), rc=%d\n",
2804 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 return;
2806 }
2807
2808 isec->sid = newsid;
2809 return;
2810}
2811
David Howells8f0cfa52008-04-29 00:59:41 -07002812static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813{
David Howells88e67f32008-11-14 10:39:21 +11002814 const struct cred *cred = current_cred();
2815
Eric Paris2875fa02011-04-28 16:04:24 -04002816 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817}
2818
Eric Paris828dfe12008-04-17 13:17:49 -04002819static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820{
David Howells88e67f32008-11-14 10:39:21 +11002821 const struct cred *cred = current_cred();
2822
Eric Paris2875fa02011-04-28 16:04:24 -04002823 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824}
2825
David Howells8f0cfa52008-04-29 00:59:41 -07002826static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002828 if (strcmp(name, XATTR_NAME_SELINUX))
2829 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
2831 /* No one is allowed to remove a SELinux security label.
2832 You can change the label, but all data must be labeled. */
2833 return -EACCES;
2834}
2835
James Morrisd381d8a2005-10-30 14:59:22 -08002836/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002837 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002838 *
2839 * Permission check is handled by selinux_inode_getxattr hook.
2840 */
David P. Quigley42492592008-02-04 22:29:39 -08002841static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842{
David P. Quigley42492592008-02-04 22:29:39 -08002843 u32 size;
2844 int error;
2845 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002848 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2849 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002851 /*
2852 * If the caller has CAP_MAC_ADMIN, then get the raw context
2853 * value even if it is not defined by current policy; otherwise,
2854 * use the in-core value under current policy.
2855 * Use the non-auditing forms of the permission checks since
2856 * getxattr may be called by unprivileged processes commonly
2857 * and lack of permission just means that we fall back to the
2858 * in-core context value, not a denial.
2859 */
Eric Paris6a9de492012-01-03 12:25:14 -05002860 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002861 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002862 if (!error)
2863 error = security_sid_to_context_force(isec->sid, &context,
2864 &size);
2865 else
2866 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002867 if (error)
2868 return error;
2869 error = size;
2870 if (alloc) {
2871 *buffer = context;
2872 goto out_nofree;
2873 }
2874 kfree(context);
2875out_nofree:
2876 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877}
2878
2879static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002880 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881{
2882 struct inode_security_struct *isec = inode->i_security;
2883 u32 newsid;
2884 int rc;
2885
2886 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2887 return -EOPNOTSUPP;
2888
2889 if (!value || !size)
2890 return -EACCES;
2891
Eric Paris828dfe12008-04-17 13:17:49 -04002892 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 if (rc)
2894 return rc;
2895
2896 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002897 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 return 0;
2899}
2900
2901static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2902{
2903 const int len = sizeof(XATTR_NAME_SELINUX);
2904 if (buffer && len <= buffer_size)
2905 memcpy(buffer, XATTR_NAME_SELINUX, len);
2906 return len;
2907}
2908
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002909static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2910{
2911 struct inode_security_struct *isec = inode->i_security;
2912 *secid = isec->sid;
2913}
2914
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915/* file security operations */
2916
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002917static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918{
David Howells88e67f32008-11-14 10:39:21 +11002919 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002920 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2923 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2924 mask |= MAY_APPEND;
2925
Paul Moore389fb802009-03-27 17:10:34 -04002926 return file_has_perm(cred, file,
2927 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928}
2929
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002930static int selinux_file_permission(struct file *file, int mask)
2931{
Stephen Smalley20dda182009-06-22 14:54:53 -04002932 struct inode *inode = file->f_path.dentry->d_inode;
2933 struct file_security_struct *fsec = file->f_security;
2934 struct inode_security_struct *isec = inode->i_security;
2935 u32 sid = current_sid();
2936
Paul Moore389fb802009-03-27 17:10:34 -04002937 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002938 /* No permission to check. Existence test. */
2939 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002940
Stephen Smalley20dda182009-06-22 14:54:53 -04002941 if (sid == fsec->sid && fsec->isid == isec->sid &&
2942 fsec->pseqno == avc_policy_seqno())
2943 /* No change since dentry_open check. */
2944 return 0;
2945
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002946 return selinux_revalidate_file_permission(file, mask);
2947}
2948
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949static int selinux_file_alloc_security(struct file *file)
2950{
2951 return file_alloc_security(file);
2952}
2953
2954static void selinux_file_free_security(struct file *file)
2955{
2956 file_free_security(file);
2957}
2958
2959static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2960 unsigned long arg)
2961{
David Howells88e67f32008-11-14 10:39:21 +11002962 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05002963 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
Eric Paris0b24dcb2011-02-25 15:39:20 -05002965 switch (cmd) {
2966 case FIONREAD:
2967 /* fall through */
2968 case FIBMAP:
2969 /* fall through */
2970 case FIGETBSZ:
2971 /* fall through */
2972 case EXT2_IOC_GETFLAGS:
2973 /* fall through */
2974 case EXT2_IOC_GETVERSION:
2975 error = file_has_perm(cred, file, FILE__GETATTR);
2976 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Eric Paris0b24dcb2011-02-25 15:39:20 -05002978 case EXT2_IOC_SETFLAGS:
2979 /* fall through */
2980 case EXT2_IOC_SETVERSION:
2981 error = file_has_perm(cred, file, FILE__SETATTR);
2982 break;
2983
2984 /* sys_ioctl() checks */
2985 case FIONBIO:
2986 /* fall through */
2987 case FIOASYNC:
2988 error = file_has_perm(cred, file, 0);
2989 break;
2990
2991 case KDSKBENT:
2992 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05002993 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
2994 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05002995 break;
2996
2997 /* default case assumes that the command will go
2998 * to the file's ioctl() function.
2999 */
3000 default:
3001 error = file_has_perm(cred, file, FILE__IOCTL);
3002 }
3003 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004}
3005
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003006static int default_noexec;
3007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3009{
David Howells88e67f32008-11-14 10:39:21 +11003010 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003011 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003012
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003013 if (default_noexec &&
3014 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 /*
3016 * We are making executable an anonymous mapping or a
3017 * private file mapping that will also be writable.
3018 * This has an additional check.
3019 */
David Howellsd84f4f92008-11-14 10:39:23 +11003020 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003022 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 if (file) {
3026 /* read access is always possible with a mapping */
3027 u32 av = FILE__READ;
3028
3029 /* write access only matters if the mapping is shared */
3030 if (shared && (prot & PROT_WRITE))
3031 av |= FILE__WRITE;
3032
3033 if (prot & PROT_EXEC)
3034 av |= FILE__EXECUTE;
3035
David Howells88e67f32008-11-14 10:39:21 +11003036 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 }
David Howellsd84f4f92008-11-14 10:39:23 +11003038
3039error:
3040 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041}
3042
3043static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003044 unsigned long prot, unsigned long flags,
3045 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046{
Eric Parised032182007-06-28 15:55:21 -04003047 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003048 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
Eric Paris84336d1a2009-07-31 12:54:05 -04003050 /*
3051 * notice that we are intentionally putting the SELinux check before
3052 * the secondary cap_file_mmap check. This is such a likely attempt
3053 * at bad behaviour/exploit that we always want to get the AVC, even
3054 * if DAC would have also denied the operation.
3055 */
Eric Parisa2551df2009-07-31 12:54:11 -04003056 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003057 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3058 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003059 if (rc)
3060 return rc;
3061 }
3062
3063 /* do DAC check on address space usage */
3064 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003065 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 return rc;
3067
3068 if (selinux_checkreqprot)
3069 prot = reqprot;
3070
3071 return file_map_prot_check(file, prot,
3072 (flags & MAP_TYPE) == MAP_SHARED);
3073}
3074
3075static int selinux_file_mprotect(struct vm_area_struct *vma,
3076 unsigned long reqprot,
3077 unsigned long prot)
3078{
David Howells88e67f32008-11-14 10:39:21 +11003079 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
3081 if (selinux_checkreqprot)
3082 prot = reqprot;
3083
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003084 if (default_noexec &&
3085 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003086 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003087 if (vma->vm_start >= vma->vm_mm->start_brk &&
3088 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003089 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003090 } else if (!vma->vm_file &&
3091 vma->vm_start <= vma->vm_mm->start_stack &&
3092 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003093 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003094 } else if (vma->vm_file && vma->anon_vma) {
3095 /*
3096 * We are making executable a file mapping that has
3097 * had some COW done. Since pages might have been
3098 * written, check ability to execute the possibly
3099 * modified content. This typically should only
3100 * occur for text relocations.
3101 */
David Howellsd84f4f92008-11-14 10:39:23 +11003102 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003103 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003104 if (rc)
3105 return rc;
3106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3109}
3110
3111static int selinux_file_lock(struct file *file, unsigned int cmd)
3112{
David Howells88e67f32008-11-14 10:39:21 +11003113 const struct cred *cred = current_cred();
3114
3115 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116}
3117
3118static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3119 unsigned long arg)
3120{
David Howells88e67f32008-11-14 10:39:21 +11003121 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 int err = 0;
3123
3124 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003125 case F_SETFL:
3126 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3127 err = -EINVAL;
3128 break;
3129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130
Eric Paris828dfe12008-04-17 13:17:49 -04003131 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003132 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003134 }
3135 /* fall through */
3136 case F_SETOWN:
3137 case F_SETSIG:
3138 case F_GETFL:
3139 case F_GETOWN:
3140 case F_GETSIG:
3141 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003142 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003143 break;
3144 case F_GETLK:
3145 case F_SETLK:
3146 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003148 case F_GETLK64:
3149 case F_SETLK64:
3150 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003152 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3153 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003155 }
David Howells88e67f32008-11-14 10:39:21 +11003156 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003157 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 }
3159
3160 return err;
3161}
3162
3163static int selinux_file_set_fowner(struct file *file)
3164{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 struct file_security_struct *fsec;
3166
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003168 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
3170 return 0;
3171}
3172
3173static int selinux_file_send_sigiotask(struct task_struct *tsk,
3174 struct fown_struct *fown, int signum)
3175{
Eric Paris828dfe12008-04-17 13:17:49 -04003176 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003177 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 struct file_security_struct *fsec;
3180
3181 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003182 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 fsec = file->f_security;
3185
3186 if (!signum)
3187 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3188 else
3189 perm = signal_to_av(signum);
3190
David Howells275bb412008-11-14 10:39:19 +11003191 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 SECCLASS_PROCESS, perm, NULL);
3193}
3194
3195static int selinux_file_receive(struct file *file)
3196{
David Howells88e67f32008-11-14 10:39:21 +11003197 const struct cred *cred = current_cred();
3198
3199 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200}
3201
David Howells745ca242008-11-14 10:39:22 +11003202static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003203{
3204 struct file_security_struct *fsec;
3205 struct inode *inode;
3206 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003207
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003208 inode = file->f_path.dentry->d_inode;
3209 fsec = file->f_security;
3210 isec = inode->i_security;
3211 /*
3212 * Save inode label and policy sequence number
3213 * at open-time so that selinux_file_permission
3214 * can determine whether revalidation is necessary.
3215 * Task label is already saved in the file security
3216 * struct as its SID.
3217 */
3218 fsec->isid = isec->sid;
3219 fsec->pseqno = avc_policy_seqno();
3220 /*
3221 * Since the inode label or policy seqno may have changed
3222 * between the selinux_inode_permission check and the saving
3223 * of state above, recheck that access is still permitted.
3224 * Otherwise, access might never be revalidated against the
3225 * new inode label or new policy.
3226 * This check is not redundant - do not remove.
3227 */
Linus Torvalds95f4efb2011-06-08 15:11:56 -07003228 return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003229}
3230
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231/* task security operations */
3232
3233static int selinux_task_create(unsigned long clone_flags)
3234{
David Howells3b11a1d2008-11-14 10:39:26 +11003235 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236}
3237
David Howellsf1752ee2008-11-14 10:39:17 +11003238/*
David Howellsee18d642009-09-02 09:14:21 +01003239 * allocate the SELinux part of blank credentials
3240 */
3241static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3242{
3243 struct task_security_struct *tsec;
3244
3245 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3246 if (!tsec)
3247 return -ENOMEM;
3248
3249 cred->security = tsec;
3250 return 0;
3251}
3252
3253/*
David Howellsf1752ee2008-11-14 10:39:17 +11003254 * detach and free the LSM part of a set of credentials
3255 */
3256static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257{
David Howellsf1752ee2008-11-14 10:39:17 +11003258 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003259
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003260 /*
3261 * cred->security == NULL if security_cred_alloc_blank() or
3262 * security_prepare_creds() returned an error.
3263 */
3264 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003265 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003266 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267}
3268
David Howellsd84f4f92008-11-14 10:39:23 +11003269/*
3270 * prepare a new set of credentials for modification
3271 */
3272static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3273 gfp_t gfp)
3274{
3275 const struct task_security_struct *old_tsec;
3276 struct task_security_struct *tsec;
3277
3278 old_tsec = old->security;
3279
3280 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3281 if (!tsec)
3282 return -ENOMEM;
3283
3284 new->security = tsec;
3285 return 0;
3286}
3287
3288/*
David Howellsee18d642009-09-02 09:14:21 +01003289 * transfer the SELinux data to a blank set of creds
3290 */
3291static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3292{
3293 const struct task_security_struct *old_tsec = old->security;
3294 struct task_security_struct *tsec = new->security;
3295
3296 *tsec = *old_tsec;
3297}
3298
3299/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003300 * set the security data for a kernel service
3301 * - all the creation contexts are set to unlabelled
3302 */
3303static int selinux_kernel_act_as(struct cred *new, u32 secid)
3304{
3305 struct task_security_struct *tsec = new->security;
3306 u32 sid = current_sid();
3307 int ret;
3308
3309 ret = avc_has_perm(sid, secid,
3310 SECCLASS_KERNEL_SERVICE,
3311 KERNEL_SERVICE__USE_AS_OVERRIDE,
3312 NULL);
3313 if (ret == 0) {
3314 tsec->sid = secid;
3315 tsec->create_sid = 0;
3316 tsec->keycreate_sid = 0;
3317 tsec->sockcreate_sid = 0;
3318 }
3319 return ret;
3320}
3321
3322/*
3323 * set the file creation context in a security record to the same as the
3324 * objective context of the specified inode
3325 */
3326static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3327{
3328 struct inode_security_struct *isec = inode->i_security;
3329 struct task_security_struct *tsec = new->security;
3330 u32 sid = current_sid();
3331 int ret;
3332
3333 ret = avc_has_perm(sid, isec->sid,
3334 SECCLASS_KERNEL_SERVICE,
3335 KERNEL_SERVICE__CREATE_FILES_AS,
3336 NULL);
3337
3338 if (ret == 0)
3339 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003340 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003341}
3342
Eric Parisdd8dbf22009-11-03 16:35:32 +11003343static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003344{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003345 u32 sid;
3346 struct common_audit_data ad;
3347
3348 sid = task_sid(current);
3349
3350 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
3351 ad.u.kmod_name = kmod_name;
3352
3353 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3354 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003355}
3356
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3358{
David Howells3b11a1d2008-11-14 10:39:26 +11003359 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360}
3361
3362static int selinux_task_getpgid(struct task_struct *p)
3363{
David Howells3b11a1d2008-11-14 10:39:26 +11003364 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365}
3366
3367static int selinux_task_getsid(struct task_struct *p)
3368{
David Howells3b11a1d2008-11-14 10:39:26 +11003369 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370}
3371
David Quigleyf9008e42006-06-30 01:55:46 -07003372static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3373{
David Howells275bb412008-11-14 10:39:19 +11003374 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003375}
3376
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377static int selinux_task_setnice(struct task_struct *p, int nice)
3378{
3379 int rc;
3380
Eric Paris200ac532009-02-12 15:01:04 -05003381 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 if (rc)
3383 return rc;
3384
David Howells3b11a1d2008-11-14 10:39:26 +11003385 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386}
3387
James Morris03e68062006-06-23 02:03:58 -07003388static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3389{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003390 int rc;
3391
Eric Paris200ac532009-02-12 15:01:04 -05003392 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003393 if (rc)
3394 return rc;
3395
David Howells3b11a1d2008-11-14 10:39:26 +11003396 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003397}
3398
David Quigleya1836a42006-06-30 01:55:49 -07003399static int selinux_task_getioprio(struct task_struct *p)
3400{
David Howells3b11a1d2008-11-14 10:39:26 +11003401 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003402}
3403
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003404static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3405 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003407 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
3409 /* Control the ability to change the hard limit (whether
3410 lowering or raising it), so that the hard limit can
3411 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003412 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003414 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
3416 return 0;
3417}
3418
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003419static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003421 int rc;
3422
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003423 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003424 if (rc)
3425 return rc;
3426
David Howells3b11a1d2008-11-14 10:39:26 +11003427 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428}
3429
3430static int selinux_task_getscheduler(struct task_struct *p)
3431{
David Howells3b11a1d2008-11-14 10:39:26 +11003432 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433}
3434
David Quigley35601542006-06-23 02:04:01 -07003435static int selinux_task_movememory(struct task_struct *p)
3436{
David Howells3b11a1d2008-11-14 10:39:26 +11003437 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003438}
3439
David Quigleyf9008e42006-06-30 01:55:46 -07003440static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3441 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442{
3443 u32 perm;
3444 int rc;
3445
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 if (!sig)
3447 perm = PROCESS__SIGNULL; /* null signal; existence test */
3448 else
3449 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003450 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003451 rc = avc_has_perm(secid, task_sid(p),
3452 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003453 else
David Howells3b11a1d2008-11-14 10:39:26 +11003454 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003455 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456}
3457
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458static int selinux_task_wait(struct task_struct *p)
3459{
Eric Paris8a535142007-10-22 16:10:31 -04003460 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461}
3462
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463static void selinux_task_to_inode(struct task_struct *p,
3464 struct inode *inode)
3465{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003467 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468
David Howells275bb412008-11-14 10:39:19 +11003469 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471}
3472
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003474static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003475 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476{
3477 int offset, ihlen, ret = -EINVAL;
3478 struct iphdr _iph, *ih;
3479
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003480 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3482 if (ih == NULL)
3483 goto out;
3484
3485 ihlen = ih->ihl * 4;
3486 if (ihlen < sizeof(_iph))
3487 goto out;
3488
3489 ad->u.net.v4info.saddr = ih->saddr;
3490 ad->u.net.v4info.daddr = ih->daddr;
3491 ret = 0;
3492
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003493 if (proto)
3494 *proto = ih->protocol;
3495
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003497 case IPPROTO_TCP: {
3498 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
Eric Paris828dfe12008-04-17 13:17:49 -04003500 if (ntohs(ih->frag_off) & IP_OFFSET)
3501 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
3503 offset += ihlen;
3504 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3505 if (th == NULL)
3506 break;
3507
3508 ad->u.net.sport = th->source;
3509 ad->u.net.dport = th->dest;
3510 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Eric Paris828dfe12008-04-17 13:17:49 -04003513 case IPPROTO_UDP: {
3514 struct udphdr _udph, *uh;
3515
3516 if (ntohs(ih->frag_off) & IP_OFFSET)
3517 break;
3518
3519 offset += ihlen;
3520 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3521 if (uh == NULL)
3522 break;
3523
3524 ad->u.net.sport = uh->source;
3525 ad->u.net.dport = uh->dest;
3526 break;
3527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
James Morris2ee92d42006-11-13 16:09:01 -08003529 case IPPROTO_DCCP: {
3530 struct dccp_hdr _dccph, *dh;
3531
3532 if (ntohs(ih->frag_off) & IP_OFFSET)
3533 break;
3534
3535 offset += ihlen;
3536 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3537 if (dh == NULL)
3538 break;
3539
3540 ad->u.net.sport = dh->dccph_sport;
3541 ad->u.net.dport = dh->dccph_dport;
3542 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003543 }
James Morris2ee92d42006-11-13 16:09:01 -08003544
Eric Paris828dfe12008-04-17 13:17:49 -04003545 default:
3546 break;
3547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548out:
3549 return ret;
3550}
3551
3552#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3553
3554/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003555static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003556 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557{
3558 u8 nexthdr;
3559 int ret = -EINVAL, offset;
3560 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003561 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003563 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3565 if (ip6 == NULL)
3566 goto out;
3567
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003568 ad->u.net.v6info.saddr = ip6->saddr;
3569 ad->u.net.v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 ret = 0;
3571
3572 nexthdr = ip6->nexthdr;
3573 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003574 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 if (offset < 0)
3576 goto out;
3577
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003578 if (proto)
3579 *proto = nexthdr;
3580
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 switch (nexthdr) {
3582 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003583 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
3585 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3586 if (th == NULL)
3587 break;
3588
3589 ad->u.net.sport = th->source;
3590 ad->u.net.dport = th->dest;
3591 break;
3592 }
3593
3594 case IPPROTO_UDP: {
3595 struct udphdr _udph, *uh;
3596
3597 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3598 if (uh == NULL)
3599 break;
3600
3601 ad->u.net.sport = uh->source;
3602 ad->u.net.dport = uh->dest;
3603 break;
3604 }
3605
James Morris2ee92d42006-11-13 16:09:01 -08003606 case IPPROTO_DCCP: {
3607 struct dccp_hdr _dccph, *dh;
3608
3609 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3610 if (dh == NULL)
3611 break;
3612
3613 ad->u.net.sport = dh->dccph_sport;
3614 ad->u.net.dport = dh->dccph_dport;
3615 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003616 }
James Morris2ee92d42006-11-13 16:09:01 -08003617
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 /* includes fragments */
3619 default:
3620 break;
3621 }
3622out:
3623 return ret;
3624}
3625
3626#endif /* IPV6 */
3627
Thomas Liu2bf49692009-07-14 12:14:09 -04003628static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003629 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630{
David Howellscf9481e2008-07-27 21:31:07 +10003631 char *addrp;
3632 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633
3634 switch (ad->u.net.family) {
3635 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003636 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003637 if (ret)
3638 goto parse_error;
3639 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3640 &ad->u.net.v4info.daddr);
3641 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642
3643#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3644 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003645 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003646 if (ret)
3647 goto parse_error;
3648 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3649 &ad->u.net.v6info.daddr);
3650 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651#endif /* IPV6 */
3652 default:
David Howellscf9481e2008-07-27 21:31:07 +10003653 addrp = NULL;
3654 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 }
3656
David Howellscf9481e2008-07-27 21:31:07 +10003657parse_error:
3658 printk(KERN_WARNING
3659 "SELinux: failure in selinux_parse_skb(),"
3660 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003662
3663okay:
3664 if (_addrp)
3665 *_addrp = addrp;
3666 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667}
3668
Paul Moore4f6a9932007-03-01 14:35:22 -05003669/**
Paul Moore220deb92008-01-29 08:38:23 -05003670 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003671 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003672 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003673 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003674 *
3675 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003676 * Check the various different forms of network peer labeling and determine
3677 * the peer label/SID for the packet; most of the magic actually occurs in
3678 * the security server function security_net_peersid_cmp(). The function
3679 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3680 * or -EACCES if @sid is invalid due to inconsistencies with the different
3681 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003682 *
3683 */
Paul Moore220deb92008-01-29 08:38:23 -05003684static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003685{
Paul Moore71f1cb02008-01-29 08:51:16 -05003686 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003687 u32 xfrm_sid;
3688 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003689 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003690
3691 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003692 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003693
Paul Moore71f1cb02008-01-29 08:51:16 -05003694 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3695 if (unlikely(err)) {
3696 printk(KERN_WARNING
3697 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3698 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003699 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003700 }
Paul Moore220deb92008-01-29 08:38:23 -05003701
3702 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003703}
3704
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003706
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003707static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3708 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003709{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003710 if (tsec->sockcreate_sid > SECSID_NULL) {
3711 *socksid = tsec->sockcreate_sid;
3712 return 0;
3713 }
3714
3715 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3716 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003717}
3718
Paul Moore253bfae2010-04-22 14:46:19 -04003719static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720{
Paul Moore253bfae2010-04-22 14:46:19 -04003721 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003722 struct common_audit_data ad;
Paul Moore253bfae2010-04-22 14:46:19 -04003723 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
Paul Moore253bfae2010-04-22 14:46:19 -04003725 if (sksec->sid == SECINITSID_KERNEL)
3726 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Thomas Liu2bf49692009-07-14 12:14:09 -04003728 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moore253bfae2010-04-22 14:46:19 -04003729 ad.u.net.sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730
Paul Moore253bfae2010-04-22 14:46:19 -04003731 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732}
3733
3734static int selinux_socket_create(int family, int type,
3735 int protocol, int kern)
3736{
Paul Moore5fb49872010-04-22 14:46:19 -04003737 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003738 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003739 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003740 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
3742 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003743 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
David Howells275bb412008-11-14 10:39:19 +11003745 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003746 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3747 if (rc)
3748 return rc;
3749
Paul Moored4f2d972010-04-22 14:46:18 -04003750 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751}
3752
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003753static int selinux_socket_post_create(struct socket *sock, int family,
3754 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755{
Paul Moore5fb49872010-04-22 14:46:19 -04003756 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003757 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003758 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003759 int err = 0;
3760
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003761 isec->sclass = socket_type_to_security_class(family, type, protocol);
3762
David Howells275bb412008-11-14 10:39:19 +11003763 if (kern)
3764 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003765 else {
3766 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3767 if (err)
3768 return err;
3769 }
David Howells275bb412008-11-14 10:39:19 +11003770
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 isec->initialized = 1;
3772
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003773 if (sock->sk) {
3774 sksec = sock->sk->sk_security;
3775 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003776 sksec->sclass = isec->sclass;
Paul Moore389fb802009-03-27 17:10:34 -04003777 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003778 }
3779
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003780 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781}
3782
3783/* Range of port numbers used to automatically bind.
3784 Need to determine whether we should perform a name_bind
3785 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786
3787static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3788{
Paul Moore253bfae2010-04-22 14:46:19 -04003789 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 u16 family;
3791 int err;
3792
Paul Moore253bfae2010-04-22 14:46:19 -04003793 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 if (err)
3795 goto out;
3796
3797 /*
3798 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003799 * Multiple address binding for SCTP is not supported yet: we just
3800 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 */
Paul Moore253bfae2010-04-22 14:46:19 -04003802 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 if (family == PF_INET || family == PF_INET6) {
3804 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003805 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003806 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 struct sockaddr_in *addr4 = NULL;
3808 struct sockaddr_in6 *addr6 = NULL;
3809 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003810 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 if (family == PF_INET) {
3813 addr4 = (struct sockaddr_in *)address;
3814 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 addrp = (char *)&addr4->sin_addr.s_addr;
3816 } else {
3817 addr6 = (struct sockaddr_in6 *)address;
3818 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 addrp = (char *)&addr6->sin6_addr.s6_addr;
3820 }
3821
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003822 if (snum) {
3823 int low, high;
3824
3825 inet_get_local_port_range(&low, &high);
3826
3827 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003828 err = sel_netport_sid(sk->sk_protocol,
3829 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003830 if (err)
3831 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003832 COMMON_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003833 ad.u.net.sport = htons(snum);
3834 ad.u.net.family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003835 err = avc_has_perm(sksec->sid, sid,
3836 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003837 SOCKET__NAME_BIND, &ad);
3838 if (err)
3839 goto out;
3840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 }
Eric Paris828dfe12008-04-17 13:17:49 -04003842
Paul Moore253bfae2010-04-22 14:46:19 -04003843 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003844 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 node_perm = TCP_SOCKET__NODE_BIND;
3846 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003847
James Morris13402582005-09-30 14:24:34 -04003848 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 node_perm = UDP_SOCKET__NODE_BIND;
3850 break;
James Morris2ee92d42006-11-13 16:09:01 -08003851
3852 case SECCLASS_DCCP_SOCKET:
3853 node_perm = DCCP_SOCKET__NODE_BIND;
3854 break;
3855
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 default:
3857 node_perm = RAWIP_SOCKET__NODE_BIND;
3858 break;
3859 }
Eric Paris828dfe12008-04-17 13:17:49 -04003860
Paul Moore224dfbd2008-01-29 08:38:13 -05003861 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 if (err)
3863 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003864
Thomas Liu2bf49692009-07-14 12:14:09 -04003865 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 ad.u.net.sport = htons(snum);
3867 ad.u.net.family = family;
3868
3869 if (family == PF_INET)
3870 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3871 else
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00003872 ad.u.net.v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
Paul Moore253bfae2010-04-22 14:46:19 -04003874 err = avc_has_perm(sksec->sid, sid,
3875 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 if (err)
3877 goto out;
3878 }
3879out:
3880 return err;
3881}
3882
3883static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3884{
Paul Moore014ab192008-10-10 10:16:33 -04003885 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003886 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 int err;
3888
Paul Moore253bfae2010-04-22 14:46:19 -04003889 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 if (err)
3891 return err;
3892
3893 /*
James Morris2ee92d42006-11-13 16:09:01 -08003894 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 */
Paul Moore253bfae2010-04-22 14:46:19 -04003896 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
3897 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003898 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 struct sockaddr_in *addr4 = NULL;
3900 struct sockaddr_in6 *addr6 = NULL;
3901 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003902 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
3904 if (sk->sk_family == PF_INET) {
3905 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003906 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 return -EINVAL;
3908 snum = ntohs(addr4->sin_port);
3909 } else {
3910 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003911 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 return -EINVAL;
3913 snum = ntohs(addr6->sin6_port);
3914 }
3915
Paul Moore3e112172008-04-10 10:48:14 -04003916 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 if (err)
3918 goto out;
3919
Paul Moore253bfae2010-04-22 14:46:19 -04003920 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08003921 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3922
Thomas Liu2bf49692009-07-14 12:14:09 -04003923 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 ad.u.net.dport = htons(snum);
3925 ad.u.net.family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04003926 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 if (err)
3928 goto out;
3929 }
3930
Paul Moore014ab192008-10-10 10:16:33 -04003931 err = selinux_netlbl_socket_connect(sk, address);
3932
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933out:
3934 return err;
3935}
3936
3937static int selinux_socket_listen(struct socket *sock, int backlog)
3938{
Paul Moore253bfae2010-04-22 14:46:19 -04003939 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940}
3941
3942static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3943{
3944 int err;
3945 struct inode_security_struct *isec;
3946 struct inode_security_struct *newisec;
3947
Paul Moore253bfae2010-04-22 14:46:19 -04003948 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 if (err)
3950 return err;
3951
3952 newisec = SOCK_INODE(newsock)->i_security;
3953
3954 isec = SOCK_INODE(sock)->i_security;
3955 newisec->sclass = isec->sclass;
3956 newisec->sid = isec->sid;
3957 newisec->initialized = 1;
3958
3959 return 0;
3960}
3961
3962static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003963 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964{
Paul Moore253bfae2010-04-22 14:46:19 -04003965 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966}
3967
3968static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3969 int size, int flags)
3970{
Paul Moore253bfae2010-04-22 14:46:19 -04003971 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972}
3973
3974static int selinux_socket_getsockname(struct socket *sock)
3975{
Paul Moore253bfae2010-04-22 14:46:19 -04003976 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977}
3978
3979static int selinux_socket_getpeername(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
Eric Paris828dfe12008-04-17 13:17:49 -04003984static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985{
Paul Mooref8687af2006-10-30 15:22:15 -08003986 int err;
3987
Paul Moore253bfae2010-04-22 14:46:19 -04003988 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08003989 if (err)
3990 return err;
3991
3992 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993}
3994
3995static int selinux_socket_getsockopt(struct socket *sock, int level,
3996 int optname)
3997{
Paul Moore253bfae2010-04-22 14:46:19 -04003998 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999}
4000
4001static int selinux_socket_shutdown(struct socket *sock, int how)
4002{
Paul Moore253bfae2010-04-22 14:46:19 -04004003 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004}
4005
David S. Miller3610cda2011-01-05 15:38:53 -08004006static int selinux_socket_unix_stream_connect(struct sock *sock,
4007 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 struct sock *newsk)
4009{
David S. Miller3610cda2011-01-05 15:38:53 -08004010 struct sk_security_struct *sksec_sock = sock->sk_security;
4011 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004012 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004013 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 int err;
4015
Thomas Liu2bf49692009-07-14 12:14:09 -04004016 COMMON_AUDIT_DATA_INIT(&ad, NET);
David S. Miller3610cda2011-01-05 15:38:53 -08004017 ad.u.net.sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
Paul Moore4d1e2452010-04-22 14:46:18 -04004019 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4020 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4022 if (err)
4023 return err;
4024
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004026 sksec_new->peer_sid = sksec_sock->sid;
4027 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4028 &sksec_new->sid);
4029 if (err)
4030 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004031
Paul Moore4d1e2452010-04-22 14:46:18 -04004032 /* connecting socket */
4033 sksec_sock->peer_sid = sksec_new->sid;
4034
4035 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036}
4037
4038static int selinux_socket_unix_may_send(struct socket *sock,
4039 struct socket *other)
4040{
Paul Moore253bfae2010-04-22 14:46:19 -04004041 struct sk_security_struct *ssec = sock->sk->sk_security;
4042 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004043 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
Thomas Liu2bf49692009-07-14 12:14:09 -04004045 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 ad.u.net.sk = other->sk;
4047
Paul Moore253bfae2010-04-22 14:46:19 -04004048 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4049 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050}
4051
Paul Mooreeffad8d2008-01-29 08:49:27 -05004052static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4053 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004054 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004055{
4056 int err;
4057 u32 if_sid;
4058 u32 node_sid;
4059
4060 err = sel_netif_sid(ifindex, &if_sid);
4061 if (err)
4062 return err;
4063 err = avc_has_perm(peer_sid, if_sid,
4064 SECCLASS_NETIF, NETIF__INGRESS, ad);
4065 if (err)
4066 return err;
4067
4068 err = sel_netnode_sid(addrp, family, &node_sid);
4069 if (err)
4070 return err;
4071 return avc_has_perm(peer_sid, node_sid,
4072 SECCLASS_NODE, NODE__RECVFROM, ad);
4073}
4074
Paul Moore220deb92008-01-29 08:38:23 -05004075static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004076 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004077{
Paul Moore277d3422008-12-31 12:54:11 -05004078 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004079 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004080 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004081 struct common_audit_data ad;
Paul Moored8395c82008-10-10 10:16:30 -04004082 char *addrp;
4083
Thomas Liu2bf49692009-07-14 12:14:09 -04004084 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Dumazet8964be42009-11-20 15:35:04 -08004085 ad.u.net.netif = skb->skb_iif;
Paul Moored8395c82008-10-10 10:16:30 -04004086 ad.u.net.family = family;
4087 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4088 if (err)
4089 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004090
Paul Moore58bfbb52009-03-27 17:10:41 -04004091 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004092 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004093 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004094 if (err)
4095 return err;
4096 }
Paul Moore220deb92008-01-29 08:38:23 -05004097
Steffen Klassertb9679a72011-02-23 12:55:21 +01004098 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4099 if (err)
4100 return err;
4101 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004102
James Morris4e5ab4c2006-06-09 00:33:33 -07004103 return err;
4104}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004105
James Morris4e5ab4c2006-06-09 00:33:33 -07004106static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4107{
Paul Moore220deb92008-01-29 08:38:23 -05004108 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004109 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004110 u16 family = sk->sk_family;
4111 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004112 struct common_audit_data ad;
Paul Moore220deb92008-01-29 08:38:23 -05004113 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004114 u8 secmark_active;
4115 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004116
James Morris4e5ab4c2006-06-09 00:33:33 -07004117 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004118 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004119
4120 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004121 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004122 family = PF_INET;
4123
Paul Moored8395c82008-10-10 10:16:30 -04004124 /* If any sort of compatibility mode is enabled then handoff processing
4125 * to the selinux_sock_rcv_skb_compat() function to deal with the
4126 * special handling. We do this in an attempt to keep this function
4127 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004128 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004129 return selinux_sock_rcv_skb_compat(sk, skb, family);
4130
4131 secmark_active = selinux_secmark_enabled();
4132 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4133 if (!secmark_active && !peerlbl_active)
4134 return 0;
4135
Thomas Liu2bf49692009-07-14 12:14:09 -04004136 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Dumazet8964be42009-11-20 15:35:04 -08004137 ad.u.net.netif = skb->skb_iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004138 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004139 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004140 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004141 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004142
Paul Moored8395c82008-10-10 10:16:30 -04004143 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004144 u32 peer_sid;
4145
4146 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4147 if (err)
4148 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004149 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004150 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004151 if (err) {
4152 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004153 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004154 }
Paul Moored621d352008-01-29 08:43:36 -05004155 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4156 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004157 if (err)
4158 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004159 }
4160
Paul Moored8395c82008-10-10 10:16:30 -04004161 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004162 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4163 PACKET__RECV, &ad);
4164 if (err)
4165 return err;
4166 }
4167
Paul Moored621d352008-01-29 08:43:36 -05004168 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169}
4170
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004171static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4172 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173{
4174 int err = 0;
4175 char *scontext;
4176 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004177 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004178 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
Paul Moore253bfae2010-04-22 14:46:19 -04004180 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4181 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004182 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004183 if (peer_sid == SECSID_NULL)
4184 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004186 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004188 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
4190 if (scontext_len > len) {
4191 err = -ERANGE;
4192 goto out_len;
4193 }
4194
4195 if (copy_to_user(optval, scontext, scontext_len))
4196 err = -EFAULT;
4197
4198out_len:
4199 if (put_user(scontext_len, optlen))
4200 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 return err;
4203}
4204
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004205static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004206{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004207 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004208 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004209
Paul Mooreaa862902008-10-10 10:16:29 -04004210 if (skb && skb->protocol == htons(ETH_P_IP))
4211 family = PF_INET;
4212 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4213 family = PF_INET6;
4214 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004215 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004216 else
4217 goto out;
4218
4219 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004220 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004221 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004222 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004223
Paul Moore75e22912008-01-29 08:38:04 -05004224out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004225 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004226 if (peer_secid == SECSID_NULL)
4227 return -EINVAL;
4228 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004229}
4230
Al Viro7d877f32005-10-21 03:20:43 -04004231static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232{
Paul Moore84914b72010-04-22 14:46:18 -04004233 struct sk_security_struct *sksec;
4234
4235 sksec = kzalloc(sizeof(*sksec), priority);
4236 if (!sksec)
4237 return -ENOMEM;
4238
4239 sksec->peer_sid = SECINITSID_UNLABELED;
4240 sksec->sid = SECINITSID_UNLABELED;
4241 selinux_netlbl_sk_security_reset(sksec);
4242 sk->sk_security = sksec;
4243
4244 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245}
4246
4247static void selinux_sk_free_security(struct sock *sk)
4248{
Paul Moore84914b72010-04-22 14:46:18 -04004249 struct sk_security_struct *sksec = sk->sk_security;
4250
4251 sk->sk_security = NULL;
4252 selinux_netlbl_sk_security_free(sksec);
4253 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254}
4255
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004256static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4257{
Eric Parisdd3e7832010-04-07 15:08:46 -04004258 struct sk_security_struct *sksec = sk->sk_security;
4259 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004260
Eric Parisdd3e7832010-04-07 15:08:46 -04004261 newsksec->sid = sksec->sid;
4262 newsksec->peer_sid = sksec->peer_sid;
4263 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004264
Eric Parisdd3e7832010-04-07 15:08:46 -04004265 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004266}
4267
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004268static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004269{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004270 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004271 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004272 else {
4273 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004274
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004275 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004276 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004277}
4278
Eric Paris828dfe12008-04-17 13:17:49 -04004279static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004280{
4281 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4282 struct sk_security_struct *sksec = sk->sk_security;
4283
David Woodhouse2148ccc2006-09-29 15:50:25 -07004284 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4285 sk->sk_family == PF_UNIX)
4286 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004287 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004288}
4289
Adrian Bunk9a673e52006-08-15 00:03:53 -07004290static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4291 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004292{
4293 struct sk_security_struct *sksec = sk->sk_security;
4294 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004295 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004296 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004297 u32 peersid;
4298
Paul Mooreaa862902008-10-10 10:16:29 -04004299 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4300 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4301 family = PF_INET;
4302
4303 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004304 if (err)
4305 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004306 if (peersid == SECSID_NULL) {
4307 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004308 req->peer_secid = SECSID_NULL;
Paul Moore389fb802009-03-27 17:10:34 -04004309 } else {
4310 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4311 if (err)
4312 return err;
4313 req->secid = newsid;
4314 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004315 }
4316
Paul Moore389fb802009-03-27 17:10:34 -04004317 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004318}
4319
Adrian Bunk9a673e52006-08-15 00:03:53 -07004320static void selinux_inet_csk_clone(struct sock *newsk,
4321 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004322{
4323 struct sk_security_struct *newsksec = newsk->sk_security;
4324
4325 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004326 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004327 /* NOTE: Ideally, we should also get the isec->sid for the
4328 new socket in sync, but we don't have the isec available yet.
4329 So we will wait until sock_graft to do it, by which
4330 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004331
Paul Moore9f2ad662006-11-17 17:38:53 -05004332 /* We don't need to take any sort of lock here as we are the only
4333 * thread with access to newsksec */
Paul Moore389fb802009-03-27 17:10:34 -04004334 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004335}
4336
Paul Moore014ab192008-10-10 10:16:33 -04004337static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004338{
Paul Mooreaa862902008-10-10 10:16:29 -04004339 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004340 struct sk_security_struct *sksec = sk->sk_security;
4341
Paul Mooreaa862902008-10-10 10:16:29 -04004342 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4343 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4344 family = PF_INET;
4345
4346 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004347}
4348
Eric Paris2606fd12010-10-13 16:24:41 -04004349static int selinux_secmark_relabel_packet(u32 sid)
4350{
4351 const struct task_security_struct *__tsec;
4352 u32 tsid;
4353
4354 __tsec = current_security();
4355 tsid = __tsec->sid;
4356
4357 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4358}
4359
4360static void selinux_secmark_refcount_inc(void)
4361{
4362 atomic_inc(&selinux_secmark_refcount);
4363}
4364
4365static void selinux_secmark_refcount_dec(void)
4366{
4367 atomic_dec(&selinux_secmark_refcount);
4368}
4369
Adrian Bunk9a673e52006-08-15 00:03:53 -07004370static void selinux_req_classify_flow(const struct request_sock *req,
4371 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004372{
David S. Miller1d28f422011-03-12 00:29:39 -05004373 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004374}
4375
Paul Mooreed6d76e2009-08-28 18:12:49 -04004376static int selinux_tun_dev_create(void)
4377{
4378 u32 sid = current_sid();
4379
4380 /* we aren't taking into account the "sockcreate" SID since the socket
4381 * that is being created here is not a socket in the traditional sense,
4382 * instead it is a private sock, accessible only to the kernel, and
4383 * representing a wide range of network traffic spanning multiple
4384 * connections unlike traditional sockets - check the TUN driver to
4385 * get a better understanding of why this socket is special */
4386
4387 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4388 NULL);
4389}
4390
4391static void selinux_tun_dev_post_create(struct sock *sk)
4392{
4393 struct sk_security_struct *sksec = sk->sk_security;
4394
4395 /* we don't currently perform any NetLabel based labeling here and it
4396 * isn't clear that we would want to do so anyway; while we could apply
4397 * labeling without the support of the TUN user the resulting labeled
4398 * traffic from the other end of the connection would almost certainly
4399 * cause confusion to the TUN user that had no idea network labeling
4400 * protocols were being used */
4401
4402 /* see the comments in selinux_tun_dev_create() about why we don't use
4403 * the sockcreate SID here */
4404
4405 sksec->sid = current_sid();
4406 sksec->sclass = SECCLASS_TUN_SOCKET;
4407}
4408
4409static int selinux_tun_dev_attach(struct sock *sk)
4410{
4411 struct sk_security_struct *sksec = sk->sk_security;
4412 u32 sid = current_sid();
4413 int err;
4414
4415 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4416 TUN_SOCKET__RELABELFROM, NULL);
4417 if (err)
4418 return err;
4419 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4420 TUN_SOCKET__RELABELTO, NULL);
4421 if (err)
4422 return err;
4423
4424 sksec->sid = sid;
4425
4426 return 0;
4427}
4428
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4430{
4431 int err = 0;
4432 u32 perm;
4433 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004434 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004435
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 if (skb->len < NLMSG_SPACE(0)) {
4437 err = -EINVAL;
4438 goto out;
4439 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004440 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004441
Paul Moore253bfae2010-04-22 14:46:19 -04004442 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 if (err) {
4444 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004445 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 "SELinux: unrecognized netlink message"
4447 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004448 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004449 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 err = 0;
4451 }
4452
4453 /* Ignore */
4454 if (err == -ENOENT)
4455 err = 0;
4456 goto out;
4457 }
4458
Paul Moore253bfae2010-04-22 14:46:19 -04004459 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460out:
4461 return err;
4462}
4463
4464#ifdef CONFIG_NETFILTER
4465
Paul Mooreeffad8d2008-01-29 08:49:27 -05004466static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4467 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468{
Paul Mooredfaebe92008-10-10 10:16:31 -04004469 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004470 char *addrp;
4471 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004472 struct common_audit_data ad;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004473 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004474 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004475 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004476
Paul Mooreeffad8d2008-01-29 08:49:27 -05004477 if (!selinux_policycap_netpeer)
4478 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004479
Paul Mooreeffad8d2008-01-29 08:49:27 -05004480 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004481 netlbl_active = netlbl_enabled();
4482 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004483 if (!secmark_active && !peerlbl_active)
4484 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004485
Paul Moored8395c82008-10-10 10:16:30 -04004486 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4487 return NF_DROP;
4488
Thomas Liu2bf49692009-07-14 12:14:09 -04004489 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004490 ad.u.net.netif = ifindex;
4491 ad.u.net.family = family;
4492 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4493 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Paul Mooredfaebe92008-10-10 10:16:31 -04004495 if (peerlbl_active) {
4496 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4497 peer_sid, &ad);
4498 if (err) {
4499 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004500 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004501 }
4502 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004503
4504 if (secmark_active)
4505 if (avc_has_perm(peer_sid, skb->secmark,
4506 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4507 return NF_DROP;
4508
Paul Moore948bf852008-10-10 10:16:32 -04004509 if (netlbl_active)
4510 /* we do this in the FORWARD path and not the POST_ROUTING
4511 * path because we want to make sure we apply the necessary
4512 * labeling before IPsec is applied so we can leverage AH
4513 * protection */
4514 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4515 return NF_DROP;
4516
Paul Mooreeffad8d2008-01-29 08:49:27 -05004517 return NF_ACCEPT;
4518}
4519
4520static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4521 struct sk_buff *skb,
4522 const struct net_device *in,
4523 const struct net_device *out,
4524 int (*okfn)(struct sk_buff *))
4525{
4526 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4527}
4528
4529#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4530static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4531 struct sk_buff *skb,
4532 const struct net_device *in,
4533 const struct net_device *out,
4534 int (*okfn)(struct sk_buff *))
4535{
4536 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4537}
4538#endif /* IPV6 */
4539
Paul Moore948bf852008-10-10 10:16:32 -04004540static unsigned int selinux_ip_output(struct sk_buff *skb,
4541 u16 family)
4542{
4543 u32 sid;
4544
4545 if (!netlbl_enabled())
4546 return NF_ACCEPT;
4547
4548 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4549 * because we want to make sure we apply the necessary labeling
4550 * before IPsec is applied so we can leverage AH protection */
4551 if (skb->sk) {
4552 struct sk_security_struct *sksec = skb->sk->sk_security;
4553 sid = sksec->sid;
4554 } else
4555 sid = SECINITSID_KERNEL;
4556 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4557 return NF_DROP;
4558
4559 return NF_ACCEPT;
4560}
4561
4562static unsigned int selinux_ipv4_output(unsigned int hooknum,
4563 struct sk_buff *skb,
4564 const struct net_device *in,
4565 const struct net_device *out,
4566 int (*okfn)(struct sk_buff *))
4567{
4568 return selinux_ip_output(skb, PF_INET);
4569}
4570
Paul Mooreeffad8d2008-01-29 08:49:27 -05004571static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4572 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004573 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004574{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004575 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004576 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004577 struct common_audit_data ad;
Paul Moored8395c82008-10-10 10:16:30 -04004578 char *addrp;
4579 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004580
Paul Mooreeffad8d2008-01-29 08:49:27 -05004581 if (sk == NULL)
4582 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004583 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004584
Thomas Liu2bf49692009-07-14 12:14:09 -04004585 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004586 ad.u.net.netif = ifindex;
4587 ad.u.net.family = family;
4588 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4589 return NF_DROP;
4590
Paul Moore58bfbb52009-03-27 17:10:41 -04004591 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004592 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004593 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004594 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004595
Steffen Klassertb9679a72011-02-23 12:55:21 +01004596 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4597 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004598
Paul Mooreeffad8d2008-01-29 08:49:27 -05004599 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600}
4601
Paul Mooreeffad8d2008-01-29 08:49:27 -05004602static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4603 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004605 u32 secmark_perm;
4606 u32 peer_sid;
4607 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004608 struct common_audit_data ad;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004609 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004610 u8 secmark_active;
4611 u8 peerlbl_active;
4612
Paul Mooreeffad8d2008-01-29 08:49:27 -05004613 /* If any sort of compatibility mode is enabled then handoff processing
4614 * to the selinux_ip_postroute_compat() function to deal with the
4615 * special handling. We do this in an attempt to keep this function
4616 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004617 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004618 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004619#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004620 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4621 * packet transformation so allow the packet to pass without any checks
4622 * since we'll have another chance to perform access control checks
4623 * when the packet is on it's final way out.
4624 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4625 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004626 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004627 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004628#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004629 secmark_active = selinux_secmark_enabled();
4630 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4631 if (!secmark_active && !peerlbl_active)
4632 return NF_ACCEPT;
4633
Paul Moored8395c82008-10-10 10:16:30 -04004634 /* if the packet is being forwarded then get the peer label from the
4635 * packet itself; otherwise check to see if it is from a local
4636 * application or the kernel, if from an application get the peer label
4637 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004638 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004639 if (sk == NULL) {
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004640 if (skb->skb_iif) {
4641 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004642 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004643 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004644 } else {
4645 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004646 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004647 }
Paul Moored8395c82008-10-10 10:16:30 -04004648 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004649 struct sk_security_struct *sksec = sk->sk_security;
4650 peer_sid = sksec->sid;
4651 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004652 }
4653
Thomas Liu2bf49692009-07-14 12:14:09 -04004654 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004655 ad.u.net.netif = ifindex;
4656 ad.u.net.family = family;
4657 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004658 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004659
Paul Mooreeffad8d2008-01-29 08:49:27 -05004660 if (secmark_active)
4661 if (avc_has_perm(peer_sid, skb->secmark,
4662 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004663 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004664
4665 if (peerlbl_active) {
4666 u32 if_sid;
4667 u32 node_sid;
4668
4669 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004670 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004671 if (avc_has_perm(peer_sid, if_sid,
4672 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004673 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004674
4675 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004676 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004677 if (avc_has_perm(peer_sid, node_sid,
4678 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004679 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004680 }
4681
4682 return NF_ACCEPT;
4683}
4684
4685static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4686 struct sk_buff *skb,
4687 const struct net_device *in,
4688 const struct net_device *out,
4689 int (*okfn)(struct sk_buff *))
4690{
4691 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692}
4693
4694#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004695static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4696 struct sk_buff *skb,
4697 const struct net_device *in,
4698 const struct net_device *out,
4699 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004701 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703#endif /* IPV6 */
4704
4705#endif /* CONFIG_NETFILTER */
4706
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4708{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 int err;
4710
Eric Paris200ac532009-02-12 15:01:04 -05004711 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 if (err)
4713 return err;
4714
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004715 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716}
4717
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718static int ipc_alloc_security(struct task_struct *task,
4719 struct kern_ipc_perm *perm,
4720 u16 sclass)
4721{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004723 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
James Morris89d155e2005-10-30 14:59:21 -08004725 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 if (!isec)
4727 return -ENOMEM;
4728
David Howells275bb412008-11-14 10:39:19 +11004729 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004731 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 perm->security = isec;
4733
4734 return 0;
4735}
4736
4737static void ipc_free_security(struct kern_ipc_perm *perm)
4738{
4739 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 perm->security = NULL;
4741 kfree(isec);
4742}
4743
4744static int msg_msg_alloc_security(struct msg_msg *msg)
4745{
4746 struct msg_security_struct *msec;
4747
James Morris89d155e2005-10-30 14:59:21 -08004748 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 if (!msec)
4750 return -ENOMEM;
4751
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 msec->sid = SECINITSID_UNLABELED;
4753 msg->security = msec;
4754
4755 return 0;
4756}
4757
4758static void msg_msg_free_security(struct msg_msg *msg)
4759{
4760 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
4762 msg->security = NULL;
4763 kfree(msec);
4764}
4765
4766static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004767 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004770 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004771 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 isec = ipc_perms->security;
4774
Thomas Liu2bf49692009-07-14 12:14:09 -04004775 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 ad.u.ipc_id = ipc_perms->key;
4777
David Howells275bb412008-11-14 10:39:19 +11004778 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779}
4780
4781static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4782{
4783 return msg_msg_alloc_security(msg);
4784}
4785
4786static void selinux_msg_msg_free_security(struct msg_msg *msg)
4787{
4788 msg_msg_free_security(msg);
4789}
4790
4791/* message queue security operations */
4792static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4793{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004795 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004796 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 int rc;
4798
4799 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4800 if (rc)
4801 return rc;
4802
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 isec = msq->q_perm.security;
4804
Thomas Liu2bf49692009-07-14 12:14:09 -04004805 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004806 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
David Howells275bb412008-11-14 10:39:19 +11004808 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 MSGQ__CREATE, &ad);
4810 if (rc) {
4811 ipc_free_security(&msq->q_perm);
4812 return rc;
4813 }
4814 return 0;
4815}
4816
4817static void selinux_msg_queue_free_security(struct msg_queue *msq)
4818{
4819 ipc_free_security(&msq->q_perm);
4820}
4821
4822static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4823{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004825 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004826 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 isec = msq->q_perm.security;
4829
Thomas Liu2bf49692009-07-14 12:14:09 -04004830 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 ad.u.ipc_id = msq->q_perm.key;
4832
David Howells275bb412008-11-14 10:39:19 +11004833 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 MSGQ__ASSOCIATE, &ad);
4835}
4836
4837static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4838{
4839 int err;
4840 int perms;
4841
Eric Paris828dfe12008-04-17 13:17:49 -04004842 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 case IPC_INFO:
4844 case MSG_INFO:
4845 /* No specific object, just general system-wide information. */
4846 return task_has_system(current, SYSTEM__IPC_INFO);
4847 case IPC_STAT:
4848 case MSG_STAT:
4849 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4850 break;
4851 case IPC_SET:
4852 perms = MSGQ__SETATTR;
4853 break;
4854 case IPC_RMID:
4855 perms = MSGQ__DESTROY;
4856 break;
4857 default:
4858 return 0;
4859 }
4860
Stephen Smalley6af963f2005-05-01 08:58:39 -07004861 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 return err;
4863}
4864
4865static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4866{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 struct ipc_security_struct *isec;
4868 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004869 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004870 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 int rc;
4872
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 isec = msq->q_perm.security;
4874 msec = msg->security;
4875
4876 /*
4877 * First time through, need to assign label to the message
4878 */
4879 if (msec->sid == SECINITSID_UNLABELED) {
4880 /*
4881 * Compute new sid based on current process and
4882 * message queue this message will be stored in
4883 */
David Howells275bb412008-11-14 10:39:19 +11004884 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05004885 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 if (rc)
4887 return rc;
4888 }
4889
Thomas Liu2bf49692009-07-14 12:14:09 -04004890 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 ad.u.ipc_id = msq->q_perm.key;
4892
4893 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004894 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 MSGQ__WRITE, &ad);
4896 if (!rc)
4897 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11004898 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
4899 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 if (!rc)
4901 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11004902 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
4903 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904
4905 return rc;
4906}
4907
4908static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
4909 struct task_struct *target,
4910 long type, int mode)
4911{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 struct ipc_security_struct *isec;
4913 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004914 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004915 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 int rc;
4917
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 isec = msq->q_perm.security;
4919 msec = msg->security;
4920
Thomas Liu2bf49692009-07-14 12:14:09 -04004921 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004922 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923
David Howells275bb412008-11-14 10:39:19 +11004924 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 SECCLASS_MSGQ, MSGQ__READ, &ad);
4926 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11004927 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 SECCLASS_MSG, MSG__RECEIVE, &ad);
4929 return rc;
4930}
4931
4932/* Shared Memory security operations */
4933static int selinux_shm_alloc_security(struct shmid_kernel *shp)
4934{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004936 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004937 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 int rc;
4939
4940 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
4941 if (rc)
4942 return rc;
4943
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944 isec = shp->shm_perm.security;
4945
Thomas Liu2bf49692009-07-14 12:14:09 -04004946 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004947 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948
David Howells275bb412008-11-14 10:39:19 +11004949 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 SHM__CREATE, &ad);
4951 if (rc) {
4952 ipc_free_security(&shp->shm_perm);
4953 return rc;
4954 }
4955 return 0;
4956}
4957
4958static void selinux_shm_free_security(struct shmid_kernel *shp)
4959{
4960 ipc_free_security(&shp->shm_perm);
4961}
4962
4963static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
4964{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004966 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004967 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 isec = shp->shm_perm.security;
4970
Thomas Liu2bf49692009-07-14 12:14:09 -04004971 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 ad.u.ipc_id = shp->shm_perm.key;
4973
David Howells275bb412008-11-14 10:39:19 +11004974 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 SHM__ASSOCIATE, &ad);
4976}
4977
4978/* Note, at this point, shp is locked down */
4979static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
4980{
4981 int perms;
4982 int err;
4983
Eric Paris828dfe12008-04-17 13:17:49 -04004984 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 case IPC_INFO:
4986 case SHM_INFO:
4987 /* No specific object, just general system-wide information. */
4988 return task_has_system(current, SYSTEM__IPC_INFO);
4989 case IPC_STAT:
4990 case SHM_STAT:
4991 perms = SHM__GETATTR | SHM__ASSOCIATE;
4992 break;
4993 case IPC_SET:
4994 perms = SHM__SETATTR;
4995 break;
4996 case SHM_LOCK:
4997 case SHM_UNLOCK:
4998 perms = SHM__LOCK;
4999 break;
5000 case IPC_RMID:
5001 perms = SHM__DESTROY;
5002 break;
5003 default:
5004 return 0;
5005 }
5006
Stephen Smalley6af963f2005-05-01 08:58:39 -07005007 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 return err;
5009}
5010
5011static int selinux_shm_shmat(struct shmid_kernel *shp,
5012 char __user *shmaddr, int shmflg)
5013{
5014 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015
5016 if (shmflg & SHM_RDONLY)
5017 perms = SHM__READ;
5018 else
5019 perms = SHM__READ | SHM__WRITE;
5020
Stephen Smalley6af963f2005-05-01 08:58:39 -07005021 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022}
5023
5024/* Semaphore security operations */
5025static int selinux_sem_alloc_security(struct sem_array *sma)
5026{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005028 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005029 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 int rc;
5031
5032 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5033 if (rc)
5034 return rc;
5035
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 isec = sma->sem_perm.security;
5037
Thomas Liu2bf49692009-07-14 12:14:09 -04005038 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005039 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040
David Howells275bb412008-11-14 10:39:19 +11005041 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 SEM__CREATE, &ad);
5043 if (rc) {
5044 ipc_free_security(&sma->sem_perm);
5045 return rc;
5046 }
5047 return 0;
5048}
5049
5050static void selinux_sem_free_security(struct sem_array *sma)
5051{
5052 ipc_free_security(&sma->sem_perm);
5053}
5054
5055static int selinux_sem_associate(struct sem_array *sma, int semflg)
5056{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005058 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005059 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 isec = sma->sem_perm.security;
5062
Thomas Liu2bf49692009-07-14 12:14:09 -04005063 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 ad.u.ipc_id = sma->sem_perm.key;
5065
David Howells275bb412008-11-14 10:39:19 +11005066 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 SEM__ASSOCIATE, &ad);
5068}
5069
5070/* Note, at this point, sma is locked down */
5071static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5072{
5073 int err;
5074 u32 perms;
5075
Eric Paris828dfe12008-04-17 13:17:49 -04005076 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 case IPC_INFO:
5078 case SEM_INFO:
5079 /* No specific object, just general system-wide information. */
5080 return task_has_system(current, SYSTEM__IPC_INFO);
5081 case GETPID:
5082 case GETNCNT:
5083 case GETZCNT:
5084 perms = SEM__GETATTR;
5085 break;
5086 case GETVAL:
5087 case GETALL:
5088 perms = SEM__READ;
5089 break;
5090 case SETVAL:
5091 case SETALL:
5092 perms = SEM__WRITE;
5093 break;
5094 case IPC_RMID:
5095 perms = SEM__DESTROY;
5096 break;
5097 case IPC_SET:
5098 perms = SEM__SETATTR;
5099 break;
5100 case IPC_STAT:
5101 case SEM_STAT:
5102 perms = SEM__GETATTR | SEM__ASSOCIATE;
5103 break;
5104 default:
5105 return 0;
5106 }
5107
Stephen Smalley6af963f2005-05-01 08:58:39 -07005108 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 return err;
5110}
5111
5112static int selinux_sem_semop(struct sem_array *sma,
5113 struct sembuf *sops, unsigned nsops, int alter)
5114{
5115 u32 perms;
5116
5117 if (alter)
5118 perms = SEM__READ | SEM__WRITE;
5119 else
5120 perms = SEM__READ;
5121
Stephen Smalley6af963f2005-05-01 08:58:39 -07005122 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123}
5124
5125static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5126{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 u32 av = 0;
5128
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 av = 0;
5130 if (flag & S_IRUGO)
5131 av |= IPC__UNIX_READ;
5132 if (flag & S_IWUGO)
5133 av |= IPC__UNIX_WRITE;
5134
5135 if (av == 0)
5136 return 0;
5137
Stephen Smalley6af963f2005-05-01 08:58:39 -07005138 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139}
5140
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005141static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5142{
5143 struct ipc_security_struct *isec = ipcp->security;
5144 *secid = isec->sid;
5145}
5146
Eric Paris828dfe12008-04-17 13:17:49 -04005147static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148{
5149 if (inode)
5150 inode_doinit_with_dentry(inode, dentry);
5151}
5152
5153static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005154 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155{
David Howells275bb412008-11-14 10:39:19 +11005156 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005157 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005159 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160
5161 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005162 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 if (error)
5164 return error;
5165 }
5166
David Howells275bb412008-11-14 10:39:19 +11005167 rcu_read_lock();
5168 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169
5170 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005171 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005173 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005175 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005177 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005178 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005179 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005180 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005181 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 else
David Howells275bb412008-11-14 10:39:19 +11005183 goto invalid;
5184 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185
5186 if (!sid)
5187 return 0;
5188
Al Viro04ff9702007-03-12 16:17:58 +00005189 error = security_sid_to_context(sid, value, &len);
5190 if (error)
5191 return error;
5192 return len;
David Howells275bb412008-11-14 10:39:19 +11005193
5194invalid:
5195 rcu_read_unlock();
5196 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197}
5198
5199static int selinux_setprocattr(struct task_struct *p,
5200 char *name, void *value, size_t size)
5201{
5202 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005203 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005204 struct cred *new;
5205 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 int error;
5207 char *str = value;
5208
5209 if (current != p) {
5210 /* SELinux only allows a process to change its own
5211 security attributes. */
5212 return -EACCES;
5213 }
5214
5215 /*
5216 * Basic control over ability to set these attributes at all.
5217 * current == p, but we'll pass them separately in case the
5218 * above restriction is ever removed.
5219 */
5220 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005221 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005223 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005224 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005225 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005226 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005227 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005229 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 else
5231 error = -EINVAL;
5232 if (error)
5233 return error;
5234
5235 /* Obtain a SID for the context, if one was specified. */
5236 if (size && str[1] && str[1] != '\n') {
5237 if (str[size-1] == '\n') {
5238 str[size-1] = 0;
5239 size--;
5240 }
5241 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005242 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5243 if (!capable(CAP_MAC_ADMIN))
5244 return error;
5245 error = security_context_to_sid_force(value, size,
5246 &sid);
5247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 if (error)
5249 return error;
5250 }
5251
David Howellsd84f4f92008-11-14 10:39:23 +11005252 new = prepare_creds();
5253 if (!new)
5254 return -ENOMEM;
5255
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 /* Permission checking based on the specified context is
5257 performed during the actual operation (execve,
5258 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005259 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 checks and may_create for the file creation checks. The
5261 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005262 tsec = new->security;
5263 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005265 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005267 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005268 error = may_create_key(sid, p);
5269 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005270 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005271 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005272 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005273 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005274 } else if (!strcmp(name, "current")) {
5275 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005277 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005278
David Howellsd84f4f92008-11-14 10:39:23 +11005279 /* Only allow single threaded processes to change context */
5280 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005281 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005282 error = security_bounded_transition(tsec->sid, sid);
5283 if (error)
5284 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
5287 /* Check permissions for the transition. */
5288 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005289 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005291 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
5293 /* Check for ptracing, and update the task SID if ok.
5294 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005295 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 task_lock(p);
Tejun Heo06d98472011-06-17 16:50:40 +02005297 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005298 if (tracer)
5299 ptsid = task_sid(tracer);
5300 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301
David Howellsd84f4f92008-11-14 10:39:23 +11005302 if (tracer) {
5303 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5304 PROCESS__PTRACE, NULL);
5305 if (error)
5306 goto abort_change;
5307 }
5308
5309 tsec->sid = sid;
5310 } else {
5311 error = -EINVAL;
5312 goto abort_change;
5313 }
5314
5315 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005317
5318abort_change:
5319 abort_creds(new);
5320 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321}
5322
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005323static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5324{
5325 return security_sid_to_context(secid, secdata, seclen);
5326}
5327
David Howells7bf570d2008-04-29 20:52:51 +01005328static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005329{
5330 return security_context_to_sid(secdata, seclen, secid);
5331}
5332
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005333static void selinux_release_secctx(char *secdata, u32 seclen)
5334{
Paul Moore088999e2007-08-01 11:12:58 -04005335 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005336}
5337
David P. Quigley1ee65e32009-09-03 14:25:57 -04005338/*
5339 * called with inode->i_mutex locked
5340 */
5341static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5342{
5343 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5344}
5345
5346/*
5347 * called with inode->i_mutex locked
5348 */
5349static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5350{
5351 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5352}
5353
5354static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5355{
5356 int len = 0;
5357 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5358 ctx, true);
5359 if (len < 0)
5360 return len;
5361 *ctxlen = len;
5362 return 0;
5363}
Michael LeMayd7200242006-06-22 14:47:17 -07005364#ifdef CONFIG_KEYS
5365
David Howellsd84f4f92008-11-14 10:39:23 +11005366static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005367 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005368{
David Howellsd84f4f92008-11-14 10:39:23 +11005369 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005370 struct key_security_struct *ksec;
5371
5372 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5373 if (!ksec)
5374 return -ENOMEM;
5375
David Howellsd84f4f92008-11-14 10:39:23 +11005376 tsec = cred->security;
5377 if (tsec->keycreate_sid)
5378 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005379 else
David Howellsd84f4f92008-11-14 10:39:23 +11005380 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005381
David Howells275bb412008-11-14 10:39:19 +11005382 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005383 return 0;
5384}
5385
5386static void selinux_key_free(struct key *k)
5387{
5388 struct key_security_struct *ksec = k->security;
5389
5390 k->security = NULL;
5391 kfree(ksec);
5392}
5393
5394static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005395 const struct cred *cred,
5396 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005397{
5398 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005399 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005400 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005401
5402 /* if no specific permissions are requested, we skip the
5403 permission check. No serious, additional covert channels
5404 appear to be created. */
5405 if (perm == 0)
5406 return 0;
5407
David Howellsd84f4f92008-11-14 10:39:23 +11005408 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005409
5410 key = key_ref_to_ptr(key_ref);
5411 ksec = key->security;
5412
5413 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005414}
5415
David Howells70a5bb72008-04-29 01:01:26 -07005416static int selinux_key_getsecurity(struct key *key, char **_buffer)
5417{
5418 struct key_security_struct *ksec = key->security;
5419 char *context = NULL;
5420 unsigned len;
5421 int rc;
5422
5423 rc = security_sid_to_context(ksec->sid, &context, &len);
5424 if (!rc)
5425 rc = len;
5426 *_buffer = context;
5427 return rc;
5428}
5429
Michael LeMayd7200242006-06-22 14:47:17 -07005430#endif
5431
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005433 .name = "selinux",
5434
Ingo Molnar9e488582009-05-07 19:26:19 +10005435 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005436 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005438 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 .capable = selinux_capable,
5440 .quotactl = selinux_quotactl,
5441 .quota_on = selinux_quota_on,
5442 .syslog = selinux_syslog,
5443 .vm_enough_memory = selinux_vm_enough_memory,
5444
5445 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
David Howellsa6f76f22008-11-14 10:39:24 +11005447 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005448 .bprm_committing_creds = selinux_bprm_committing_creds,
5449 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 .bprm_secureexec = selinux_bprm_secureexec,
5451
5452 .sb_alloc_security = selinux_sb_alloc_security,
5453 .sb_free_security = selinux_sb_free_security,
5454 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005455 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005456 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005457 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 .sb_statfs = selinux_sb_statfs,
5459 .sb_mount = selinux_mount,
5460 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005461 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005462 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005463 .sb_parse_opts_str = selinux_parse_opts_str,
5464
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465
5466 .inode_alloc_security = selinux_inode_alloc_security,
5467 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005468 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 .inode_unlink = selinux_inode_unlink,
5472 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 .inode_rmdir = selinux_inode_rmdir,
5475 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 .inode_readlink = selinux_inode_readlink,
5478 .inode_follow_link = selinux_inode_follow_link,
5479 .inode_permission = selinux_inode_permission,
5480 .inode_setattr = selinux_inode_setattr,
5481 .inode_getattr = selinux_inode_getattr,
5482 .inode_setxattr = selinux_inode_setxattr,
5483 .inode_post_setxattr = selinux_inode_post_setxattr,
5484 .inode_getxattr = selinux_inode_getxattr,
5485 .inode_listxattr = selinux_inode_listxattr,
5486 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005487 .inode_getsecurity = selinux_inode_getsecurity,
5488 .inode_setsecurity = selinux_inode_setsecurity,
5489 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005490 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491
5492 .file_permission = selinux_file_permission,
5493 .file_alloc_security = selinux_file_alloc_security,
5494 .file_free_security = selinux_file_free_security,
5495 .file_ioctl = selinux_file_ioctl,
5496 .file_mmap = selinux_file_mmap,
5497 .file_mprotect = selinux_file_mprotect,
5498 .file_lock = selinux_file_lock,
5499 .file_fcntl = selinux_file_fcntl,
5500 .file_set_fowner = selinux_file_set_fowner,
5501 .file_send_sigiotask = selinux_file_send_sigiotask,
5502 .file_receive = selinux_file_receive,
5503
Eric Paris828dfe12008-04-17 13:17:49 -04005504 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005505
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005507 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005508 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005509 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005510 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005511 .kernel_act_as = selinux_kernel_act_as,
5512 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005513 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 .task_setpgid = selinux_task_setpgid,
5515 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005516 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005517 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005519 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005520 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 .task_setrlimit = selinux_task_setrlimit,
5522 .task_setscheduler = selinux_task_setscheduler,
5523 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005524 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 .task_kill = selinux_task_kill,
5526 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005527 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
5529 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005530 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531
5532 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5533 .msg_msg_free_security = selinux_msg_msg_free_security,
5534
5535 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5536 .msg_queue_free_security = selinux_msg_queue_free_security,
5537 .msg_queue_associate = selinux_msg_queue_associate,
5538 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5539 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5540 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5541
5542 .shm_alloc_security = selinux_shm_alloc_security,
5543 .shm_free_security = selinux_shm_free_security,
5544 .shm_associate = selinux_shm_associate,
5545 .shm_shmctl = selinux_shm_shmctl,
5546 .shm_shmat = selinux_shm_shmat,
5547
Eric Paris828dfe12008-04-17 13:17:49 -04005548 .sem_alloc_security = selinux_sem_alloc_security,
5549 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 .sem_associate = selinux_sem_associate,
5551 .sem_semctl = selinux_sem_semctl,
5552 .sem_semop = selinux_sem_semop,
5553
Eric Paris828dfe12008-04-17 13:17:49 -04005554 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555
Eric Paris828dfe12008-04-17 13:17:49 -04005556 .getprocattr = selinux_getprocattr,
5557 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005559 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005560 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005561 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005562 .inode_notifysecctx = selinux_inode_notifysecctx,
5563 .inode_setsecctx = selinux_inode_setsecctx,
5564 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005565
Eric Paris828dfe12008-04-17 13:17:49 -04005566 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 .unix_may_send = selinux_socket_unix_may_send,
5568
5569 .socket_create = selinux_socket_create,
5570 .socket_post_create = selinux_socket_post_create,
5571 .socket_bind = selinux_socket_bind,
5572 .socket_connect = selinux_socket_connect,
5573 .socket_listen = selinux_socket_listen,
5574 .socket_accept = selinux_socket_accept,
5575 .socket_sendmsg = selinux_socket_sendmsg,
5576 .socket_recvmsg = selinux_socket_recvmsg,
5577 .socket_getsockname = selinux_socket_getsockname,
5578 .socket_getpeername = selinux_socket_getpeername,
5579 .socket_getsockopt = selinux_socket_getsockopt,
5580 .socket_setsockopt = selinux_socket_setsockopt,
5581 .socket_shutdown = selinux_socket_shutdown,
5582 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005583 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5584 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 .sk_alloc_security = selinux_sk_alloc_security,
5586 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005587 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005588 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005589 .sock_graft = selinux_sock_graft,
5590 .inet_conn_request = selinux_inet_conn_request,
5591 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005592 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005593 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5594 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5595 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005596 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005597 .tun_dev_create = selinux_tun_dev_create,
5598 .tun_dev_post_create = selinux_tun_dev_post_create,
5599 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005600
5601#ifdef CONFIG_SECURITY_NETWORK_XFRM
5602 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5603 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5604 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005605 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005606 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5607 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005608 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005609 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005610 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005611 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005613
5614#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005615 .key_alloc = selinux_key_alloc,
5616 .key_free = selinux_key_free,
5617 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005618 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005619#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005620
5621#ifdef CONFIG_AUDIT
5622 .audit_rule_init = selinux_audit_rule_init,
5623 .audit_rule_known = selinux_audit_rule_known,
5624 .audit_rule_match = selinux_audit_rule_match,
5625 .audit_rule_free = selinux_audit_rule_free,
5626#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627};
5628
5629static __init int selinux_init(void)
5630{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005631 if (!security_module_enable(&selinux_ops)) {
5632 selinux_enabled = 0;
5633 return 0;
5634 }
5635
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 if (!selinux_enabled) {
5637 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5638 return 0;
5639 }
5640
5641 printk(KERN_INFO "SELinux: Initializing.\n");
5642
5643 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005644 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005646 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5647
James Morris7cae7e22006-03-22 00:09:22 -08005648 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5649 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005650 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 avc_init();
5652
Eric Paris828dfe12008-04-17 13:17:49 -04005653 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 panic("SELinux: Unable to register with kernel.\n");
5655
Eric Paris828dfe12008-04-17 13:17:49 -04005656 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005657 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005658 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005659 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005660
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 return 0;
5662}
5663
Al Viroe8c26252010-03-23 06:36:54 -04005664static void delayed_superblock_init(struct super_block *sb, void *unused)
5665{
5666 superblock_doinit(sb, NULL);
5667}
5668
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669void selinux_complete_init(void)
5670{
Eric Parisfadcdb42007-02-22 18:11:31 -05005671 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672
5673 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005674 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005675 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676}
5677
5678/* SELinux requires early initialization in order to label
5679 all processes and objects when they are created. */
5680security_initcall(selinux_init);
5681
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005682#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683
Paul Mooreeffad8d2008-01-29 08:49:27 -05005684static struct nf_hook_ops selinux_ipv4_ops[] = {
5685 {
5686 .hook = selinux_ipv4_postroute,
5687 .owner = THIS_MODULE,
5688 .pf = PF_INET,
5689 .hooknum = NF_INET_POST_ROUTING,
5690 .priority = NF_IP_PRI_SELINUX_LAST,
5691 },
5692 {
5693 .hook = selinux_ipv4_forward,
5694 .owner = THIS_MODULE,
5695 .pf = PF_INET,
5696 .hooknum = NF_INET_FORWARD,
5697 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005698 },
5699 {
5700 .hook = selinux_ipv4_output,
5701 .owner = THIS_MODULE,
5702 .pf = PF_INET,
5703 .hooknum = NF_INET_LOCAL_OUT,
5704 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706};
5707
5708#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5709
Paul Mooreeffad8d2008-01-29 08:49:27 -05005710static struct nf_hook_ops selinux_ipv6_ops[] = {
5711 {
5712 .hook = selinux_ipv6_postroute,
5713 .owner = THIS_MODULE,
5714 .pf = PF_INET6,
5715 .hooknum = NF_INET_POST_ROUTING,
5716 .priority = NF_IP6_PRI_SELINUX_LAST,
5717 },
5718 {
5719 .hook = selinux_ipv6_forward,
5720 .owner = THIS_MODULE,
5721 .pf = PF_INET6,
5722 .hooknum = NF_INET_FORWARD,
5723 .priority = NF_IP6_PRI_SELINUX_FIRST,
5724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725};
5726
5727#endif /* IPV6 */
5728
5729static int __init selinux_nf_ip_init(void)
5730{
5731 int err = 0;
5732
5733 if (!selinux_enabled)
5734 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005735
5736 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5737
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005738 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5739 if (err)
5740 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741
5742#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005743 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5744 if (err)
5745 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005747
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748out:
5749 return err;
5750}
5751
5752__initcall(selinux_nf_ip_init);
5753
5754#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5755static void selinux_nf_ip_exit(void)
5756{
Eric Parisfadcdb42007-02-22 18:11:31 -05005757 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005759 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005761 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762#endif /* IPV6 */
5763}
5764#endif
5765
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005766#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767
5768#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5769#define selinux_nf_ip_exit()
5770#endif
5771
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005772#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
5774#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005775static int selinux_disabled;
5776
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777int selinux_disable(void)
5778{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 if (ss_initialized) {
5780 /* Not permitted after initial policy load. */
5781 return -EINVAL;
5782 }
5783
5784 if (selinux_disabled) {
5785 /* Only do this once. */
5786 return -EINVAL;
5787 }
5788
5789 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5790
5791 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005792 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08005794 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Eric Parisaf8ff042009-09-20 21:23:01 -04005796 /* Try to destroy the avc node cache */
5797 avc_disable();
5798
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 /* Unregister netfilter hooks. */
5800 selinux_nf_ip_exit();
5801
5802 /* Unregister selinuxfs. */
5803 exit_sel_fs();
5804
5805 return 0;
5806}
5807#endif