blob: a29d6612a328c30a2cfdb1225780023ad71fb296 [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.
17 * Paul Moore <paul.moore@hp.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>
27#include <linux/kernel.h>
Roland McGrath0d094ef2008-07-25 19:45:49 -070028#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/errno.h>
30#include <linux/sched.h>
31#include <linux/security.h>
32#include <linux/xattr.h>
33#include <linux/capability.h>
34#include <linux/unistd.h>
35#include <linux/mm.h>
36#include <linux/mman.h>
37#include <linux/slab.h>
38#include <linux/pagemap.h>
39#include <linux/swap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/spinlock.h>
41#include <linux/syscalls.h>
42#include <linux/file.h>
Al Viro9f3acc32008-04-24 07:44:08 -040043#include <linux/fdtable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/namei.h>
45#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/netfilter_ipv4.h>
48#include <linux/netfilter_ipv6.h>
49#include <linux/tty.h>
50#include <net/icmp.h>
Stephen Hemminger227b60f2007-10-10 17:30:46 -070051#include <net/ip.h> /* for local_port_range[] */
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
Paul Moore220deb92008-01-29 08:38:23 -050053#include <net/net_namespace.h>
Paul Moored621d352008-01-29 08:43:36 -050054#include <net/netlabel.h>
Eric Parisf5269712008-05-14 11:27:45 -040055#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <asm/ioctls.h>
Paul Moored621d352008-01-29 08:43:36 -050057#include <asm/atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <linux/bitops.h>
59#include <linux/interrupt.h>
60#include <linux/netdevice.h> /* for network interface checks */
61#include <linux/netlink.h>
62#include <linux/tcp.h>
63#include <linux/udp.h>
James Morris2ee92d42006-11-13 16:09:01 -080064#include <linux/dccp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <linux/quota.h>
66#include <linux/un.h> /* for Unix socket types */
67#include <net/af_unix.h> /* for Unix socket types */
68#include <linux/parser.h>
69#include <linux/nfs_mount.h>
70#include <net/ipv6.h>
71#include <linux/hugetlb.h>
72#include <linux/personality.h>
73#include <linux/sysctl.h>
74#include <linux/audit.h>
Eric Paris6931dfc2005-06-30 02:58:51 -070075#include <linux/string.h>
Catherine Zhang877ce7c2006-06-29 12:27:47 -070076#include <linux/selinux.h>
Eric Paris23970742006-09-25 23:32:01 -070077#include <linux/mutex.h>
Frank Mayharf06febc2008-09-12 09:54:39 -070078#include <linux/posix-timers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80#include "avc.h"
81#include "objsec.h"
82#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050083#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040084#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080085#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050086#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020087#include "audit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89#define XATTR_SELINUX_SUFFIX "selinux"
90#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
91
David P. Quigley11689d42009-01-16 09:22:03 -050092#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
James Morris20510f22007-10-16 23:31:32 -070095extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Paul Moored621d352008-01-29 08:43:36 -050097/* SECMARK reference count */
98atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400101int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103static int __init enforcing_setup(char *str)
104{
Eric Parisf5269712008-05-14 11:27:45 -0400105 unsigned long enforcing;
106 if (!strict_strtoul(str, 0, &enforcing))
107 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 return 1;
109}
110__setup("enforcing=", enforcing_setup);
111#endif
112
113#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
114int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
115
116static int __init selinux_enabled_setup(char *str)
117{
Eric Parisf5269712008-05-14 11:27:45 -0400118 unsigned long enabled;
119 if (!strict_strtoul(str, 0, &enabled))
120 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 return 1;
122}
123__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400124#else
125int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#endif
127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
James Morris6f0f0fd2008-07-10 17:02:07 +0900129/*
130 * Minimal support for a secondary security module,
131 * just to allow the use of the capability module.
132 */
Eric Paris828dfe12008-04-17 13:17:49 -0400133static struct security_operations *secondary_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
135/* Lists of inode and superblock security structures initialized
136 before the policy was loaded. */
137static LIST_HEAD(superblock_security_head);
138static DEFINE_SPINLOCK(sb_security_lock);
139
Christoph Lametere18b8902006-12-06 20:33:20 -0800140static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800141
Paul Moored621d352008-01-29 08:43:36 -0500142/**
143 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
144 *
145 * Description:
146 * This function checks the SECMARK reference counter to see if any SECMARK
147 * targets are currently configured, if the reference counter is greater than
148 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
149 * enabled, false (0) if SECMARK is disabled.
150 *
151 */
152static int selinux_secmark_enabled(void)
153{
154 return (atomic_read(&selinux_secmark_refcount) > 0);
155}
156
David Howellsd84f4f92008-11-14 10:39:23 +1100157/*
158 * initialise the security for the init task
159 */
160static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
David Howells3b11a1d2008-11-14 10:39:26 +1100162 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 struct task_security_struct *tsec;
164
James Morris89d155e2005-10-30 14:59:21 -0800165 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100167 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
David Howellsd84f4f92008-11-14 10:39:23 +1100169 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100170 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
David Howells275bb412008-11-14 10:39:19 +1100173/*
David Howells88e67f32008-11-14 10:39:21 +1100174 * get the security ID of a set of credentials
175 */
176static inline u32 cred_sid(const struct cred *cred)
177{
178 const struct task_security_struct *tsec;
179
180 tsec = cred->security;
181 return tsec->sid;
182}
183
184/*
David Howells3b11a1d2008-11-14 10:39:26 +1100185 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100186 */
187static inline u32 task_sid(const struct task_struct *task)
188{
David Howells275bb412008-11-14 10:39:19 +1100189 u32 sid;
190
191 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100192 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100193 rcu_read_unlock();
194 return sid;
195}
196
197/*
David Howells3b11a1d2008-11-14 10:39:26 +1100198 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100199 */
200static inline u32 current_sid(void)
201{
202 const struct task_security_struct *tsec = current_cred()->security;
203
204 return tsec->sid;
205}
206
David Howells88e67f32008-11-14 10:39:21 +1100207/* Allocate and free functions for each kind of security blob. */
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static int inode_alloc_security(struct inode *inode)
210{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100212 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Josef Bacika02fe132008-04-04 09:35:05 +1100214 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 if (!isec)
216 return -ENOMEM;
217
Eric Paris23970742006-09-25 23:32:01 -0700218 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 isec->inode = inode;
221 isec->sid = SECINITSID_UNLABELED;
222 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100223 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 inode->i_security = isec;
225
226 return 0;
227}
228
229static void inode_free_security(struct inode *inode)
230{
231 struct inode_security_struct *isec = inode->i_security;
232 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 spin_lock(&sbsec->isec_lock);
235 if (!list_empty(&isec->list))
236 list_del_init(&isec->list);
237 spin_unlock(&sbsec->isec_lock);
238
239 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800240 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241}
242
243static int file_alloc_security(struct file *file)
244{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100246 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800248 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if (!fsec)
250 return -ENOMEM;
251
David Howells275bb412008-11-14 10:39:19 +1100252 fsec->sid = sid;
253 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 file->f_security = fsec;
255
256 return 0;
257}
258
259static void file_free_security(struct file *file)
260{
261 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 file->f_security = NULL;
263 kfree(fsec);
264}
265
266static int superblock_alloc_security(struct super_block *sb)
267{
268 struct superblock_security_struct *sbsec;
269
James Morris89d155e2005-10-30 14:59:21 -0800270 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 if (!sbsec)
272 return -ENOMEM;
273
Eric Parisbc7e9822006-09-25 23:32:02 -0700274 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 INIT_LIST_HEAD(&sbsec->list);
276 INIT_LIST_HEAD(&sbsec->isec_head);
277 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 sbsec->sb = sb;
279 sbsec->sid = SECINITSID_UNLABELED;
280 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700281 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 sb->s_security = sbsec;
283
284 return 0;
285}
286
287static void superblock_free_security(struct super_block *sb)
288{
289 struct superblock_security_struct *sbsec = sb->s_security;
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 spin_lock(&sb_security_lock);
292 if (!list_empty(&sbsec->list))
293 list_del_init(&sbsec->list);
294 spin_unlock(&sb_security_lock);
295
296 sb->s_security = NULL;
297 kfree(sbsec);
298}
299
Al Viro7d877f32005-10-21 03:20:43 -0400300static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 struct sk_security_struct *ssec;
303
James Morris89d155e2005-10-30 14:59:21 -0800304 ssec = kzalloc(sizeof(*ssec), priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 if (!ssec)
306 return -ENOMEM;
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 ssec->peer_sid = SECINITSID_UNLABELED;
Venkat Yekkirala892c1412006-08-04 23:08:56 -0700309 ssec->sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 sk->sk_security = ssec;
311
Paul Moore389fb802009-03-27 17:10:34 -0400312 selinux_netlbl_sk_security_reset(ssec);
Paul Moore99f59ed2006-08-29 17:53:48 -0700313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 return 0;
315}
316
317static void sk_free_security(struct sock *sk)
318{
319 struct sk_security_struct *ssec = sk->sk_security;
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 sk->sk_security = NULL;
Paul Moore6c5b3fc2008-10-10 10:16:33 -0400322 selinux_netlbl_sk_security_free(ssec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 kfree(ssec);
324}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326/* The security server must be initialized before
327 any labeling or access decisions can be provided. */
328extern int ss_initialized;
329
330/* The file system's label must be initialized prior to use. */
331
332static char *labeling_behaviors[6] = {
333 "uses xattr",
334 "uses transition SIDs",
335 "uses task SIDs",
336 "uses genfs_contexts",
337 "not configured for labeling",
338 "uses mountpoint labeling",
339};
340
341static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
342
343static inline int inode_doinit(struct inode *inode)
344{
345 return inode_doinit_with_dentry(inode, NULL);
346}
347
348enum {
Eric Paris31e87932007-09-19 17:19:12 -0400349 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 Opt_context = 1,
351 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500352 Opt_defcontext = 3,
353 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500354 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355};
356
Steven Whitehousea447c092008-10-13 10:46:57 +0100357static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400358 {Opt_context, CONTEXT_STR "%s"},
359 {Opt_fscontext, FSCONTEXT_STR "%s"},
360 {Opt_defcontext, DEFCONTEXT_STR "%s"},
361 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500362 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400363 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364};
365
366#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
367
Eric Parisc312feb2006-07-10 04:43:53 -0700368static int may_context_mount_sb_relabel(u32 sid,
369 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100370 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700371{
David Howells275bb412008-11-14 10:39:19 +1100372 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700373 int rc;
374
375 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
376 FILESYSTEM__RELABELFROM, NULL);
377 if (rc)
378 return rc;
379
380 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
381 FILESYSTEM__RELABELTO, NULL);
382 return rc;
383}
384
Eric Paris08089252006-07-10 04:43:55 -0700385static int may_context_mount_inode_relabel(u32 sid,
386 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100387 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700388{
David Howells275bb412008-11-14 10:39:19 +1100389 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700390 int rc;
391 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
392 FILESYSTEM__RELABELFROM, NULL);
393 if (rc)
394 return rc;
395
396 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
397 FILESYSTEM__ASSOCIATE, NULL);
398 return rc;
399}
400
Eric Parisc9180a52007-11-30 13:00:35 -0500401static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
403 struct superblock_security_struct *sbsec = sb->s_security;
404 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500405 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 int rc = 0;
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
409 /* Make sure that the xattr handler exists and that no
410 error other than -ENODATA is returned by getxattr on
411 the root directory. -ENODATA is ok, as this may be
412 the first boot of the SELinux kernel before we have
413 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500414 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
416 "xattr support\n", sb->s_id, sb->s_type->name);
417 rc = -EOPNOTSUPP;
418 goto out;
419 }
Eric Parisc9180a52007-11-30 13:00:35 -0500420 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 if (rc < 0 && rc != -ENODATA) {
422 if (rc == -EOPNOTSUPP)
423 printk(KERN_WARNING "SELinux: (dev %s, type "
424 "%s) has no security xattr handler\n",
425 sb->s_id, sb->s_type->name);
426 else
427 printk(KERN_WARNING "SELinux: (dev %s, type "
428 "%s) getxattr errno %d\n", sb->s_id,
429 sb->s_type->name, -rc);
430 goto out;
431 }
432 }
433
David P. Quigley11689d42009-01-16 09:22:03 -0500434 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Eric Parisc9180a52007-11-30 13:00:35 -0500436 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500437 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500439 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500440 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sb->s_id, sb->s_type->name,
442 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
David P. Quigley11689d42009-01-16 09:22:03 -0500444 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
445 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
446 sbsec->behavior == SECURITY_FS_USE_NONE ||
447 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
448 sbsec->flags &= ~SE_SBLABELSUPP;
449
David P. Quigleyddd29ec2009-09-09 14:25:37 -0400450 /* Special handling for sysfs. Is genfs but also has setxattr handler*/
451 if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
452 sbsec->flags |= SE_SBLABELSUPP;
453
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500455 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
457 /* Initialize any other inodes associated with the superblock, e.g.
458 inodes created prior to initial policy load or inodes created
459 during get_sb by a pseudo filesystem that directly
460 populates itself. */
461 spin_lock(&sbsec->isec_lock);
462next_inode:
463 if (!list_empty(&sbsec->isec_head)) {
464 struct inode_security_struct *isec =
465 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500466 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 struct inode *inode = isec->inode;
468 spin_unlock(&sbsec->isec_lock);
469 inode = igrab(inode);
470 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500471 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 inode_doinit(inode);
473 iput(inode);
474 }
475 spin_lock(&sbsec->isec_lock);
476 list_del_init(&isec->list);
477 goto next_inode;
478 }
479 spin_unlock(&sbsec->isec_lock);
480out:
Eric Parisc9180a52007-11-30 13:00:35 -0500481 return rc;
482}
483
484/*
485 * This function should allow an FS to ask what it's mount security
486 * options were so it can use those later for submounts, displaying
487 * mount options, or whatever.
488 */
489static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500490 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500491{
492 int rc = 0, i;
493 struct superblock_security_struct *sbsec = sb->s_security;
494 char *context = NULL;
495 u32 len;
496 char tmp;
497
Eric Parise0007522008-03-05 10:31:54 -0500498 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500499
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500500 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500501 return -EINVAL;
502
503 if (!ss_initialized)
504 return -EINVAL;
505
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500506 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500507 /* count the number of mount options for this sb */
508 for (i = 0; i < 8; i++) {
509 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500510 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500511 tmp >>= 1;
512 }
David P. Quigley11689d42009-01-16 09:22:03 -0500513 /* Check if the Label support flag is set */
514 if (sbsec->flags & SE_SBLABELSUPP)
515 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500516
Eric Parise0007522008-03-05 10:31:54 -0500517 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
518 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500519 rc = -ENOMEM;
520 goto out_free;
521 }
522
Eric Parise0007522008-03-05 10:31:54 -0500523 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
524 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500525 rc = -ENOMEM;
526 goto out_free;
527 }
528
529 i = 0;
530 if (sbsec->flags & FSCONTEXT_MNT) {
531 rc = security_sid_to_context(sbsec->sid, &context, &len);
532 if (rc)
533 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500534 opts->mnt_opts[i] = context;
535 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500536 }
537 if (sbsec->flags & CONTEXT_MNT) {
538 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
539 if (rc)
540 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500541 opts->mnt_opts[i] = context;
542 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500543 }
544 if (sbsec->flags & DEFCONTEXT_MNT) {
545 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
546 if (rc)
547 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500548 opts->mnt_opts[i] = context;
549 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500550 }
551 if (sbsec->flags & ROOTCONTEXT_MNT) {
552 struct inode *root = sbsec->sb->s_root->d_inode;
553 struct inode_security_struct *isec = root->i_security;
554
555 rc = security_sid_to_context(isec->sid, &context, &len);
556 if (rc)
557 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500558 opts->mnt_opts[i] = context;
559 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500560 }
David P. Quigley11689d42009-01-16 09:22:03 -0500561 if (sbsec->flags & SE_SBLABELSUPP) {
562 opts->mnt_opts[i] = NULL;
563 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
564 }
Eric Parisc9180a52007-11-30 13:00:35 -0500565
Eric Parise0007522008-03-05 10:31:54 -0500566 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500567
568 return 0;
569
570out_free:
Eric Parise0007522008-03-05 10:31:54 -0500571 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500572 return rc;
573}
574
575static int bad_option(struct superblock_security_struct *sbsec, char flag,
576 u32 old_sid, u32 new_sid)
577{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500578 char mnt_flags = sbsec->flags & SE_MNTMASK;
579
Eric Parisc9180a52007-11-30 13:00:35 -0500580 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500581 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500582 if (!(sbsec->flags & flag) ||
583 (old_sid != new_sid))
584 return 1;
585
586 /* check if we were passed the same options twice,
587 * aka someone passed context=a,context=b
588 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500589 if (!(sbsec->flags & SE_SBINITIALIZED))
590 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500591 return 1;
592 return 0;
593}
Eric Parise0007522008-03-05 10:31:54 -0500594
Eric Parisc9180a52007-11-30 13:00:35 -0500595/*
596 * Allow filesystems with binary mount data to explicitly set mount point
597 * labeling information.
598 */
Eric Parise0007522008-03-05 10:31:54 -0500599static int selinux_set_mnt_opts(struct super_block *sb,
600 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500601{
David Howells275bb412008-11-14 10:39:19 +1100602 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500603 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500604 struct superblock_security_struct *sbsec = sb->s_security;
605 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000606 struct inode *inode = sbsec->sb->s_root->d_inode;
607 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500608 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
609 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500610 char **mount_options = opts->mnt_opts;
611 int *flags = opts->mnt_opts_flags;
612 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500613
614 mutex_lock(&sbsec->lock);
615
616 if (!ss_initialized) {
617 if (!num_opts) {
618 /* Defer initialization until selinux_complete_init,
619 after the initial policy is loaded and the security
620 server is ready to handle calls. */
621 spin_lock(&sb_security_lock);
622 if (list_empty(&sbsec->list))
623 list_add(&sbsec->list, &superblock_security_head);
624 spin_unlock(&sb_security_lock);
625 goto out;
626 }
627 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400628 printk(KERN_WARNING "SELinux: Unable to set superblock options "
629 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500630 goto out;
631 }
632
633 /*
Eric Parise0007522008-03-05 10:31:54 -0500634 * Binary mount data FS will come through this function twice. Once
635 * from an explicit call and once from the generic calls from the vfs.
636 * Since the generic VFS calls will not contain any security mount data
637 * we need to skip the double mount verification.
638 *
639 * This does open a hole in which we will not notice if the first
640 * mount using this sb set explict options and a second mount using
641 * this sb does not set any security options. (The first options
642 * will be used for both mounts)
643 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500644 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500645 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400646 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500647
648 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500649 * parse the mount options, check if they are valid sids.
650 * also check if someone is trying to mount the same sb more
651 * than once with different security options.
652 */
653 for (i = 0; i < num_opts; i++) {
654 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500655
656 if (flags[i] == SE_SBLABELSUPP)
657 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500658 rc = security_context_to_sid(mount_options[i],
659 strlen(mount_options[i]), &sid);
660 if (rc) {
661 printk(KERN_WARNING "SELinux: security_context_to_sid"
662 "(%s) failed for (dev %s, type %s) errno=%d\n",
663 mount_options[i], sb->s_id, name, rc);
664 goto out;
665 }
666 switch (flags[i]) {
667 case FSCONTEXT_MNT:
668 fscontext_sid = sid;
669
670 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
671 fscontext_sid))
672 goto out_double_mount;
673
674 sbsec->flags |= FSCONTEXT_MNT;
675 break;
676 case CONTEXT_MNT:
677 context_sid = sid;
678
679 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
680 context_sid))
681 goto out_double_mount;
682
683 sbsec->flags |= CONTEXT_MNT;
684 break;
685 case ROOTCONTEXT_MNT:
686 rootcontext_sid = sid;
687
688 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
689 rootcontext_sid))
690 goto out_double_mount;
691
692 sbsec->flags |= ROOTCONTEXT_MNT;
693
694 break;
695 case DEFCONTEXT_MNT:
696 defcontext_sid = sid;
697
698 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
699 defcontext_sid))
700 goto out_double_mount;
701
702 sbsec->flags |= DEFCONTEXT_MNT;
703
704 break;
705 default:
706 rc = -EINVAL;
707 goto out;
708 }
709 }
710
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500711 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500712 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500713 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500714 goto out_double_mount;
715 rc = 0;
716 goto out;
717 }
718
James Morris089be432008-07-15 18:32:49 +1000719 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500720 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500721
722 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500723 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500724 if (rc) {
725 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000726 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500727 goto out;
728 }
729
730 /* sets the context of the superblock for the fs being mounted. */
731 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100732 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500733 if (rc)
734 goto out;
735
736 sbsec->sid = fscontext_sid;
737 }
738
739 /*
740 * Switch to using mount point labeling behavior.
741 * sets the label used on all file below the mountpoint, and will set
742 * the superblock context if not already set.
743 */
744 if (context_sid) {
745 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100746 rc = may_context_mount_sb_relabel(context_sid, sbsec,
747 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500748 if (rc)
749 goto out;
750 sbsec->sid = context_sid;
751 } else {
David Howells275bb412008-11-14 10:39:19 +1100752 rc = may_context_mount_inode_relabel(context_sid, sbsec,
753 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500754 if (rc)
755 goto out;
756 }
757 if (!rootcontext_sid)
758 rootcontext_sid = context_sid;
759
760 sbsec->mntpoint_sid = context_sid;
761 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
762 }
763
764 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100765 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
766 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500767 if (rc)
768 goto out;
769
770 root_isec->sid = rootcontext_sid;
771 root_isec->initialized = 1;
772 }
773
774 if (defcontext_sid) {
775 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
776 rc = -EINVAL;
777 printk(KERN_WARNING "SELinux: defcontext option is "
778 "invalid for this filesystem type\n");
779 goto out;
780 }
781
782 if (defcontext_sid != sbsec->def_sid) {
783 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100784 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500785 if (rc)
786 goto out;
787 }
788
789 sbsec->def_sid = defcontext_sid;
790 }
791
792 rc = sb_finish_set_opts(sb);
793out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700794 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500796out_double_mount:
797 rc = -EINVAL;
798 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
799 "security settings for (dev %s, type %s)\n", sb->s_id, name);
800 goto out;
801}
802
803static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
804 struct super_block *newsb)
805{
806 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
807 struct superblock_security_struct *newsbsec = newsb->s_security;
808
809 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
810 int set_context = (oldsbsec->flags & CONTEXT_MNT);
811 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
812
Eric Paris0f5e6422008-04-21 16:24:11 -0400813 /*
814 * if the parent was able to be mounted it clearly had no special lsm
815 * mount options. thus we can safely put this sb on the list and deal
816 * with it later
817 */
818 if (!ss_initialized) {
819 spin_lock(&sb_security_lock);
820 if (list_empty(&newsbsec->list))
821 list_add(&newsbsec->list, &superblock_security_head);
822 spin_unlock(&sb_security_lock);
823 return;
824 }
Eric Parisc9180a52007-11-30 13:00:35 -0500825
Eric Parisc9180a52007-11-30 13:00:35 -0500826 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500827 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500828
Eric Paris5a552612008-04-09 14:08:35 -0400829 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500830 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400831 return;
832
Eric Parisc9180a52007-11-30 13:00:35 -0500833 mutex_lock(&newsbsec->lock);
834
835 newsbsec->flags = oldsbsec->flags;
836
837 newsbsec->sid = oldsbsec->sid;
838 newsbsec->def_sid = oldsbsec->def_sid;
839 newsbsec->behavior = oldsbsec->behavior;
840
841 if (set_context) {
842 u32 sid = oldsbsec->mntpoint_sid;
843
844 if (!set_fscontext)
845 newsbsec->sid = sid;
846 if (!set_rootcontext) {
847 struct inode *newinode = newsb->s_root->d_inode;
848 struct inode_security_struct *newisec = newinode->i_security;
849 newisec->sid = sid;
850 }
851 newsbsec->mntpoint_sid = sid;
852 }
853 if (set_rootcontext) {
854 const struct inode *oldinode = oldsb->s_root->d_inode;
855 const struct inode_security_struct *oldisec = oldinode->i_security;
856 struct inode *newinode = newsb->s_root->d_inode;
857 struct inode_security_struct *newisec = newinode->i_security;
858
859 newisec->sid = oldisec->sid;
860 }
861
862 sb_finish_set_opts(newsb);
863 mutex_unlock(&newsbsec->lock);
864}
865
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200866static int selinux_parse_opts_str(char *options,
867 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500868{
Eric Parise0007522008-03-05 10:31:54 -0500869 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500870 char *context = NULL, *defcontext = NULL;
871 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500872 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500873
Eric Parise0007522008-03-05 10:31:54 -0500874 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500875
876 /* Standard string-based options. */
877 while ((p = strsep(&options, "|")) != NULL) {
878 int token;
879 substring_t args[MAX_OPT_ARGS];
880
881 if (!*p)
882 continue;
883
884 token = match_token(p, tokens, args);
885
886 switch (token) {
887 case Opt_context:
888 if (context || defcontext) {
889 rc = -EINVAL;
890 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
891 goto out_err;
892 }
893 context = match_strdup(&args[0]);
894 if (!context) {
895 rc = -ENOMEM;
896 goto out_err;
897 }
898 break;
899
900 case Opt_fscontext:
901 if (fscontext) {
902 rc = -EINVAL;
903 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
904 goto out_err;
905 }
906 fscontext = match_strdup(&args[0]);
907 if (!fscontext) {
908 rc = -ENOMEM;
909 goto out_err;
910 }
911 break;
912
913 case Opt_rootcontext:
914 if (rootcontext) {
915 rc = -EINVAL;
916 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
917 goto out_err;
918 }
919 rootcontext = match_strdup(&args[0]);
920 if (!rootcontext) {
921 rc = -ENOMEM;
922 goto out_err;
923 }
924 break;
925
926 case Opt_defcontext:
927 if (context || defcontext) {
928 rc = -EINVAL;
929 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
930 goto out_err;
931 }
932 defcontext = match_strdup(&args[0]);
933 if (!defcontext) {
934 rc = -ENOMEM;
935 goto out_err;
936 }
937 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500938 case Opt_labelsupport:
939 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500940 default:
941 rc = -EINVAL;
942 printk(KERN_WARNING "SELinux: unknown mount option\n");
943 goto out_err;
944
945 }
946 }
947
Eric Parise0007522008-03-05 10:31:54 -0500948 rc = -ENOMEM;
949 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
950 if (!opts->mnt_opts)
951 goto out_err;
952
953 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
954 if (!opts->mnt_opts_flags) {
955 kfree(opts->mnt_opts);
956 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500957 }
958
Eric Parise0007522008-03-05 10:31:54 -0500959 if (fscontext) {
960 opts->mnt_opts[num_mnt_opts] = fscontext;
961 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
962 }
963 if (context) {
964 opts->mnt_opts[num_mnt_opts] = context;
965 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
966 }
967 if (rootcontext) {
968 opts->mnt_opts[num_mnt_opts] = rootcontext;
969 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
970 }
971 if (defcontext) {
972 opts->mnt_opts[num_mnt_opts] = defcontext;
973 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
974 }
975
976 opts->num_mnt_opts = num_mnt_opts;
977 return 0;
978
Eric Parisc9180a52007-11-30 13:00:35 -0500979out_err:
980 kfree(context);
981 kfree(defcontext);
982 kfree(fscontext);
983 kfree(rootcontext);
984 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985}
Eric Parise0007522008-03-05 10:31:54 -0500986/*
987 * string mount options parsing and call set the sbsec
988 */
989static int superblock_doinit(struct super_block *sb, void *data)
990{
991 int rc = 0;
992 char *options = data;
993 struct security_mnt_opts opts;
994
995 security_init_mnt_opts(&opts);
996
997 if (!data)
998 goto out;
999
1000 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
1001
1002 rc = selinux_parse_opts_str(options, &opts);
1003 if (rc)
1004 goto out_err;
1005
1006out:
1007 rc = selinux_set_mnt_opts(sb, &opts);
1008
1009out_err:
1010 security_free_mnt_opts(&opts);
1011 return rc;
1012}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Adrian Bunk3583a712008-07-22 20:21:23 +03001014static void selinux_write_opts(struct seq_file *m,
1015 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +10001016{
1017 int i;
1018 char *prefix;
1019
1020 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -05001021 char *has_comma;
1022
1023 if (opts->mnt_opts[i])
1024 has_comma = strchr(opts->mnt_opts[i], ',');
1025 else
1026 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +10001027
1028 switch (opts->mnt_opts_flags[i]) {
1029 case CONTEXT_MNT:
1030 prefix = CONTEXT_STR;
1031 break;
1032 case FSCONTEXT_MNT:
1033 prefix = FSCONTEXT_STR;
1034 break;
1035 case ROOTCONTEXT_MNT:
1036 prefix = ROOTCONTEXT_STR;
1037 break;
1038 case DEFCONTEXT_MNT:
1039 prefix = DEFCONTEXT_STR;
1040 break;
David P. Quigley11689d42009-01-16 09:22:03 -05001041 case SE_SBLABELSUPP:
1042 seq_putc(m, ',');
1043 seq_puts(m, LABELSUPP_STR);
1044 continue;
Eric Paris2069f452008-07-04 09:47:13 +10001045 default:
1046 BUG();
1047 };
1048 /* we need a comma before each option */
1049 seq_putc(m, ',');
1050 seq_puts(m, prefix);
1051 if (has_comma)
1052 seq_putc(m, '\"');
1053 seq_puts(m, opts->mnt_opts[i]);
1054 if (has_comma)
1055 seq_putc(m, '\"');
1056 }
1057}
1058
1059static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1060{
1061 struct security_mnt_opts opts;
1062 int rc;
1063
1064 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001065 if (rc) {
1066 /* before policy load we may get EINVAL, don't show anything */
1067 if (rc == -EINVAL)
1068 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001069 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001070 }
Eric Paris2069f452008-07-04 09:47:13 +10001071
1072 selinux_write_opts(m, &opts);
1073
1074 security_free_mnt_opts(&opts);
1075
1076 return rc;
1077}
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079static inline u16 inode_mode_to_security_class(umode_t mode)
1080{
1081 switch (mode & S_IFMT) {
1082 case S_IFSOCK:
1083 return SECCLASS_SOCK_FILE;
1084 case S_IFLNK:
1085 return SECCLASS_LNK_FILE;
1086 case S_IFREG:
1087 return SECCLASS_FILE;
1088 case S_IFBLK:
1089 return SECCLASS_BLK_FILE;
1090 case S_IFDIR:
1091 return SECCLASS_DIR;
1092 case S_IFCHR:
1093 return SECCLASS_CHR_FILE;
1094 case S_IFIFO:
1095 return SECCLASS_FIFO_FILE;
1096
1097 }
1098
1099 return SECCLASS_FILE;
1100}
1101
James Morris13402582005-09-30 14:24:34 -04001102static inline int default_protocol_stream(int protocol)
1103{
1104 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1105}
1106
1107static inline int default_protocol_dgram(int protocol)
1108{
1109 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1110}
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1113{
1114 switch (family) {
1115 case PF_UNIX:
1116 switch (type) {
1117 case SOCK_STREAM:
1118 case SOCK_SEQPACKET:
1119 return SECCLASS_UNIX_STREAM_SOCKET;
1120 case SOCK_DGRAM:
1121 return SECCLASS_UNIX_DGRAM_SOCKET;
1122 }
1123 break;
1124 case PF_INET:
1125 case PF_INET6:
1126 switch (type) {
1127 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001128 if (default_protocol_stream(protocol))
1129 return SECCLASS_TCP_SOCKET;
1130 else
1131 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001133 if (default_protocol_dgram(protocol))
1134 return SECCLASS_UDP_SOCKET;
1135 else
1136 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001137 case SOCK_DCCP:
1138 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001139 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 return SECCLASS_RAWIP_SOCKET;
1141 }
1142 break;
1143 case PF_NETLINK:
1144 switch (protocol) {
1145 case NETLINK_ROUTE:
1146 return SECCLASS_NETLINK_ROUTE_SOCKET;
1147 case NETLINK_FIREWALL:
1148 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001149 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1151 case NETLINK_NFLOG:
1152 return SECCLASS_NETLINK_NFLOG_SOCKET;
1153 case NETLINK_XFRM:
1154 return SECCLASS_NETLINK_XFRM_SOCKET;
1155 case NETLINK_SELINUX:
1156 return SECCLASS_NETLINK_SELINUX_SOCKET;
1157 case NETLINK_AUDIT:
1158 return SECCLASS_NETLINK_AUDIT_SOCKET;
1159 case NETLINK_IP6_FW:
1160 return SECCLASS_NETLINK_IP6FW_SOCKET;
1161 case NETLINK_DNRTMSG:
1162 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001163 case NETLINK_KOBJECT_UEVENT:
1164 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 default:
1166 return SECCLASS_NETLINK_SOCKET;
1167 }
1168 case PF_PACKET:
1169 return SECCLASS_PACKET_SOCKET;
1170 case PF_KEY:
1171 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001172 case PF_APPLETALK:
1173 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 return SECCLASS_SOCKET;
1177}
1178
1179#ifdef CONFIG_PROC_FS
1180static int selinux_proc_get_sid(struct proc_dir_entry *de,
1181 u16 tclass,
1182 u32 *sid)
1183{
1184 int buflen, rc;
1185 char *buffer, *path, *end;
1186
Eric Paris828dfe12008-04-17 13:17:49 -04001187 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 if (!buffer)
1189 return -ENOMEM;
1190
1191 buflen = PAGE_SIZE;
1192 end = buffer+buflen;
1193 *--end = '\0';
1194 buflen--;
1195 path = end-1;
1196 *path = '/';
1197 while (de && de != de->parent) {
1198 buflen -= de->namelen + 1;
1199 if (buflen < 0)
1200 break;
1201 end -= de->namelen;
1202 memcpy(end, de->name, de->namelen);
1203 *--end = '/';
1204 path = end;
1205 de = de->parent;
1206 }
1207 rc = security_genfs_sid("proc", path, tclass, sid);
1208 free_page((unsigned long)buffer);
1209 return rc;
1210}
1211#else
1212static int selinux_proc_get_sid(struct proc_dir_entry *de,
1213 u16 tclass,
1214 u32 *sid)
1215{
1216 return -EINVAL;
1217}
1218#endif
1219
1220/* The inode's security attributes must be initialized before first use. */
1221static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1222{
1223 struct superblock_security_struct *sbsec = NULL;
1224 struct inode_security_struct *isec = inode->i_security;
1225 u32 sid;
1226 struct dentry *dentry;
1227#define INITCONTEXTLEN 255
1228 char *context = NULL;
1229 unsigned len = 0;
1230 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 if (isec->initialized)
1233 goto out;
1234
Eric Paris23970742006-09-25 23:32:01 -07001235 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001237 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001240 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 /* Defer initialization until selinux_complete_init,
1242 after the initial policy is loaded and the security
1243 server is ready to handle calls. */
1244 spin_lock(&sbsec->isec_lock);
1245 if (list_empty(&isec->list))
1246 list_add(&isec->list, &sbsec->isec_head);
1247 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001248 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 }
1250
1251 switch (sbsec->behavior) {
1252 case SECURITY_FS_USE_XATTR:
1253 if (!inode->i_op->getxattr) {
1254 isec->sid = sbsec->def_sid;
1255 break;
1256 }
1257
1258 /* Need a dentry, since the xattr API requires one.
1259 Life would be simpler if we could just pass the inode. */
1260 if (opt_dentry) {
1261 /* Called from d_instantiate or d_splice_alias. */
1262 dentry = dget(opt_dentry);
1263 } else {
1264 /* Called from selinux_complete_init, try to find a dentry. */
1265 dentry = d_find_alias(inode);
1266 }
1267 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001268 /*
1269 * this is can be hit on boot when a file is accessed
1270 * before the policy is loaded. When we load policy we
1271 * may find inodes that have no dentry on the
1272 * sbsec->isec_head list. No reason to complain as these
1273 * will get fixed up the next time we go through
1274 * inode_doinit with a dentry, before these inodes could
1275 * be used again by userspace.
1276 */
Eric Paris23970742006-09-25 23:32:01 -07001277 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 }
1279
1280 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001281 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (!context) {
1283 rc = -ENOMEM;
1284 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001285 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001287 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1289 context, len);
1290 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001291 kfree(context);
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 /* Need a larger buffer. Query for the right size. */
1294 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1295 NULL, 0);
1296 if (rc < 0) {
1297 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001298 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001301 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (!context) {
1303 rc = -ENOMEM;
1304 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001305 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001307 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 rc = inode->i_op->getxattr(dentry,
1309 XATTR_NAME_SELINUX,
1310 context, len);
1311 }
1312 dput(dentry);
1313 if (rc < 0) {
1314 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001315 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001316 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 -rc, inode->i_sb->s_id, inode->i_ino);
1318 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001319 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 }
1321 /* Map ENODATA to the default file SID */
1322 sid = sbsec->def_sid;
1323 rc = 0;
1324 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001325 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001326 sbsec->def_sid,
1327 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001329 char *dev = inode->i_sb->s_id;
1330 unsigned long ino = inode->i_ino;
1331
1332 if (rc == -EINVAL) {
1333 if (printk_ratelimit())
1334 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1335 "context=%s. This indicates you may need to relabel the inode or the "
1336 "filesystem in question.\n", ino, dev, context);
1337 } else {
1338 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1339 "returned %d for dev=%s ino=%ld\n",
1340 __func__, context, -rc, dev, ino);
1341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 kfree(context);
1343 /* Leave with the unlabeled SID */
1344 rc = 0;
1345 break;
1346 }
1347 }
1348 kfree(context);
1349 isec->sid = sid;
1350 break;
1351 case SECURITY_FS_USE_TASK:
1352 isec->sid = isec->task_sid;
1353 break;
1354 case SECURITY_FS_USE_TRANS:
1355 /* Default to the fs SID. */
1356 isec->sid = sbsec->sid;
1357
1358 /* Try to obtain a transition SID. */
1359 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1360 rc = security_transition_sid(isec->task_sid,
1361 sbsec->sid,
1362 isec->sclass,
1363 &sid);
1364 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001365 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 isec->sid = sid;
1367 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001368 case SECURITY_FS_USE_MNTPOINT:
1369 isec->sid = sbsec->mntpoint_sid;
1370 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001372 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 isec->sid = sbsec->sid;
1374
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001375 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 struct proc_inode *proci = PROC_I(inode);
1377 if (proci->pde) {
1378 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1379 rc = selinux_proc_get_sid(proci->pde,
1380 isec->sclass,
1381 &sid);
1382 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001383 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 isec->sid = sid;
1385 }
1386 }
1387 break;
1388 }
1389
1390 isec->initialized = 1;
1391
Eric Paris23970742006-09-25 23:32:01 -07001392out_unlock:
1393 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394out:
1395 if (isec->sclass == SECCLASS_FILE)
1396 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 return rc;
1398}
1399
1400/* Convert a Linux signal to an access vector. */
1401static inline u32 signal_to_av(int sig)
1402{
1403 u32 perm = 0;
1404
1405 switch (sig) {
1406 case SIGCHLD:
1407 /* Commonly granted from child to parent. */
1408 perm = PROCESS__SIGCHLD;
1409 break;
1410 case SIGKILL:
1411 /* Cannot be caught or ignored */
1412 perm = PROCESS__SIGKILL;
1413 break;
1414 case SIGSTOP:
1415 /* Cannot be caught or ignored */
1416 perm = PROCESS__SIGSTOP;
1417 break;
1418 default:
1419 /* All other signals. */
1420 perm = PROCESS__SIGNAL;
1421 break;
1422 }
1423
1424 return perm;
1425}
1426
David Howells275bb412008-11-14 10:39:19 +11001427/*
David Howellsd84f4f92008-11-14 10:39:23 +11001428 * Check permission between a pair of credentials
1429 * fork check, ptrace check, etc.
1430 */
1431static int cred_has_perm(const struct cred *actor,
1432 const struct cred *target,
1433 u32 perms)
1434{
1435 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1436
1437 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1438}
1439
1440/*
David Howells88e67f32008-11-14 10:39:21 +11001441 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001442 * fork check, ptrace check, etc.
1443 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001444 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001445 */
1446static int task_has_perm(const struct task_struct *tsk1,
1447 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 u32 perms)
1449{
David Howells275bb412008-11-14 10:39:19 +11001450 const struct task_security_struct *__tsec1, *__tsec2;
1451 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
David Howells275bb412008-11-14 10:39:19 +11001453 rcu_read_lock();
1454 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1455 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1456 rcu_read_unlock();
1457 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458}
1459
David Howells3b11a1d2008-11-14 10:39:26 +11001460/*
1461 * Check permission between current and another task, e.g. signal checks,
1462 * fork check, ptrace check, etc.
1463 * current is the actor and tsk2 is the target
1464 * - this uses current's subjective creds
1465 */
1466static int current_has_perm(const struct task_struct *tsk,
1467 u32 perms)
1468{
1469 u32 sid, tsid;
1470
1471 sid = current_sid();
1472 tsid = task_sid(tsk);
1473 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1474}
1475
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001476#if CAP_LAST_CAP > 63
1477#error Fix SELinux to handle capabilities > 63.
1478#endif
1479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480/* Check whether a task is allowed to use a capability. */
1481static int task_has_capability(struct task_struct *tsk,
David Howells3699c532009-01-06 22:27:01 +00001482 const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001483 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
Thomas Liu2bf49692009-07-14 12:14:09 -04001485 struct common_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001486 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001487 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001488 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001489 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001490 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
Thomas Liu2bf49692009-07-14 12:14:09 -04001492 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 ad.tsk = tsk;
1494 ad.u.cap = cap;
1495
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001496 switch (CAP_TO_INDEX(cap)) {
1497 case 0:
1498 sclass = SECCLASS_CAPABILITY;
1499 break;
1500 case 1:
1501 sclass = SECCLASS_CAPABILITY2;
1502 break;
1503 default:
1504 printk(KERN_ERR
1505 "SELinux: out of range capability %d\n", cap);
1506 BUG();
1507 }
Eric Paris06112162008-11-11 22:02:50 +11001508
David Howells275bb412008-11-14 10:39:19 +11001509 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001510 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001511 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001512 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513}
1514
1515/* Check whether a task is allowed to use a system operation. */
1516static int task_has_system(struct task_struct *tsk,
1517 u32 perms)
1518{
David Howells275bb412008-11-14 10:39:19 +11001519 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
David Howells275bb412008-11-14 10:39:19 +11001521 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 SECCLASS_SYSTEM, perms, NULL);
1523}
1524
1525/* Check whether a task has a particular permission to an inode.
1526 The 'adp' parameter is optional and allows other audit
1527 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001528static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 struct inode *inode,
1530 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001531 struct common_audit_data *adp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001534 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001535 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
David Howellse0e81732009-09-02 09:13:40 +01001537 validate_creds(cred);
1538
Eric Paris828dfe12008-04-17 13:17:49 -04001539 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001540 return 0;
1541
David Howells88e67f32008-11-14 10:39:21 +11001542 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 isec = inode->i_security;
1544
1545 if (!adp) {
1546 adp = &ad;
Thomas Liu2bf49692009-07-14 12:14:09 -04001547 COMMON_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 ad.u.fs.inode = inode;
1549 }
1550
David Howells275bb412008-11-14 10:39:19 +11001551 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552}
1553
1554/* Same as inode_has_perm, but pass explicit audit data containing
1555 the dentry to help the auditing code to more easily generate the
1556 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001557static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 struct vfsmount *mnt,
1559 struct dentry *dentry,
1560 u32 av)
1561{
1562 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001563 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001564
Thomas Liu2bf49692009-07-14 12:14:09 -04001565 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001566 ad.u.fs.path.mnt = mnt;
1567 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001568 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569}
1570
1571/* Check whether a task can use an open file descriptor to
1572 access an inode in a given way. Check access to the
1573 descriptor itself, and then use dentry_has_perm to
1574 check a particular permission to the file.
1575 Access to the descriptor is implicitly granted if it
1576 has the same SID as the process. If av is zero, then
1577 access to the file is not checked, e.g. for cases
1578 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001579static int file_has_perm(const struct cred *cred,
1580 struct file *file,
1581 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001584 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001585 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001586 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 int rc;
1588
Thomas Liu2bf49692009-07-14 12:14:09 -04001589 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001590 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
David Howells275bb412008-11-14 10:39:19 +11001592 if (sid != fsec->sid) {
1593 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 SECCLASS_FD,
1595 FD__USE,
1596 &ad);
1597 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001598 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 }
1600
1601 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001602 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001604 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
David Howells88e67f32008-11-14 10:39:21 +11001606out:
1607 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608}
1609
1610/* Check whether a task can create a file. */
1611static int may_create(struct inode *dir,
1612 struct dentry *dentry,
1613 u16 tclass)
1614{
David Howells275bb412008-11-14 10:39:19 +11001615 const struct cred *cred = current_cred();
1616 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 struct inode_security_struct *dsec;
1618 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001619 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001620 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 int rc;
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 dsec = dir->i_security;
1624 sbsec = dir->i_sb->s_security;
1625
David Howells275bb412008-11-14 10:39:19 +11001626 sid = tsec->sid;
1627 newsid = tsec->create_sid;
1628
Thomas Liu2bf49692009-07-14 12:14:09 -04001629 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001630 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
David Howells275bb412008-11-14 10:39:19 +11001632 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 DIR__ADD_NAME | DIR__SEARCH,
1634 &ad);
1635 if (rc)
1636 return rc;
1637
David P. Quigleycd895962009-01-16 09:22:04 -05001638 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11001639 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (rc)
1641 return rc;
1642 }
1643
David Howells275bb412008-11-14 10:39:19 +11001644 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 if (rc)
1646 return rc;
1647
1648 return avc_has_perm(newsid, sbsec->sid,
1649 SECCLASS_FILESYSTEM,
1650 FILESYSTEM__ASSOCIATE, &ad);
1651}
1652
Michael LeMay4eb582c2006-06-26 00:24:57 -07001653/* Check whether a task can create a key. */
1654static int may_create_key(u32 ksid,
1655 struct task_struct *ctx)
1656{
David Howells275bb412008-11-14 10:39:19 +11001657 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001658
David Howells275bb412008-11-14 10:39:19 +11001659 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001660}
1661
Eric Paris828dfe12008-04-17 13:17:49 -04001662#define MAY_LINK 0
1663#define MAY_UNLINK 1
1664#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666/* Check whether a task can link, unlink, or rmdir a file/directory. */
1667static int may_link(struct inode *dir,
1668 struct dentry *dentry,
1669 int kind)
1670
1671{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001673 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001674 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 u32 av;
1676 int rc;
1677
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 dsec = dir->i_security;
1679 isec = dentry->d_inode->i_security;
1680
Thomas Liu2bf49692009-07-14 12:14:09 -04001681 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001682 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
1684 av = DIR__SEARCH;
1685 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001686 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 if (rc)
1688 return rc;
1689
1690 switch (kind) {
1691 case MAY_LINK:
1692 av = FILE__LINK;
1693 break;
1694 case MAY_UNLINK:
1695 av = FILE__UNLINK;
1696 break;
1697 case MAY_RMDIR:
1698 av = DIR__RMDIR;
1699 break;
1700 default:
Eric Paris744ba352008-04-17 11:52:44 -04001701 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1702 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 return 0;
1704 }
1705
David Howells275bb412008-11-14 10:39:19 +11001706 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 return rc;
1708}
1709
1710static inline int may_rename(struct inode *old_dir,
1711 struct dentry *old_dentry,
1712 struct inode *new_dir,
1713 struct dentry *new_dentry)
1714{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001716 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001717 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 u32 av;
1719 int old_is_dir, new_is_dir;
1720 int rc;
1721
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 old_dsec = old_dir->i_security;
1723 old_isec = old_dentry->d_inode->i_security;
1724 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1725 new_dsec = new_dir->i_security;
1726
Thomas Liu2bf49692009-07-14 12:14:09 -04001727 COMMON_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
Jan Blunck44707fd2008-02-14 19:38:33 -08001729 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001730 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1732 if (rc)
1733 return rc;
David Howells275bb412008-11-14 10:39:19 +11001734 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 old_isec->sclass, FILE__RENAME, &ad);
1736 if (rc)
1737 return rc;
1738 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001739 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 old_isec->sclass, DIR__REPARENT, &ad);
1741 if (rc)
1742 return rc;
1743 }
1744
Jan Blunck44707fd2008-02-14 19:38:33 -08001745 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 av = DIR__ADD_NAME | DIR__SEARCH;
1747 if (new_dentry->d_inode)
1748 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001749 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 if (rc)
1751 return rc;
1752 if (new_dentry->d_inode) {
1753 new_isec = new_dentry->d_inode->i_security;
1754 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001755 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 new_isec->sclass,
1757 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1758 if (rc)
1759 return rc;
1760 }
1761
1762 return 0;
1763}
1764
1765/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001766static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 struct super_block *sb,
1768 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001769 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001772 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001775 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776}
1777
1778/* Convert a Linux mode and permission mask to an access vector. */
1779static inline u32 file_mask_to_av(int mode, int mask)
1780{
1781 u32 av = 0;
1782
1783 if ((mode & S_IFMT) != S_IFDIR) {
1784 if (mask & MAY_EXEC)
1785 av |= FILE__EXECUTE;
1786 if (mask & MAY_READ)
1787 av |= FILE__READ;
1788
1789 if (mask & MAY_APPEND)
1790 av |= FILE__APPEND;
1791 else if (mask & MAY_WRITE)
1792 av |= FILE__WRITE;
1793
1794 } else {
1795 if (mask & MAY_EXEC)
1796 av |= DIR__SEARCH;
1797 if (mask & MAY_WRITE)
1798 av |= DIR__WRITE;
1799 if (mask & MAY_READ)
1800 av |= DIR__READ;
1801 }
1802
1803 return av;
1804}
1805
1806/* Convert a Linux file to an access vector. */
1807static inline u32 file_to_av(struct file *file)
1808{
1809 u32 av = 0;
1810
1811 if (file->f_mode & FMODE_READ)
1812 av |= FILE__READ;
1813 if (file->f_mode & FMODE_WRITE) {
1814 if (file->f_flags & O_APPEND)
1815 av |= FILE__APPEND;
1816 else
1817 av |= FILE__WRITE;
1818 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001819 if (!av) {
1820 /*
1821 * Special file opened with flags 3 for ioctl-only use.
1822 */
1823 av = FILE__IOCTL;
1824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
1826 return av;
1827}
1828
Eric Paris8b6a5a32008-10-29 17:06:46 -04001829/*
1830 * Convert a file to an access vector and include the correct open
1831 * open permission.
1832 */
1833static inline u32 open_file_to_av(struct file *file)
1834{
1835 u32 av = file_to_av(file);
1836
1837 if (selinux_policycap_openperm) {
1838 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1839 /*
1840 * lnk files and socks do not really have an 'open'
1841 */
1842 if (S_ISREG(mode))
1843 av |= FILE__OPEN;
1844 else if (S_ISCHR(mode))
1845 av |= CHR_FILE__OPEN;
1846 else if (S_ISBLK(mode))
1847 av |= BLK_FILE__OPEN;
1848 else if (S_ISFIFO(mode))
1849 av |= FIFO_FILE__OPEN;
1850 else if (S_ISDIR(mode))
1851 av |= DIR__OPEN;
Eric Paris6a25b272009-03-05 13:40:35 -05001852 else if (S_ISSOCK(mode))
1853 av |= SOCK_FILE__OPEN;
Eric Paris8b6a5a32008-10-29 17:06:46 -04001854 else
1855 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1856 "unknown mode:%o\n", __func__, mode);
1857 }
1858 return av;
1859}
1860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861/* Hook functions begin here. */
1862
Ingo Molnar9e488582009-05-07 19:26:19 +10001863static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001864 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 int rc;
1867
Ingo Molnar9e488582009-05-07 19:26:19 +10001868 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (rc)
1870 return rc;
1871
Stephen Smalley006ebb42008-05-19 08:32:49 -04001872 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001873 u32 sid = current_sid();
1874 u32 csid = task_sid(child);
1875 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001876 }
1877
David Howells3b11a1d2008-11-14 10:39:26 +11001878 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001879}
1880
1881static int selinux_ptrace_traceme(struct task_struct *parent)
1882{
1883 int rc;
1884
Eric Paris200ac532009-02-12 15:01:04 -05001885 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001886 if (rc)
1887 return rc;
1888
1889 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890}
1891
1892static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001893 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894{
1895 int error;
1896
David Howells3b11a1d2008-11-14 10:39:26 +11001897 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 if (error)
1899 return error;
1900
Eric Paris200ac532009-02-12 15:01:04 -05001901 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902}
1903
David Howellsd84f4f92008-11-14 10:39:23 +11001904static int selinux_capset(struct cred *new, const struct cred *old,
1905 const kernel_cap_t *effective,
1906 const kernel_cap_t *inheritable,
1907 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
1909 int error;
1910
Eric Paris200ac532009-02-12 15:01:04 -05001911 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001912 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 if (error)
1914 return error;
1915
David Howellsd84f4f92008-11-14 10:39:23 +11001916 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917}
1918
James Morris5626d3e2009-01-30 10:05:06 +11001919/*
1920 * (This comment used to live with the selinux_task_setuid hook,
1921 * which was removed).
1922 *
1923 * Since setuid only affects the current process, and since the SELinux
1924 * controls are not based on the Linux identity attributes, SELinux does not
1925 * need to control this operation. However, SELinux does control the use of
1926 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1927 */
1928
David Howells3699c532009-01-06 22:27:01 +00001929static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
1930 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931{
1932 int rc;
1933
Eric Paris200ac532009-02-12 15:01:04 -05001934 rc = cap_capable(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (rc)
1936 return rc;
1937
David Howells3699c532009-01-06 22:27:01 +00001938 return task_has_capability(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939}
1940
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001941static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1942{
1943 int buflen, rc;
1944 char *buffer, *path, *end;
1945
1946 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001947 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001948 if (!buffer)
1949 goto out;
1950
1951 buflen = PAGE_SIZE;
1952 end = buffer+buflen;
1953 *--end = '\0';
1954 buflen--;
1955 path = end-1;
1956 *path = '/';
1957 while (table) {
1958 const char *name = table->procname;
1959 size_t namelen = strlen(name);
1960 buflen -= namelen + 1;
1961 if (buflen < 0)
1962 goto out_free;
1963 end -= namelen;
1964 memcpy(end, name, namelen);
1965 *--end = '/';
1966 path = end;
1967 table = table->parent;
1968 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001969 buflen -= 4;
1970 if (buflen < 0)
1971 goto out_free;
1972 end -= 4;
1973 memcpy(end, "/sys", 4);
1974 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001975 rc = security_genfs_sid("proc", path, tclass, sid);
1976out_free:
1977 free_page((unsigned long)buffer);
1978out:
1979 return rc;
1980}
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982static int selinux_sysctl(ctl_table *table, int op)
1983{
1984 int error = 0;
1985 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001986 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 int rc;
1988
David Howells275bb412008-11-14 10:39:19 +11001989 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001991 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1992 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 if (rc) {
1994 /* Default to the well-defined sysctl SID. */
1995 tsid = SECINITSID_SYSCTL;
1996 }
1997
1998 /* The op values are "defined" in sysctl.c, thereby creating
1999 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04002000 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11002001 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 SECCLASS_DIR, DIR__SEARCH, NULL);
2003 } else {
2004 av = 0;
2005 if (op & 004)
2006 av |= FILE__READ;
2007 if (op & 002)
2008 av |= FILE__WRITE;
2009 if (av)
David Howells275bb412008-11-14 10:39:19 +11002010 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
2014 return error;
2015}
2016
2017static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
2018{
David Howells88e67f32008-11-14 10:39:21 +11002019 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 int rc = 0;
2021
2022 if (!sb)
2023 return 0;
2024
2025 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04002026 case Q_SYNC:
2027 case Q_QUOTAON:
2028 case Q_QUOTAOFF:
2029 case Q_SETINFO:
2030 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11002031 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002032 break;
2033 case Q_GETFMT:
2034 case Q_GETINFO:
2035 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11002036 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002037 break;
2038 default:
2039 rc = 0; /* let the kernel handle invalid cmds */
2040 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 }
2042 return rc;
2043}
2044
2045static int selinux_quota_on(struct dentry *dentry)
2046{
David Howells88e67f32008-11-14 10:39:21 +11002047 const struct cred *cred = current_cred();
2048
2049 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050}
2051
2052static int selinux_syslog(int type)
2053{
2054 int rc;
2055
Eric Paris200ac532009-02-12 15:01:04 -05002056 rc = cap_syslog(type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 if (rc)
2058 return rc;
2059
2060 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04002061 case 3: /* Read last kernel messages */
2062 case 10: /* Return size of the log buffer */
2063 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
2064 break;
2065 case 6: /* Disable logging to console */
2066 case 7: /* Enable logging to console */
2067 case 8: /* Set level of messages printed to console */
2068 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
2069 break;
2070 case 0: /* Close log */
2071 case 1: /* Open log */
2072 case 2: /* Read from log */
2073 case 4: /* Read/clear last kernel messages */
2074 case 5: /* Clear ring buffer */
2075 default:
2076 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2077 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 }
2079 return rc;
2080}
2081
2082/*
2083 * Check that a process has enough memory to allocate a new virtual
2084 * mapping. 0 means there is enough memory for the allocation to
2085 * succeed and -ENOMEM implies there is not.
2086 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 * Do not audit the selinux permission check, as this is applied to all
2088 * processes that allocate mappings.
2089 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002090static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091{
2092 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
David Howells3699c532009-01-06 22:27:01 +00002094 rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
2095 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (rc == 0)
2097 cap_sys_admin = 1;
2098
Alan Cox34b4e4a2007-08-22 14:01:28 -07002099 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100}
2101
2102/* binprm security operations */
2103
David Howellsa6f76f22008-11-14 10:39:24 +11002104static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105{
David Howellsa6f76f22008-11-14 10:39:24 +11002106 const struct task_security_struct *old_tsec;
2107 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002109 struct common_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11002110 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 int rc;
2112
Eric Paris200ac532009-02-12 15:01:04 -05002113 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 if (rc)
2115 return rc;
2116
David Howellsa6f76f22008-11-14 10:39:24 +11002117 /* SELinux context only depends on initial program or script and not
2118 * the script interpreter */
2119 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 return 0;
2121
David Howellsa6f76f22008-11-14 10:39:24 +11002122 old_tsec = current_security();
2123 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 isec = inode->i_security;
2125
2126 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002127 new_tsec->sid = old_tsec->sid;
2128 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
Michael LeMay28eba5b2006-06-27 02:53:42 -07002130 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002131 new_tsec->create_sid = 0;
2132 new_tsec->keycreate_sid = 0;
2133 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
David Howellsa6f76f22008-11-14 10:39:24 +11002135 if (old_tsec->exec_sid) {
2136 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002138 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 } else {
2140 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002141 rc = security_transition_sid(old_tsec->sid, isec->sid,
2142 SECCLASS_PROCESS, &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 if (rc)
2144 return rc;
2145 }
2146
Thomas Liu2bf49692009-07-14 12:14:09 -04002147 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002148 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Josef Sipek3d5ff522006-12-08 02:37:38 -08002150 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002151 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
David Howellsa6f76f22008-11-14 10:39:24 +11002153 if (new_tsec->sid == old_tsec->sid) {
2154 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2156 if (rc)
2157 return rc;
2158 } else {
2159 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002160 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2162 if (rc)
2163 return rc;
2164
David Howellsa6f76f22008-11-14 10:39:24 +11002165 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2167 if (rc)
2168 return rc;
2169
David Howellsa6f76f22008-11-14 10:39:24 +11002170 /* Check for shared state */
2171 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2172 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2173 SECCLASS_PROCESS, PROCESS__SHARE,
2174 NULL);
2175 if (rc)
2176 return -EPERM;
2177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
David Howellsa6f76f22008-11-14 10:39:24 +11002179 /* Make sure that anyone attempting to ptrace over a task that
2180 * changes its SID has the appropriate permit */
2181 if (bprm->unsafe &
2182 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2183 struct task_struct *tracer;
2184 struct task_security_struct *sec;
2185 u32 ptsid = 0;
2186
2187 rcu_read_lock();
2188 tracer = tracehook_tracer_task(current);
2189 if (likely(tracer != NULL)) {
2190 sec = __task_cred(tracer)->security;
2191 ptsid = sec->sid;
2192 }
2193 rcu_read_unlock();
2194
2195 if (ptsid != 0) {
2196 rc = avc_has_perm(ptsid, new_tsec->sid,
2197 SECCLASS_PROCESS,
2198 PROCESS__PTRACE, NULL);
2199 if (rc)
2200 return -EPERM;
2201 }
2202 }
2203
2204 /* Clear any possibly unsafe personality bits on exec: */
2205 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 }
2207
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 return 0;
2209}
2210
Eric Paris828dfe12008-04-17 13:17:49 -04002211static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{
David Howells275bb412008-11-14 10:39:19 +11002213 const struct cred *cred = current_cred();
2214 const struct task_security_struct *tsec = cred->security;
2215 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 int atsecure = 0;
2217
David Howells275bb412008-11-14 10:39:19 +11002218 sid = tsec->sid;
2219 osid = tsec->osid;
2220
2221 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 /* Enable secure mode for SIDs transitions unless
2223 the noatsecure permission is granted between
2224 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002225 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002226 SECCLASS_PROCESS,
2227 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 }
2229
Eric Paris200ac532009-02-12 15:01:04 -05002230 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231}
2232
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233extern struct vfsmount *selinuxfs_mount;
2234extern struct dentry *selinux_null;
2235
2236/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002237static inline void flush_unauthorized_files(const struct cred *cred,
2238 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239{
Thomas Liu2bf49692009-07-14 12:14:09 -04002240 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002242 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002243 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002245 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002247 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 if (tty) {
2249 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002250 if (!list_empty(&tty->tty_files)) {
2251 struct inode *inode;
2252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 /* Revalidate access to controlling tty.
2254 Use inode_has_perm on the tty inode directly rather
2255 than using file_has_perm, as this particular open
2256 file may belong to another process and we are only
2257 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002258 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2259 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002260 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002262 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 }
2264 }
2265 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002266 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002268 /* Reset controlling tty. */
2269 if (drop_tty)
2270 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271
2272 /* Revalidate access to inherited open files. */
2273
Thomas Liu2bf49692009-07-14 12:14:09 -04002274 COMMON_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
2276 spin_lock(&files->file_lock);
2277 for (;;) {
2278 unsigned long set, i;
2279 int fd;
2280
2281 j++;
2282 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002283 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002284 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002286 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 if (!set)
2288 continue;
2289 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002290 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 if (set & 1) {
2292 file = fget(i);
2293 if (!file)
2294 continue;
David Howells88e67f32008-11-14 10:39:21 +11002295 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 file,
2297 file_to_av(file))) {
2298 sys_close(i);
2299 fd = get_unused_fd();
2300 if (fd != i) {
2301 if (fd >= 0)
2302 put_unused_fd(fd);
2303 fput(file);
2304 continue;
2305 }
2306 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002307 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 } else {
David Howells745ca242008-11-14 10:39:22 +11002309 devnull = dentry_open(
2310 dget(selinux_null),
2311 mntget(selinuxfs_mount),
2312 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002313 if (IS_ERR(devnull)) {
2314 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 put_unused_fd(fd);
2316 fput(file);
2317 continue;
2318 }
2319 }
2320 fd_install(fd, devnull);
2321 }
2322 fput(file);
2323 }
2324 }
2325 spin_lock(&files->file_lock);
2326
2327 }
2328 spin_unlock(&files->file_lock);
2329}
2330
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331/*
David Howellsa6f76f22008-11-14 10:39:24 +11002332 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 */
David Howellsa6f76f22008-11-14 10:39:24 +11002334static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335{
David Howellsa6f76f22008-11-14 10:39:24 +11002336 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 int rc, i;
2339
David Howellsa6f76f22008-11-14 10:39:24 +11002340 new_tsec = bprm->cred->security;
2341 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 return;
2343
2344 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002345 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
David Howellsa6f76f22008-11-14 10:39:24 +11002347 /* Always clear parent death signal on SID transitions. */
2348 current->pdeath_signal = 0;
2349
2350 /* Check whether the new SID can inherit resource limits from the old
2351 * SID. If not, reset all soft limits to the lower of the current
2352 * task's hard limit and the init task's soft limit.
2353 *
2354 * Note that the setting of hard limits (even to lower them) can be
2355 * controlled by the setrlimit check. The inclusion of the init task's
2356 * soft limit into the computation is to avoid resetting soft limits
2357 * higher than the default soft limit for cases where the default is
2358 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2359 */
2360 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2361 PROCESS__RLIMITINH, NULL);
2362 if (rc) {
2363 for (i = 0; i < RLIM_NLIMITS; i++) {
2364 rlim = current->signal->rlim + i;
2365 initrlim = init_task.signal->rlim + i;
2366 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2367 }
2368 update_rlimit_cpu(rlim->rlim_cur);
2369 }
2370}
2371
2372/*
2373 * Clean up the process immediately after the installation of new credentials
2374 * due to exec
2375 */
2376static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2377{
2378 const struct task_security_struct *tsec = current_security();
2379 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002380 u32 osid, sid;
2381 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002382
David Howellsa6f76f22008-11-14 10:39:24 +11002383 osid = tsec->osid;
2384 sid = tsec->sid;
2385
2386 if (sid == osid)
2387 return;
2388
2389 /* Check whether the new SID can inherit signal state from the old SID.
2390 * If not, clear itimers to avoid subsequent signal generation and
2391 * flush and unblock signals.
2392 *
2393 * This must occur _after_ the task SID has been updated so that any
2394 * kill done after the flush will be checked against the new SID.
2395 */
2396 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 if (rc) {
2398 memset(&itimer, 0, sizeof itimer);
2399 for (i = 0; i < 3; i++)
2400 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002402 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2403 __flush_signals(current);
2404 flush_signal_handlers(current, 1);
2405 sigemptyset(&current->blocked);
2406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 spin_unlock_irq(&current->sighand->siglock);
2408 }
2409
David Howellsa6f76f22008-11-14 10:39:24 +11002410 /* Wake up the parent if it is waiting so that it can recheck
2411 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002412 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002413 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002414 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415}
2416
2417/* superblock security operations */
2418
2419static int selinux_sb_alloc_security(struct super_block *sb)
2420{
2421 return superblock_alloc_security(sb);
2422}
2423
2424static void selinux_sb_free_security(struct super_block *sb)
2425{
2426 superblock_free_security(sb);
2427}
2428
2429static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2430{
2431 if (plen > olen)
2432 return 0;
2433
2434 return !memcmp(prefix, option, plen);
2435}
2436
2437static inline int selinux_option(char *option, int len)
2438{
Eric Paris832cbd92008-04-01 13:24:09 -04002439 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2440 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2441 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002442 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2443 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444}
2445
2446static inline void take_option(char **to, char *from, int *first, int len)
2447{
2448 if (!*first) {
2449 **to = ',';
2450 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002451 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 *first = 0;
2453 memcpy(*to, from, len);
2454 *to += len;
2455}
2456
Eric Paris828dfe12008-04-17 13:17:49 -04002457static inline void take_selinux_option(char **to, char *from, int *first,
2458 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002459{
2460 int current_size = 0;
2461
2462 if (!*first) {
2463 **to = '|';
2464 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002465 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002466 *first = 0;
2467
2468 while (current_size < len) {
2469 if (*from != '"') {
2470 **to = *from;
2471 *to += 1;
2472 }
2473 from += 1;
2474 current_size += 1;
2475 }
2476}
2477
Eric Parise0007522008-03-05 10:31:54 -05002478static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479{
2480 int fnosec, fsec, rc = 0;
2481 char *in_save, *in_curr, *in_end;
2482 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002483 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484
2485 in_curr = orig;
2486 sec_curr = copy;
2487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2489 if (!nosec) {
2490 rc = -ENOMEM;
2491 goto out;
2492 }
2493
2494 nosec_save = nosec;
2495 fnosec = fsec = 1;
2496 in_save = in_end = orig;
2497
2498 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002499 if (*in_end == '"')
2500 open_quote = !open_quote;
2501 if ((*in_end == ',' && open_quote == 0) ||
2502 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 int len = in_end - in_curr;
2504
2505 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002506 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 else
2508 take_option(&nosec, in_curr, &fnosec, len);
2509
2510 in_curr = in_end + 1;
2511 }
2512 } while (*in_end++);
2513
Eric Paris6931dfc2005-06-30 02:58:51 -07002514 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002515 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516out:
2517 return rc;
2518}
2519
James Morris12204e22008-12-19 10:44:42 +11002520static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521{
David Howells88e67f32008-11-14 10:39:21 +11002522 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002523 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 int rc;
2525
2526 rc = superblock_doinit(sb, data);
2527 if (rc)
2528 return rc;
2529
James Morris74192242008-12-19 11:41:10 +11002530 /* Allow all mounts performed by the kernel */
2531 if (flags & MS_KERNMOUNT)
2532 return 0;
2533
Thomas Liu2bf49692009-07-14 12:14:09 -04002534 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002535 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002536 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537}
2538
David Howells726c3342006-06-23 02:02:58 -07002539static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540{
David Howells88e67f32008-11-14 10:39:21 +11002541 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002542 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
Thomas Liu2bf49692009-07-14 12:14:09 -04002544 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002545 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002546 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547}
2548
Eric Paris828dfe12008-04-17 13:17:49 -04002549static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002550 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002551 char *type,
2552 unsigned long flags,
2553 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554{
David Howells88e67f32008-11-14 10:39:21 +11002555 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
2557 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002558 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002559 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 else
David Howells88e67f32008-11-14 10:39:21 +11002561 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002562 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563}
2564
2565static int selinux_umount(struct vfsmount *mnt, int flags)
2566{
David Howells88e67f32008-11-14 10:39:21 +11002567 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
David Howells88e67f32008-11-14 10:39:21 +11002569 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002570 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571}
2572
2573/* inode security operations */
2574
2575static int selinux_inode_alloc_security(struct inode *inode)
2576{
2577 return inode_alloc_security(inode);
2578}
2579
2580static void selinux_inode_free_security(struct inode *inode)
2581{
2582 inode_free_security(inode);
2583}
2584
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002585static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2586 char **name, void **value,
2587 size_t *len)
2588{
David Howells275bb412008-11-14 10:39:19 +11002589 const struct cred *cred = current_cred();
2590 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002591 struct inode_security_struct *dsec;
2592 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002593 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002594 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002595 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002596
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002597 dsec = dir->i_security;
2598 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002599
David Howells275bb412008-11-14 10:39:19 +11002600 sid = tsec->sid;
2601 newsid = tsec->create_sid;
2602
David P. Quigleycd895962009-01-16 09:22:04 -05002603 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002604 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002605 inode_mode_to_security_class(inode->i_mode),
2606 &newsid);
2607 if (rc) {
2608 printk(KERN_WARNING "%s: "
2609 "security_transition_sid failed, rc=%d (dev=%s "
2610 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002611 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002612 -rc, inode->i_sb->s_id, inode->i_ino);
2613 return rc;
2614 }
2615 }
2616
Eric Paris296fddf2006-09-25 23:32:00 -07002617 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002618 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002619 struct inode_security_struct *isec = inode->i_security;
2620 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2621 isec->sid = newsid;
2622 isec->initialized = 1;
2623 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002624
David P. Quigleycd895962009-01-16 09:22:04 -05002625 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002626 return -EOPNOTSUPP;
2627
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002628 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002629 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002630 if (!namep)
2631 return -ENOMEM;
2632 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002633 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002634
2635 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002636 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002637 if (rc) {
2638 kfree(namep);
2639 return rc;
2640 }
2641 *value = context;
2642 *len = clen;
2643 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002644
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002645 return 0;
2646}
2647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2649{
2650 return may_create(dir, dentry, SECCLASS_FILE);
2651}
2652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2654{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return may_link(dir, old_dentry, MAY_LINK);
2656}
2657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2659{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 return may_link(dir, dentry, MAY_UNLINK);
2661}
2662
2663static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2664{
2665 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2666}
2667
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2669{
2670 return may_create(dir, dentry, SECCLASS_DIR);
2671}
2672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2674{
2675 return may_link(dir, dentry, MAY_RMDIR);
2676}
2677
2678static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2679{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2681}
2682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002684 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685{
2686 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2687}
2688
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689static int selinux_inode_readlink(struct dentry *dentry)
2690{
David Howells88e67f32008-11-14 10:39:21 +11002691 const struct cred *cred = current_cred();
2692
2693 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694}
2695
2696static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2697{
David Howells88e67f32008-11-14 10:39:21 +11002698 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
David Howells88e67f32008-11-14 10:39:21 +11002700 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701}
2702
Al Virob77b0642008-07-17 09:37:02 -04002703static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704{
David Howells88e67f32008-11-14 10:39:21 +11002705 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
2707 if (!mask) {
2708 /* No permission to check. Existence test. */
2709 return 0;
2710 }
2711
David Howells88e67f32008-11-14 10:39:21 +11002712 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002713 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714}
2715
2716static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2717{
David Howells88e67f32008-11-14 10:39:21 +11002718 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002719 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002721 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2722 if (ia_valid & ATTR_FORCE) {
2723 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2724 ATTR_FORCE);
2725 if (!ia_valid)
2726 return 0;
2727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002729 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2730 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
David Howells88e67f32008-11-14 10:39:21 +11002731 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
David Howells88e67f32008-11-14 10:39:21 +11002733 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734}
2735
2736static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2737{
David Howells88e67f32008-11-14 10:39:21 +11002738 const struct cred *cred = current_cred();
2739
2740 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741}
2742
David Howells8f0cfa52008-04-29 00:59:41 -07002743static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002744{
David Howells88e67f32008-11-14 10:39:21 +11002745 const struct cred *cred = current_cred();
2746
Serge E. Hallynb5376772007-10-16 23:31:36 -07002747 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2748 sizeof XATTR_SECURITY_PREFIX - 1)) {
2749 if (!strcmp(name, XATTR_NAME_CAPS)) {
2750 if (!capable(CAP_SETFCAP))
2751 return -EPERM;
2752 } else if (!capable(CAP_SYS_ADMIN)) {
2753 /* A different attribute in the security namespace.
2754 Restrict to administrator. */
2755 return -EPERM;
2756 }
2757 }
2758
2759 /* Not an attribute we recognize, so just check the
2760 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002761 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002762}
2763
David Howells8f0cfa52008-04-29 00:59:41 -07002764static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2765 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 struct inode *inode = dentry->d_inode;
2768 struct inode_security_struct *isec = inode->i_security;
2769 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002770 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002771 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 int rc = 0;
2773
Serge E. Hallynb5376772007-10-16 23:31:36 -07002774 if (strcmp(name, XATTR_NAME_SELINUX))
2775 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
2777 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002778 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 return -EOPNOTSUPP;
2780
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302781 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 return -EPERM;
2783
Thomas Liu2bf49692009-07-14 12:14:09 -04002784 COMMON_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002785 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
David Howells275bb412008-11-14 10:39:19 +11002787 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 FILE__RELABELFROM, &ad);
2789 if (rc)
2790 return rc;
2791
2792 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002793 if (rc == -EINVAL) {
2794 if (!capable(CAP_MAC_ADMIN))
2795 return rc;
2796 rc = security_context_to_sid_force(value, size, &newsid);
2797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 if (rc)
2799 return rc;
2800
David Howells275bb412008-11-14 10:39:19 +11002801 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 FILE__RELABELTO, &ad);
2803 if (rc)
2804 return rc;
2805
David Howells275bb412008-11-14 10:39:19 +11002806 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002807 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 if (rc)
2809 return rc;
2810
2811 return avc_has_perm(newsid,
2812 sbsec->sid,
2813 SECCLASS_FILESYSTEM,
2814 FILESYSTEM__ASSOCIATE,
2815 &ad);
2816}
2817
David Howells8f0cfa52008-04-29 00:59:41 -07002818static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002819 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002820 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821{
2822 struct inode *inode = dentry->d_inode;
2823 struct inode_security_struct *isec = inode->i_security;
2824 u32 newsid;
2825 int rc;
2826
2827 if (strcmp(name, XATTR_NAME_SELINUX)) {
2828 /* Not an attribute we recognize, so nothing to do. */
2829 return;
2830 }
2831
Stephen Smalley12b29f32008-05-07 13:03:20 -04002832 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002834 printk(KERN_ERR "SELinux: unable to map context to SID"
2835 "for (%s, %lu), rc=%d\n",
2836 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 return;
2838 }
2839
2840 isec->sid = newsid;
2841 return;
2842}
2843
David Howells8f0cfa52008-04-29 00:59:41 -07002844static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845{
David Howells88e67f32008-11-14 10:39:21 +11002846 const struct cred *cred = current_cred();
2847
2848 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849}
2850
Eric Paris828dfe12008-04-17 13:17:49 -04002851static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852{
David Howells88e67f32008-11-14 10:39:21 +11002853 const struct cred *cred = current_cred();
2854
2855 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856}
2857
David Howells8f0cfa52008-04-29 00:59:41 -07002858static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002860 if (strcmp(name, XATTR_NAME_SELINUX))
2861 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
2863 /* No one is allowed to remove a SELinux security label.
2864 You can change the label, but all data must be labeled. */
2865 return -EACCES;
2866}
2867
James Morrisd381d8a2005-10-30 14:59:22 -08002868/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002869 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002870 *
2871 * Permission check is handled by selinux_inode_getxattr hook.
2872 */
David P. Quigley42492592008-02-04 22:29:39 -08002873static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874{
David P. Quigley42492592008-02-04 22:29:39 -08002875 u32 size;
2876 int error;
2877 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002880 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2881 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002883 /*
2884 * If the caller has CAP_MAC_ADMIN, then get the raw context
2885 * value even if it is not defined by current policy; otherwise,
2886 * use the in-core value under current policy.
2887 * Use the non-auditing forms of the permission checks since
2888 * getxattr may be called by unprivileged processes commonly
2889 * and lack of permission just means that we fall back to the
2890 * in-core context value, not a denial.
2891 */
David Howells3699c532009-01-06 22:27:01 +00002892 error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
2893 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002894 if (!error)
2895 error = security_sid_to_context_force(isec->sid, &context,
2896 &size);
2897 else
2898 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002899 if (error)
2900 return error;
2901 error = size;
2902 if (alloc) {
2903 *buffer = context;
2904 goto out_nofree;
2905 }
2906 kfree(context);
2907out_nofree:
2908 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909}
2910
2911static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002912 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913{
2914 struct inode_security_struct *isec = inode->i_security;
2915 u32 newsid;
2916 int rc;
2917
2918 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2919 return -EOPNOTSUPP;
2920
2921 if (!value || !size)
2922 return -EACCES;
2923
Eric Paris828dfe12008-04-17 13:17:49 -04002924 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 if (rc)
2926 return rc;
2927
2928 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002929 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 return 0;
2931}
2932
2933static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2934{
2935 const int len = sizeof(XATTR_NAME_SELINUX);
2936 if (buffer && len <= buffer_size)
2937 memcpy(buffer, XATTR_NAME_SELINUX, len);
2938 return len;
2939}
2940
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002941static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2942{
2943 struct inode_security_struct *isec = inode->i_security;
2944 *secid = isec->sid;
2945}
2946
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947/* file security operations */
2948
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002949static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950{
David Howells88e67f32008-11-14 10:39:21 +11002951 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002952 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2955 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2956 mask |= MAY_APPEND;
2957
Paul Moore389fb802009-03-27 17:10:34 -04002958 return file_has_perm(cred, file,
2959 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960}
2961
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002962static int selinux_file_permission(struct file *file, int mask)
2963{
Stephen Smalley20dda182009-06-22 14:54:53 -04002964 struct inode *inode = file->f_path.dentry->d_inode;
2965 struct file_security_struct *fsec = file->f_security;
2966 struct inode_security_struct *isec = inode->i_security;
2967 u32 sid = current_sid();
2968
Paul Moore389fb802009-03-27 17:10:34 -04002969 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002970 /* No permission to check. Existence test. */
2971 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002972
Stephen Smalley20dda182009-06-22 14:54:53 -04002973 if (sid == fsec->sid && fsec->isid == isec->sid &&
2974 fsec->pseqno == avc_policy_seqno())
2975 /* No change since dentry_open check. */
2976 return 0;
2977
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002978 return selinux_revalidate_file_permission(file, mask);
2979}
2980
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981static int selinux_file_alloc_security(struct file *file)
2982{
2983 return file_alloc_security(file);
2984}
2985
2986static void selinux_file_free_security(struct file *file)
2987{
2988 file_free_security(file);
2989}
2990
2991static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2992 unsigned long arg)
2993{
David Howells88e67f32008-11-14 10:39:21 +11002994 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04002995 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996
Stephen Smalley242631c2008-06-05 09:21:28 -04002997 if (_IOC_DIR(cmd) & _IOC_WRITE)
2998 av |= FILE__WRITE;
2999 if (_IOC_DIR(cmd) & _IOC_READ)
3000 av |= FILE__READ;
3001 if (!av)
3002 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
David Howells88e67f32008-11-14 10:39:21 +11003004 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005}
3006
3007static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3008{
David Howells88e67f32008-11-14 10:39:21 +11003009 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003010 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003011
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012#ifndef CONFIG_PPC32
3013 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3014 /*
3015 * We are making executable an anonymous mapping or a
3016 * private file mapping that will also be writable.
3017 * This has an additional check.
3018 */
David Howellsd84f4f92008-11-14 10:39:23 +11003019 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003021 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 }
3023#endif
3024
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
3084#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003085 if ((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#endif
3108
3109 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3110}
3111
3112static int selinux_file_lock(struct file *file, unsigned int cmd)
3113{
David Howells88e67f32008-11-14 10:39:21 +11003114 const struct cred *cred = current_cred();
3115
3116 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117}
3118
3119static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3120 unsigned long arg)
3121{
David Howells88e67f32008-11-14 10:39:21 +11003122 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 int err = 0;
3124
3125 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003126 case F_SETFL:
3127 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3128 err = -EINVAL;
3129 break;
3130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
Eric Paris828dfe12008-04-17 13:17:49 -04003132 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003133 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003135 }
3136 /* fall through */
3137 case F_SETOWN:
3138 case F_SETSIG:
3139 case F_GETFL:
3140 case F_GETOWN:
3141 case F_GETSIG:
3142 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003143 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003144 break;
3145 case F_GETLK:
3146 case F_SETLK:
3147 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003149 case F_GETLK64:
3150 case F_SETLK64:
3151 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003153 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3154 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003156 }
David Howells88e67f32008-11-14 10:39:21 +11003157 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003158 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 }
3160
3161 return err;
3162}
3163
3164static int selinux_file_set_fowner(struct file *file)
3165{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 struct file_security_struct *fsec;
3167
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003169 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
3171 return 0;
3172}
3173
3174static int selinux_file_send_sigiotask(struct task_struct *tsk,
3175 struct fown_struct *fown, int signum)
3176{
Eric Paris828dfe12008-04-17 13:17:49 -04003177 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003178 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 struct file_security_struct *fsec;
3181
3182 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003183 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 fsec = file->f_security;
3186
3187 if (!signum)
3188 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3189 else
3190 perm = signal_to_av(signum);
3191
David Howells275bb412008-11-14 10:39:19 +11003192 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 SECCLASS_PROCESS, perm, NULL);
3194}
3195
3196static int selinux_file_receive(struct file *file)
3197{
David Howells88e67f32008-11-14 10:39:21 +11003198 const struct cred *cred = current_cred();
3199
3200 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201}
3202
David Howells745ca242008-11-14 10:39:22 +11003203static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003204{
3205 struct file_security_struct *fsec;
3206 struct inode *inode;
3207 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003208
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003209 inode = file->f_path.dentry->d_inode;
3210 fsec = file->f_security;
3211 isec = inode->i_security;
3212 /*
3213 * Save inode label and policy sequence number
3214 * at open-time so that selinux_file_permission
3215 * can determine whether revalidation is necessary.
3216 * Task label is already saved in the file security
3217 * struct as its SID.
3218 */
3219 fsec->isid = isec->sid;
3220 fsec->pseqno = avc_policy_seqno();
3221 /*
3222 * Since the inode label or policy seqno may have changed
3223 * between the selinux_inode_permission check and the saving
3224 * of state above, recheck that access is still permitted.
3225 * Otherwise, access might never be revalidated against the
3226 * new inode label or new policy.
3227 * This check is not redundant - do not remove.
3228 */
David Howells88e67f32008-11-14 10:39:21 +11003229 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003230}
3231
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232/* task security operations */
3233
3234static int selinux_task_create(unsigned long clone_flags)
3235{
David Howells3b11a1d2008-11-14 10:39:26 +11003236 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237}
3238
David Howellsf1752ee2008-11-14 10:39:17 +11003239/*
David Howellsee18d642009-09-02 09:14:21 +01003240 * allocate the SELinux part of blank credentials
3241 */
3242static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3243{
3244 struct task_security_struct *tsec;
3245
3246 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3247 if (!tsec)
3248 return -ENOMEM;
3249
3250 cred->security = tsec;
3251 return 0;
3252}
3253
3254/*
David Howellsf1752ee2008-11-14 10:39:17 +11003255 * detach and free the LSM part of a set of credentials
3256 */
3257static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258{
David Howellsf1752ee2008-11-14 10:39:17 +11003259 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003260
3261 BUG_ON((unsigned long) cred->security < PAGE_SIZE);
3262 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003263 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264}
3265
David Howellsd84f4f92008-11-14 10:39:23 +11003266/*
3267 * prepare a new set of credentials for modification
3268 */
3269static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3270 gfp_t gfp)
3271{
3272 const struct task_security_struct *old_tsec;
3273 struct task_security_struct *tsec;
3274
3275 old_tsec = old->security;
3276
3277 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3278 if (!tsec)
3279 return -ENOMEM;
3280
3281 new->security = tsec;
3282 return 0;
3283}
3284
3285/*
David Howellsee18d642009-09-02 09:14:21 +01003286 * transfer the SELinux data to a blank set of creds
3287 */
3288static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3289{
3290 const struct task_security_struct *old_tsec = old->security;
3291 struct task_security_struct *tsec = new->security;
3292
3293 *tsec = *old_tsec;
3294}
3295
3296/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003297 * set the security data for a kernel service
3298 * - all the creation contexts are set to unlabelled
3299 */
3300static int selinux_kernel_act_as(struct cred *new, u32 secid)
3301{
3302 struct task_security_struct *tsec = new->security;
3303 u32 sid = current_sid();
3304 int ret;
3305
3306 ret = avc_has_perm(sid, secid,
3307 SECCLASS_KERNEL_SERVICE,
3308 KERNEL_SERVICE__USE_AS_OVERRIDE,
3309 NULL);
3310 if (ret == 0) {
3311 tsec->sid = secid;
3312 tsec->create_sid = 0;
3313 tsec->keycreate_sid = 0;
3314 tsec->sockcreate_sid = 0;
3315 }
3316 return ret;
3317}
3318
3319/*
3320 * set the file creation context in a security record to the same as the
3321 * objective context of the specified inode
3322 */
3323static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3324{
3325 struct inode_security_struct *isec = inode->i_security;
3326 struct task_security_struct *tsec = new->security;
3327 u32 sid = current_sid();
3328 int ret;
3329
3330 ret = avc_has_perm(sid, isec->sid,
3331 SECCLASS_KERNEL_SERVICE,
3332 KERNEL_SERVICE__CREATE_FILES_AS,
3333 NULL);
3334
3335 if (ret == 0)
3336 tsec->create_sid = isec->sid;
3337 return 0;
3338}
3339
Eric Paris25354c42009-08-13 09:45:03 -04003340static int selinux_kernel_module_request(void)
3341{
3342 return task_has_system(current, SYSTEM__MODULE_REQUEST);
3343}
3344
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3346{
David Howells3b11a1d2008-11-14 10:39:26 +11003347 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348}
3349
3350static int selinux_task_getpgid(struct task_struct *p)
3351{
David Howells3b11a1d2008-11-14 10:39:26 +11003352 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353}
3354
3355static int selinux_task_getsid(struct task_struct *p)
3356{
David Howells3b11a1d2008-11-14 10:39:26 +11003357 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358}
3359
David Quigleyf9008e42006-06-30 01:55:46 -07003360static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3361{
David Howells275bb412008-11-14 10:39:19 +11003362 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003363}
3364
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365static int selinux_task_setnice(struct task_struct *p, int nice)
3366{
3367 int rc;
3368
Eric Paris200ac532009-02-12 15:01:04 -05003369 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 if (rc)
3371 return rc;
3372
David Howells3b11a1d2008-11-14 10:39:26 +11003373 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374}
3375
James Morris03e68062006-06-23 02:03:58 -07003376static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3377{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003378 int rc;
3379
Eric Paris200ac532009-02-12 15:01:04 -05003380 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003381 if (rc)
3382 return rc;
3383
David Howells3b11a1d2008-11-14 10:39:26 +11003384 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003385}
3386
David Quigleya1836a42006-06-30 01:55:49 -07003387static int selinux_task_getioprio(struct task_struct *p)
3388{
David Howells3b11a1d2008-11-14 10:39:26 +11003389 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003390}
3391
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3393{
3394 struct rlimit *old_rlim = current->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
3396 /* Control the ability to change the hard limit (whether
3397 lowering or raising it), so that the hard limit can
3398 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003399 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003401 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402
3403 return 0;
3404}
3405
3406static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3407{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003408 int rc;
3409
Eric Paris200ac532009-02-12 15:01:04 -05003410 rc = cap_task_setscheduler(p, policy, lp);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003411 if (rc)
3412 return rc;
3413
David Howells3b11a1d2008-11-14 10:39:26 +11003414 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415}
3416
3417static int selinux_task_getscheduler(struct task_struct *p)
3418{
David Howells3b11a1d2008-11-14 10:39:26 +11003419 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420}
3421
David Quigley35601542006-06-23 02:04:01 -07003422static int selinux_task_movememory(struct task_struct *p)
3423{
David Howells3b11a1d2008-11-14 10:39:26 +11003424 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003425}
3426
David Quigleyf9008e42006-06-30 01:55:46 -07003427static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3428 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429{
3430 u32 perm;
3431 int rc;
3432
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 if (!sig)
3434 perm = PROCESS__SIGNULL; /* null signal; existence test */
3435 else
3436 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003437 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003438 rc = avc_has_perm(secid, task_sid(p),
3439 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003440 else
David Howells3b11a1d2008-11-14 10:39:26 +11003441 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003442 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443}
3444
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445static int selinux_task_wait(struct task_struct *p)
3446{
Eric Paris8a535142007-10-22 16:10:31 -04003447 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448}
3449
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450static void selinux_task_to_inode(struct task_struct *p,
3451 struct inode *inode)
3452{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003454 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455
David Howells275bb412008-11-14 10:39:19 +11003456 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458}
3459
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003461static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003462 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463{
3464 int offset, ihlen, ret = -EINVAL;
3465 struct iphdr _iph, *ih;
3466
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003467 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3469 if (ih == NULL)
3470 goto out;
3471
3472 ihlen = ih->ihl * 4;
3473 if (ihlen < sizeof(_iph))
3474 goto out;
3475
3476 ad->u.net.v4info.saddr = ih->saddr;
3477 ad->u.net.v4info.daddr = ih->daddr;
3478 ret = 0;
3479
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003480 if (proto)
3481 *proto = ih->protocol;
3482
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003484 case IPPROTO_TCP: {
3485 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
Eric Paris828dfe12008-04-17 13:17:49 -04003487 if (ntohs(ih->frag_off) & IP_OFFSET)
3488 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489
3490 offset += ihlen;
3491 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3492 if (th == NULL)
3493 break;
3494
3495 ad->u.net.sport = th->source;
3496 ad->u.net.dport = th->dest;
3497 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
Eric Paris828dfe12008-04-17 13:17:49 -04003500 case IPPROTO_UDP: {
3501 struct udphdr _udph, *uh;
3502
3503 if (ntohs(ih->frag_off) & IP_OFFSET)
3504 break;
3505
3506 offset += ihlen;
3507 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3508 if (uh == NULL)
3509 break;
3510
3511 ad->u.net.sport = uh->source;
3512 ad->u.net.dport = uh->dest;
3513 break;
3514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
James Morris2ee92d42006-11-13 16:09:01 -08003516 case IPPROTO_DCCP: {
3517 struct dccp_hdr _dccph, *dh;
3518
3519 if (ntohs(ih->frag_off) & IP_OFFSET)
3520 break;
3521
3522 offset += ihlen;
3523 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3524 if (dh == NULL)
3525 break;
3526
3527 ad->u.net.sport = dh->dccph_sport;
3528 ad->u.net.dport = dh->dccph_dport;
3529 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003530 }
James Morris2ee92d42006-11-13 16:09:01 -08003531
Eric Paris828dfe12008-04-17 13:17:49 -04003532 default:
3533 break;
3534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535out:
3536 return ret;
3537}
3538
3539#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3540
3541/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003542static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003543 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544{
3545 u8 nexthdr;
3546 int ret = -EINVAL, offset;
3547 struct ipv6hdr _ipv6h, *ip6;
3548
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003549 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3551 if (ip6 == NULL)
3552 goto out;
3553
3554 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3555 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3556 ret = 0;
3557
3558 nexthdr = ip6->nexthdr;
3559 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003560 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 if (offset < 0)
3562 goto out;
3563
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003564 if (proto)
3565 *proto = nexthdr;
3566
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 switch (nexthdr) {
3568 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003569 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
3571 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3572 if (th == NULL)
3573 break;
3574
3575 ad->u.net.sport = th->source;
3576 ad->u.net.dport = th->dest;
3577 break;
3578 }
3579
3580 case IPPROTO_UDP: {
3581 struct udphdr _udph, *uh;
3582
3583 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3584 if (uh == NULL)
3585 break;
3586
3587 ad->u.net.sport = uh->source;
3588 ad->u.net.dport = uh->dest;
3589 break;
3590 }
3591
James Morris2ee92d42006-11-13 16:09:01 -08003592 case IPPROTO_DCCP: {
3593 struct dccp_hdr _dccph, *dh;
3594
3595 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3596 if (dh == NULL)
3597 break;
3598
3599 ad->u.net.sport = dh->dccph_sport;
3600 ad->u.net.dport = dh->dccph_dport;
3601 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003602 }
James Morris2ee92d42006-11-13 16:09:01 -08003603
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 /* includes fragments */
3605 default:
3606 break;
3607 }
3608out:
3609 return ret;
3610}
3611
3612#endif /* IPV6 */
3613
Thomas Liu2bf49692009-07-14 12:14:09 -04003614static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003615 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616{
David Howellscf9481e2008-07-27 21:31:07 +10003617 char *addrp;
3618 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
3620 switch (ad->u.net.family) {
3621 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003622 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003623 if (ret)
3624 goto parse_error;
3625 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3626 &ad->u.net.v4info.daddr);
3627 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
3629#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3630 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003631 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003632 if (ret)
3633 goto parse_error;
3634 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3635 &ad->u.net.v6info.daddr);
3636 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637#endif /* IPV6 */
3638 default:
David Howellscf9481e2008-07-27 21:31:07 +10003639 addrp = NULL;
3640 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 }
3642
David Howellscf9481e2008-07-27 21:31:07 +10003643parse_error:
3644 printk(KERN_WARNING
3645 "SELinux: failure in selinux_parse_skb(),"
3646 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003648
3649okay:
3650 if (_addrp)
3651 *_addrp = addrp;
3652 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653}
3654
Paul Moore4f6a9932007-03-01 14:35:22 -05003655/**
Paul Moore220deb92008-01-29 08:38:23 -05003656 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003657 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003658 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003659 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003660 *
3661 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003662 * Check the various different forms of network peer labeling and determine
3663 * the peer label/SID for the packet; most of the magic actually occurs in
3664 * the security server function security_net_peersid_cmp(). The function
3665 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3666 * or -EACCES if @sid is invalid due to inconsistencies with the different
3667 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003668 *
3669 */
Paul Moore220deb92008-01-29 08:38:23 -05003670static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003671{
Paul Moore71f1cb02008-01-29 08:51:16 -05003672 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003673 u32 xfrm_sid;
3674 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003675 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003676
3677 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003678 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003679
Paul Moore71f1cb02008-01-29 08:51:16 -05003680 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3681 if (unlikely(err)) {
3682 printk(KERN_WARNING
3683 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3684 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003685 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003686 }
Paul Moore220deb92008-01-29 08:38:23 -05003687
3688 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003689}
3690
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691/* socket security operations */
3692static int socket_has_perm(struct task_struct *task, struct socket *sock,
3693 u32 perms)
3694{
3695 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04003696 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003697 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 int err = 0;
3699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 isec = SOCK_INODE(sock)->i_security;
3701
3702 if (isec->sid == SECINITSID_KERNEL)
3703 goto out;
David Howells275bb412008-11-14 10:39:19 +11003704 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
Thomas Liu2bf49692009-07-14 12:14:09 -04003706 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003708 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710out:
3711 return err;
3712}
3713
3714static int selinux_socket_create(int family, int type,
3715 int protocol, int kern)
3716{
David Howells275bb412008-11-14 10:39:19 +11003717 const struct cred *cred = current_cred();
3718 const struct task_security_struct *tsec = cred->security;
3719 u32 sid, newsid;
3720 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
3723 if (kern)
3724 goto out;
3725
David Howells275bb412008-11-14 10:39:19 +11003726 sid = tsec->sid;
3727 newsid = tsec->sockcreate_sid ?: sid;
3728
3729 secclass = socket_type_to_security_class(family, type, protocol);
3730 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
3732out:
3733 return err;
3734}
3735
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003736static int selinux_socket_post_create(struct socket *sock, int family,
3737 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738{
David Howells275bb412008-11-14 10:39:19 +11003739 const struct cred *cred = current_cred();
3740 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003742 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003743 u32 sid, newsid;
3744 int err = 0;
3745
3746 sid = tsec->sid;
3747 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748
3749 isec = SOCK_INODE(sock)->i_security;
3750
David Howells275bb412008-11-14 10:39:19 +11003751 if (kern)
3752 isec->sid = SECINITSID_KERNEL;
3753 else if (newsid)
3754 isec->sid = newsid;
3755 else
3756 isec->sid = sid;
3757
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 isec->initialized = 1;
3760
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003761 if (sock->sk) {
3762 sksec = sock->sk->sk_security;
3763 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003764 sksec->sclass = isec->sclass;
Paul Moore389fb802009-03-27 17:10:34 -04003765 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003766 }
3767
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003768 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769}
3770
3771/* Range of port numbers used to automatically bind.
3772 Need to determine whether we should perform a name_bind
3773 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
3775static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3776{
3777 u16 family;
3778 int err;
3779
3780 err = socket_has_perm(current, sock, SOCKET__BIND);
3781 if (err)
3782 goto out;
3783
3784 /*
3785 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003786 * Multiple address binding for SCTP is not supported yet: we just
3787 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 */
3789 family = sock->sk->sk_family;
3790 if (family == PF_INET || family == PF_INET6) {
3791 char *addrp;
3792 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04003793 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 struct sockaddr_in *addr4 = NULL;
3795 struct sockaddr_in6 *addr6 = NULL;
3796 unsigned short snum;
3797 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003798 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 isec = SOCK_INODE(sock)->i_security;
3801
3802 if (family == PF_INET) {
3803 addr4 = (struct sockaddr_in *)address;
3804 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 addrp = (char *)&addr4->sin_addr.s_addr;
3806 } else {
3807 addr6 = (struct sockaddr_in6 *)address;
3808 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 addrp = (char *)&addr6->sin6_addr.s6_addr;
3810 }
3811
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003812 if (snum) {
3813 int low, high;
3814
3815 inet_get_local_port_range(&low, &high);
3816
3817 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003818 err = sel_netport_sid(sk->sk_protocol,
3819 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003820 if (err)
3821 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003822 COMMON_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003823 ad.u.net.sport = htons(snum);
3824 ad.u.net.family = family;
3825 err = avc_has_perm(isec->sid, sid,
3826 isec->sclass,
3827 SOCKET__NAME_BIND, &ad);
3828 if (err)
3829 goto out;
3830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 }
Eric Paris828dfe12008-04-17 13:17:49 -04003832
3833 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003834 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 node_perm = TCP_SOCKET__NODE_BIND;
3836 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003837
James Morris13402582005-09-30 14:24:34 -04003838 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 node_perm = UDP_SOCKET__NODE_BIND;
3840 break;
James Morris2ee92d42006-11-13 16:09:01 -08003841
3842 case SECCLASS_DCCP_SOCKET:
3843 node_perm = DCCP_SOCKET__NODE_BIND;
3844 break;
3845
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 default:
3847 node_perm = RAWIP_SOCKET__NODE_BIND;
3848 break;
3849 }
Eric Paris828dfe12008-04-17 13:17:49 -04003850
Paul Moore224dfbd2008-01-29 08:38:13 -05003851 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 if (err)
3853 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003854
Thomas Liu2bf49692009-07-14 12:14:09 -04003855 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 ad.u.net.sport = htons(snum);
3857 ad.u.net.family = family;
3858
3859 if (family == PF_INET)
3860 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3861 else
3862 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3863
3864 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003865 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 if (err)
3867 goto out;
3868 }
3869out:
3870 return err;
3871}
3872
3873static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3874{
Paul Moore014ab192008-10-10 10:16:33 -04003875 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 struct inode_security_struct *isec;
3877 int err;
3878
3879 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3880 if (err)
3881 return err;
3882
3883 /*
James Morris2ee92d42006-11-13 16:09:01 -08003884 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 */
3886 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003887 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3888 isec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003889 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 struct sockaddr_in *addr4 = NULL;
3891 struct sockaddr_in6 *addr6 = NULL;
3892 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003893 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894
3895 if (sk->sk_family == PF_INET) {
3896 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003897 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 return -EINVAL;
3899 snum = ntohs(addr4->sin_port);
3900 } else {
3901 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003902 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 return -EINVAL;
3904 snum = ntohs(addr6->sin6_port);
3905 }
3906
Paul Moore3e112172008-04-10 10:48:14 -04003907 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 if (err)
3909 goto out;
3910
James Morris2ee92d42006-11-13 16:09:01 -08003911 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3912 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3913
Thomas Liu2bf49692009-07-14 12:14:09 -04003914 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 ad.u.net.dport = htons(snum);
3916 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003917 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 if (err)
3919 goto out;
3920 }
3921
Paul Moore014ab192008-10-10 10:16:33 -04003922 err = selinux_netlbl_socket_connect(sk, address);
3923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924out:
3925 return err;
3926}
3927
3928static int selinux_socket_listen(struct socket *sock, int backlog)
3929{
3930 return socket_has_perm(current, sock, SOCKET__LISTEN);
3931}
3932
3933static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3934{
3935 int err;
3936 struct inode_security_struct *isec;
3937 struct inode_security_struct *newisec;
3938
3939 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3940 if (err)
3941 return err;
3942
3943 newisec = SOCK_INODE(newsock)->i_security;
3944
3945 isec = SOCK_INODE(sock)->i_security;
3946 newisec->sclass = isec->sclass;
3947 newisec->sid = isec->sid;
3948 newisec->initialized = 1;
3949
3950 return 0;
3951}
3952
3953static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003954 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955{
Paul Moore389fb802009-03-27 17:10:34 -04003956 return socket_has_perm(current, sock, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957}
3958
3959static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3960 int size, int flags)
3961{
3962 return socket_has_perm(current, sock, SOCKET__READ);
3963}
3964
3965static int selinux_socket_getsockname(struct socket *sock)
3966{
3967 return socket_has_perm(current, sock, SOCKET__GETATTR);
3968}
3969
3970static int selinux_socket_getpeername(struct socket *sock)
3971{
3972 return socket_has_perm(current, sock, SOCKET__GETATTR);
3973}
3974
Eric Paris828dfe12008-04-17 13:17:49 -04003975static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976{
Paul Mooref8687af2006-10-30 15:22:15 -08003977 int err;
3978
3979 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3980 if (err)
3981 return err;
3982
3983 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984}
3985
3986static int selinux_socket_getsockopt(struct socket *sock, int level,
3987 int optname)
3988{
3989 return socket_has_perm(current, sock, SOCKET__GETOPT);
3990}
3991
3992static int selinux_socket_shutdown(struct socket *sock, int how)
3993{
3994 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
3995}
3996
3997static int selinux_socket_unix_stream_connect(struct socket *sock,
3998 struct socket *other,
3999 struct sock *newsk)
4000{
4001 struct sk_security_struct *ssec;
4002 struct inode_security_struct *isec;
4003 struct inode_security_struct *other_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004004 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 int err;
4006
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 isec = SOCK_INODE(sock)->i_security;
4008 other_isec = SOCK_INODE(other)->i_security;
4009
Thomas Liu2bf49692009-07-14 12:14:09 -04004010 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 ad.u.net.sk = other->sk;
4012
4013 err = avc_has_perm(isec->sid, other_isec->sid,
4014 isec->sclass,
4015 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4016 if (err)
4017 return err;
4018
4019 /* connecting socket */
4020 ssec = sock->sk->sk_security;
4021 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004022
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 /* server child socket */
4024 ssec = newsk->sk_security;
4025 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004026 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4027
4028 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029}
4030
4031static int selinux_socket_unix_may_send(struct socket *sock,
4032 struct socket *other)
4033{
4034 struct inode_security_struct *isec;
4035 struct inode_security_struct *other_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004036 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 int err;
4038
4039 isec = SOCK_INODE(sock)->i_security;
4040 other_isec = SOCK_INODE(other)->i_security;
4041
Thomas Liu2bf49692009-07-14 12:14:09 -04004042 COMMON_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 ad.u.net.sk = other->sk;
4044
4045 err = avc_has_perm(isec->sid, other_isec->sid,
4046 isec->sclass, SOCKET__SENDTO, &ad);
4047 if (err)
4048 return err;
4049
4050 return 0;
4051}
4052
Paul Mooreeffad8d2008-01-29 08:49:27 -05004053static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4054 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004055 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004056{
4057 int err;
4058 u32 if_sid;
4059 u32 node_sid;
4060
4061 err = sel_netif_sid(ifindex, &if_sid);
4062 if (err)
4063 return err;
4064 err = avc_has_perm(peer_sid, if_sid,
4065 SECCLASS_NETIF, NETIF__INGRESS, ad);
4066 if (err)
4067 return err;
4068
4069 err = sel_netnode_sid(addrp, family, &node_sid);
4070 if (err)
4071 return err;
4072 return avc_has_perm(peer_sid, node_sid,
4073 SECCLASS_NODE, NODE__RECVFROM, ad);
4074}
4075
Paul Moore220deb92008-01-29 08:38:23 -05004076static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004077 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004078{
Paul Moore277d3422008-12-31 12:54:11 -05004079 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004080 struct sk_security_struct *sksec = sk->sk_security;
4081 u32 peer_sid;
4082 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004083 struct common_audit_data ad;
Paul Moored8395c82008-10-10 10:16:30 -04004084 char *addrp;
4085
Thomas Liu2bf49692009-07-14 12:14:09 -04004086 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004087 ad.u.net.netif = skb->iif;
4088 ad.u.net.family = family;
4089 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4090 if (err)
4091 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004092
Paul Moore58bfbb52009-03-27 17:10:41 -04004093 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004094 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004095 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004096 if (err)
4097 return err;
4098 }
Paul Moore220deb92008-01-29 08:38:23 -05004099
4100 if (selinux_policycap_netpeer) {
4101 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004103 return err;
4104 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004105 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004106 if (err)
4107 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004108 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004109 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004110 if (err)
4111 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004112 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004114
James Morris4e5ab4c2006-06-09 00:33:33 -07004115 return err;
4116}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004117
James Morris4e5ab4c2006-06-09 00:33:33 -07004118static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4119{
Paul Moore220deb92008-01-29 08:38:23 -05004120 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004121 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004122 u16 family = sk->sk_family;
4123 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004124 struct common_audit_data ad;
Paul Moore220deb92008-01-29 08:38:23 -05004125 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004126 u8 secmark_active;
4127 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004128
James Morris4e5ab4c2006-06-09 00:33:33 -07004129 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004130 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004131
4132 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004133 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004134 family = PF_INET;
4135
Paul Moored8395c82008-10-10 10:16:30 -04004136 /* If any sort of compatibility mode is enabled then handoff processing
4137 * to the selinux_sock_rcv_skb_compat() function to deal with the
4138 * special handling. We do this in an attempt to keep this function
4139 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004140 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004141 return selinux_sock_rcv_skb_compat(sk, skb, family);
4142
4143 secmark_active = selinux_secmark_enabled();
4144 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4145 if (!secmark_active && !peerlbl_active)
4146 return 0;
4147
Thomas Liu2bf49692009-07-14 12:14:09 -04004148 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004149 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004150 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004151 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004152 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004153 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004154
Paul Moored8395c82008-10-10 10:16:30 -04004155 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004156 u32 peer_sid;
4157
4158 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4159 if (err)
4160 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004161 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4162 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004163 if (err) {
4164 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004165 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004166 }
Paul Moored621d352008-01-29 08:43:36 -05004167 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4168 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004169 if (err)
4170 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004171 }
4172
Paul Moored8395c82008-10-10 10:16:30 -04004173 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004174 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4175 PACKET__RECV, &ad);
4176 if (err)
4177 return err;
4178 }
4179
Paul Moored621d352008-01-29 08:43:36 -05004180 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181}
4182
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004183static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4184 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185{
4186 int err = 0;
4187 char *scontext;
4188 u32 scontext_len;
4189 struct sk_security_struct *ssec;
4190 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004191 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
4193 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004194
Paul Moore3de4bab2006-11-17 17:38:54 -05004195 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4196 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004197 ssec = sock->sk->sk_security;
4198 peer_sid = ssec->peer_sid;
4199 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004200 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 err = -ENOPROTOOPT;
4202 goto out;
4203 }
4204
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004205 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4206
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 if (err)
4208 goto out;
4209
4210 if (scontext_len > len) {
4211 err = -ERANGE;
4212 goto out_len;
4213 }
4214
4215 if (copy_to_user(optval, scontext, scontext_len))
4216 err = -EFAULT;
4217
4218out_len:
4219 if (put_user(scontext_len, optlen))
4220 err = -EFAULT;
4221
4222 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004223out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 return err;
4225}
4226
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004227static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004228{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004229 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004230 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004231
Paul Mooreaa862902008-10-10 10:16:29 -04004232 if (skb && skb->protocol == htons(ETH_P_IP))
4233 family = PF_INET;
4234 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4235 family = PF_INET6;
4236 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004237 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004238 else
4239 goto out;
4240
4241 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004242 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004243 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004244 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004245
Paul Moore75e22912008-01-29 08:38:04 -05004246out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004247 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004248 if (peer_secid == SECSID_NULL)
4249 return -EINVAL;
4250 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004251}
4252
Al Viro7d877f32005-10-21 03:20:43 -04004253static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254{
4255 return sk_alloc_security(sk, family, priority);
4256}
4257
4258static void selinux_sk_free_security(struct sock *sk)
4259{
4260 sk_free_security(sk);
4261}
4262
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004263static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4264{
4265 struct sk_security_struct *ssec = sk->sk_security;
4266 struct sk_security_struct *newssec = newsk->sk_security;
4267
4268 newssec->sid = ssec->sid;
4269 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004270 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004271
Paul Moore389fb802009-03-27 17:10:34 -04004272 selinux_netlbl_sk_security_reset(newssec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004273}
4274
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004275static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004276{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004277 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004278 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004279 else {
4280 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004281
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004282 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004283 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004284}
4285
Eric Paris828dfe12008-04-17 13:17:49 -04004286static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004287{
4288 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4289 struct sk_security_struct *sksec = sk->sk_security;
4290
David Woodhouse2148ccc2006-09-29 15:50:25 -07004291 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4292 sk->sk_family == PF_UNIX)
4293 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004294 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004295}
4296
Adrian Bunk9a673e52006-08-15 00:03:53 -07004297static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4298 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004299{
4300 struct sk_security_struct *sksec = sk->sk_security;
4301 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004302 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004303 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004304 u32 peersid;
4305
Paul Mooreaa862902008-10-10 10:16:29 -04004306 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4307 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4308 family = PF_INET;
4309
4310 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004311 if (err)
4312 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004313 if (peersid == SECSID_NULL) {
4314 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004315 req->peer_secid = SECSID_NULL;
Paul Moore389fb802009-03-27 17:10:34 -04004316 } else {
4317 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4318 if (err)
4319 return err;
4320 req->secid = newsid;
4321 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004322 }
4323
Paul Moore389fb802009-03-27 17:10:34 -04004324 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004325}
4326
Adrian Bunk9a673e52006-08-15 00:03:53 -07004327static void selinux_inet_csk_clone(struct sock *newsk,
4328 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004329{
4330 struct sk_security_struct *newsksec = newsk->sk_security;
4331
4332 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004333 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004334 /* NOTE: Ideally, we should also get the isec->sid for the
4335 new socket in sync, but we don't have the isec available yet.
4336 So we will wait until sock_graft to do it, by which
4337 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004338
Paul Moore9f2ad662006-11-17 17:38:53 -05004339 /* We don't need to take any sort of lock here as we are the only
4340 * thread with access to newsksec */
Paul Moore389fb802009-03-27 17:10:34 -04004341 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004342}
4343
Paul Moore014ab192008-10-10 10:16:33 -04004344static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004345{
Paul Mooreaa862902008-10-10 10:16:29 -04004346 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004347 struct sk_security_struct *sksec = sk->sk_security;
4348
Paul Mooreaa862902008-10-10 10:16:29 -04004349 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4350 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4351 family = PF_INET;
4352
4353 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004354}
4355
Adrian Bunk9a673e52006-08-15 00:03:53 -07004356static void selinux_req_classify_flow(const struct request_sock *req,
4357 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004358{
4359 fl->secid = req->secid;
4360}
4361
Paul Mooreed6d76e2009-08-28 18:12:49 -04004362static int selinux_tun_dev_create(void)
4363{
4364 u32 sid = current_sid();
4365
4366 /* we aren't taking into account the "sockcreate" SID since the socket
4367 * that is being created here is not a socket in the traditional sense,
4368 * instead it is a private sock, accessible only to the kernel, and
4369 * representing a wide range of network traffic spanning multiple
4370 * connections unlike traditional sockets - check the TUN driver to
4371 * get a better understanding of why this socket is special */
4372
4373 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4374 NULL);
4375}
4376
4377static void selinux_tun_dev_post_create(struct sock *sk)
4378{
4379 struct sk_security_struct *sksec = sk->sk_security;
4380
4381 /* we don't currently perform any NetLabel based labeling here and it
4382 * isn't clear that we would want to do so anyway; while we could apply
4383 * labeling without the support of the TUN user the resulting labeled
4384 * traffic from the other end of the connection would almost certainly
4385 * cause confusion to the TUN user that had no idea network labeling
4386 * protocols were being used */
4387
4388 /* see the comments in selinux_tun_dev_create() about why we don't use
4389 * the sockcreate SID here */
4390
4391 sksec->sid = current_sid();
4392 sksec->sclass = SECCLASS_TUN_SOCKET;
4393}
4394
4395static int selinux_tun_dev_attach(struct sock *sk)
4396{
4397 struct sk_security_struct *sksec = sk->sk_security;
4398 u32 sid = current_sid();
4399 int err;
4400
4401 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4402 TUN_SOCKET__RELABELFROM, NULL);
4403 if (err)
4404 return err;
4405 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4406 TUN_SOCKET__RELABELTO, NULL);
4407 if (err)
4408 return err;
4409
4410 sksec->sid = sid;
4411
4412 return 0;
4413}
4414
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4416{
4417 int err = 0;
4418 u32 perm;
4419 struct nlmsghdr *nlh;
4420 struct socket *sock = sk->sk_socket;
4421 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004422
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 if (skb->len < NLMSG_SPACE(0)) {
4424 err = -EINVAL;
4425 goto out;
4426 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004427 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004428
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4430 if (err) {
4431 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004432 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 "SELinux: unrecognized netlink message"
4434 " type=%hu for sclass=%hu\n",
4435 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004436 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 err = 0;
4438 }
4439
4440 /* Ignore */
4441 if (err == -ENOENT)
4442 err = 0;
4443 goto out;
4444 }
4445
4446 err = socket_has_perm(current, sock, perm);
4447out:
4448 return err;
4449}
4450
4451#ifdef CONFIG_NETFILTER
4452
Paul Mooreeffad8d2008-01-29 08:49:27 -05004453static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4454 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455{
Paul Mooredfaebe92008-10-10 10:16:31 -04004456 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004457 char *addrp;
4458 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004459 struct common_audit_data ad;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004460 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004461 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004462 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004463
Paul Mooreeffad8d2008-01-29 08:49:27 -05004464 if (!selinux_policycap_netpeer)
4465 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004466
Paul Mooreeffad8d2008-01-29 08:49:27 -05004467 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004468 netlbl_active = netlbl_enabled();
4469 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004470 if (!secmark_active && !peerlbl_active)
4471 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004472
Paul Moored8395c82008-10-10 10:16:30 -04004473 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4474 return NF_DROP;
4475
Thomas Liu2bf49692009-07-14 12:14:09 -04004476 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004477 ad.u.net.netif = ifindex;
4478 ad.u.net.family = family;
4479 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4480 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481
Paul Mooredfaebe92008-10-10 10:16:31 -04004482 if (peerlbl_active) {
4483 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4484 peer_sid, &ad);
4485 if (err) {
4486 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004487 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004488 }
4489 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004490
4491 if (secmark_active)
4492 if (avc_has_perm(peer_sid, skb->secmark,
4493 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4494 return NF_DROP;
4495
Paul Moore948bf852008-10-10 10:16:32 -04004496 if (netlbl_active)
4497 /* we do this in the FORWARD path and not the POST_ROUTING
4498 * path because we want to make sure we apply the necessary
4499 * labeling before IPsec is applied so we can leverage AH
4500 * protection */
4501 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4502 return NF_DROP;
4503
Paul Mooreeffad8d2008-01-29 08:49:27 -05004504 return NF_ACCEPT;
4505}
4506
4507static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4508 struct sk_buff *skb,
4509 const struct net_device *in,
4510 const struct net_device *out,
4511 int (*okfn)(struct sk_buff *))
4512{
4513 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4514}
4515
4516#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4517static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4518 struct sk_buff *skb,
4519 const struct net_device *in,
4520 const struct net_device *out,
4521 int (*okfn)(struct sk_buff *))
4522{
4523 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4524}
4525#endif /* IPV6 */
4526
Paul Moore948bf852008-10-10 10:16:32 -04004527static unsigned int selinux_ip_output(struct sk_buff *skb,
4528 u16 family)
4529{
4530 u32 sid;
4531
4532 if (!netlbl_enabled())
4533 return NF_ACCEPT;
4534
4535 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4536 * because we want to make sure we apply the necessary labeling
4537 * before IPsec is applied so we can leverage AH protection */
4538 if (skb->sk) {
4539 struct sk_security_struct *sksec = skb->sk->sk_security;
4540 sid = sksec->sid;
4541 } else
4542 sid = SECINITSID_KERNEL;
4543 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4544 return NF_DROP;
4545
4546 return NF_ACCEPT;
4547}
4548
4549static unsigned int selinux_ipv4_output(unsigned int hooknum,
4550 struct sk_buff *skb,
4551 const struct net_device *in,
4552 const struct net_device *out,
4553 int (*okfn)(struct sk_buff *))
4554{
4555 return selinux_ip_output(skb, PF_INET);
4556}
4557
Paul Mooreeffad8d2008-01-29 08:49:27 -05004558static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4559 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004560 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004561{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004562 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004563 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004564 struct common_audit_data ad;
Paul Moored8395c82008-10-10 10:16:30 -04004565 char *addrp;
4566 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004567
Paul Mooreeffad8d2008-01-29 08:49:27 -05004568 if (sk == NULL)
4569 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004570 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004571
Thomas Liu2bf49692009-07-14 12:14:09 -04004572 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004573 ad.u.net.netif = ifindex;
4574 ad.u.net.family = family;
4575 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4576 return NF_DROP;
4577
Paul Moore58bfbb52009-03-27 17:10:41 -04004578 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004579 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004580 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004581 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004582
Paul Mooreeffad8d2008-01-29 08:49:27 -05004583 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004584 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004585 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004586
Paul Mooreeffad8d2008-01-29 08:49:27 -05004587 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588}
4589
Paul Mooreeffad8d2008-01-29 08:49:27 -05004590static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4591 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004593 u32 secmark_perm;
4594 u32 peer_sid;
4595 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004596 struct common_audit_data ad;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004597 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004598 u8 secmark_active;
4599 u8 peerlbl_active;
4600
Paul Mooreeffad8d2008-01-29 08:49:27 -05004601 /* If any sort of compatibility mode is enabled then handoff processing
4602 * to the selinux_ip_postroute_compat() function to deal with the
4603 * special handling. We do this in an attempt to keep this function
4604 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004605 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004606 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004607#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004608 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4609 * packet transformation so allow the packet to pass without any checks
4610 * since we'll have another chance to perform access control checks
4611 * when the packet is on it's final way out.
4612 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4613 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004614 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004615 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004616#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004617 secmark_active = selinux_secmark_enabled();
4618 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4619 if (!secmark_active && !peerlbl_active)
4620 return NF_ACCEPT;
4621
Paul Moored8395c82008-10-10 10:16:30 -04004622 /* if the packet is being forwarded then get the peer label from the
4623 * packet itself; otherwise check to see if it is from a local
4624 * application or the kernel, if from an application get the peer label
4625 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004626 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004627 if (sk == NULL) {
4628 switch (family) {
4629 case PF_INET:
4630 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4631 secmark_perm = PACKET__FORWARD_OUT;
4632 else
4633 secmark_perm = PACKET__SEND;
4634 break;
4635 case PF_INET6:
4636 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4637 secmark_perm = PACKET__FORWARD_OUT;
4638 else
4639 secmark_perm = PACKET__SEND;
4640 break;
4641 default:
4642 return NF_DROP;
4643 }
4644 if (secmark_perm == PACKET__FORWARD_OUT) {
4645 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4646 return NF_DROP;
4647 } else
4648 peer_sid = SECINITSID_KERNEL;
4649 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004650 struct sk_security_struct *sksec = sk->sk_security;
4651 peer_sid = sksec->sid;
4652 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004653 }
4654
Thomas Liu2bf49692009-07-14 12:14:09 -04004655 COMMON_AUDIT_DATA_INIT(&ad, NET);
Paul Moored8395c82008-10-10 10:16:30 -04004656 ad.u.net.netif = ifindex;
4657 ad.u.net.family = family;
4658 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4659 return NF_DROP;
4660
Paul Mooreeffad8d2008-01-29 08:49:27 -05004661 if (secmark_active)
4662 if (avc_has_perm(peer_sid, skb->secmark,
4663 SECCLASS_PACKET, secmark_perm, &ad))
4664 return NF_DROP;
4665
4666 if (peerlbl_active) {
4667 u32 if_sid;
4668 u32 node_sid;
4669
4670 if (sel_netif_sid(ifindex, &if_sid))
4671 return NF_DROP;
4672 if (avc_has_perm(peer_sid, if_sid,
4673 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4674 return NF_DROP;
4675
4676 if (sel_netnode_sid(addrp, family, &node_sid))
4677 return NF_DROP;
4678 if (avc_has_perm(peer_sid, node_sid,
4679 SECCLASS_NODE, NODE__SENDTO, &ad))
4680 return NF_DROP;
4681 }
4682
4683 return NF_ACCEPT;
4684}
4685
4686static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4687 struct sk_buff *skb,
4688 const struct net_device *in,
4689 const struct net_device *out,
4690 int (*okfn)(struct sk_buff *))
4691{
4692 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693}
4694
4695#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004696static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4697 struct sk_buff *skb,
4698 const struct net_device *in,
4699 const struct net_device *out,
4700 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004702 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704#endif /* IPV6 */
4705
4706#endif /* CONFIG_NETFILTER */
4707
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4709{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 int err;
4711
Eric Paris200ac532009-02-12 15:01:04 -05004712 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 if (err)
4714 return err;
4715
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004716 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717}
4718
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004719static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004721 int err;
Thomas Liu2bf49692009-07-14 12:14:09 -04004722 struct common_audit_data ad;
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004723
Eric Paris200ac532009-02-12 15:01:04 -05004724 err = cap_netlink_recv(skb, capability);
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004725 if (err)
4726 return err;
4727
Thomas Liu2bf49692009-07-14 12:14:09 -04004728 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004729 ad.u.cap = capability;
4730
4731 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004732 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733}
4734
4735static int ipc_alloc_security(struct task_struct *task,
4736 struct kern_ipc_perm *perm,
4737 u16 sclass)
4738{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004740 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741
James Morris89d155e2005-10-30 14:59:21 -08004742 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 if (!isec)
4744 return -ENOMEM;
4745
David Howells275bb412008-11-14 10:39:19 +11004746 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004748 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 perm->security = isec;
4750
4751 return 0;
4752}
4753
4754static void ipc_free_security(struct kern_ipc_perm *perm)
4755{
4756 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 perm->security = NULL;
4758 kfree(isec);
4759}
4760
4761static int msg_msg_alloc_security(struct msg_msg *msg)
4762{
4763 struct msg_security_struct *msec;
4764
James Morris89d155e2005-10-30 14:59:21 -08004765 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 if (!msec)
4767 return -ENOMEM;
4768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 msec->sid = SECINITSID_UNLABELED;
4770 msg->security = msec;
4771
4772 return 0;
4773}
4774
4775static void msg_msg_free_security(struct msg_msg *msg)
4776{
4777 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
4779 msg->security = NULL;
4780 kfree(msec);
4781}
4782
4783static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004784 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004787 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004788 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 isec = ipc_perms->security;
4791
Thomas Liu2bf49692009-07-14 12:14:09 -04004792 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 ad.u.ipc_id = ipc_perms->key;
4794
David Howells275bb412008-11-14 10:39:19 +11004795 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796}
4797
4798static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4799{
4800 return msg_msg_alloc_security(msg);
4801}
4802
4803static void selinux_msg_msg_free_security(struct msg_msg *msg)
4804{
4805 msg_msg_free_security(msg);
4806}
4807
4808/* message queue security operations */
4809static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4810{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004812 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004813 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 int rc;
4815
4816 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4817 if (rc)
4818 return rc;
4819
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 isec = msq->q_perm.security;
4821
Thomas Liu2bf49692009-07-14 12:14:09 -04004822 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004823 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824
David Howells275bb412008-11-14 10:39:19 +11004825 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 MSGQ__CREATE, &ad);
4827 if (rc) {
4828 ipc_free_security(&msq->q_perm);
4829 return rc;
4830 }
4831 return 0;
4832}
4833
4834static void selinux_msg_queue_free_security(struct msg_queue *msq)
4835{
4836 ipc_free_security(&msq->q_perm);
4837}
4838
4839static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004842 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004843 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 isec = msq->q_perm.security;
4846
Thomas Liu2bf49692009-07-14 12:14:09 -04004847 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 ad.u.ipc_id = msq->q_perm.key;
4849
David Howells275bb412008-11-14 10:39:19 +11004850 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 MSGQ__ASSOCIATE, &ad);
4852}
4853
4854static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4855{
4856 int err;
4857 int perms;
4858
Eric Paris828dfe12008-04-17 13:17:49 -04004859 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 case IPC_INFO:
4861 case MSG_INFO:
4862 /* No specific object, just general system-wide information. */
4863 return task_has_system(current, SYSTEM__IPC_INFO);
4864 case IPC_STAT:
4865 case MSG_STAT:
4866 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4867 break;
4868 case IPC_SET:
4869 perms = MSGQ__SETATTR;
4870 break;
4871 case IPC_RMID:
4872 perms = MSGQ__DESTROY;
4873 break;
4874 default:
4875 return 0;
4876 }
4877
Stephen Smalley6af963f2005-05-01 08:58:39 -07004878 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 return err;
4880}
4881
4882static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4883{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 struct ipc_security_struct *isec;
4885 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004886 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004887 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 int rc;
4889
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 isec = msq->q_perm.security;
4891 msec = msg->security;
4892
4893 /*
4894 * First time through, need to assign label to the message
4895 */
4896 if (msec->sid == SECINITSID_UNLABELED) {
4897 /*
4898 * Compute new sid based on current process and
4899 * message queue this message will be stored in
4900 */
David Howells275bb412008-11-14 10:39:19 +11004901 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 &msec->sid);
4903 if (rc)
4904 return rc;
4905 }
4906
Thomas Liu2bf49692009-07-14 12:14:09 -04004907 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 ad.u.ipc_id = msq->q_perm.key;
4909
4910 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004911 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 MSGQ__WRITE, &ad);
4913 if (!rc)
4914 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11004915 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
4916 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 if (!rc)
4918 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11004919 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
4920 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921
4922 return rc;
4923}
4924
4925static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
4926 struct task_struct *target,
4927 long type, int mode)
4928{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 struct ipc_security_struct *isec;
4930 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004931 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004932 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 int rc;
4934
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 isec = msq->q_perm.security;
4936 msec = msg->security;
4937
Thomas Liu2bf49692009-07-14 12:14:09 -04004938 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004939 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940
David Howells275bb412008-11-14 10:39:19 +11004941 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 SECCLASS_MSGQ, MSGQ__READ, &ad);
4943 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11004944 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 SECCLASS_MSG, MSG__RECEIVE, &ad);
4946 return rc;
4947}
4948
4949/* Shared Memory security operations */
4950static int selinux_shm_alloc_security(struct shmid_kernel *shp)
4951{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004953 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004954 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 int rc;
4956
4957 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
4958 if (rc)
4959 return rc;
4960
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 isec = shp->shm_perm.security;
4962
Thomas Liu2bf49692009-07-14 12:14:09 -04004963 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004964 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965
David Howells275bb412008-11-14 10:39:19 +11004966 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 SHM__CREATE, &ad);
4968 if (rc) {
4969 ipc_free_security(&shp->shm_perm);
4970 return rc;
4971 }
4972 return 0;
4973}
4974
4975static void selinux_shm_free_security(struct shmid_kernel *shp)
4976{
4977 ipc_free_security(&shp->shm_perm);
4978}
4979
4980static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
4981{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004983 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004984 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 isec = shp->shm_perm.security;
4987
Thomas Liu2bf49692009-07-14 12:14:09 -04004988 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 ad.u.ipc_id = shp->shm_perm.key;
4990
David Howells275bb412008-11-14 10:39:19 +11004991 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 SHM__ASSOCIATE, &ad);
4993}
4994
4995/* Note, at this point, shp is locked down */
4996static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
4997{
4998 int perms;
4999 int err;
5000
Eric Paris828dfe12008-04-17 13:17:49 -04005001 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 case IPC_INFO:
5003 case SHM_INFO:
5004 /* No specific object, just general system-wide information. */
5005 return task_has_system(current, SYSTEM__IPC_INFO);
5006 case IPC_STAT:
5007 case SHM_STAT:
5008 perms = SHM__GETATTR | SHM__ASSOCIATE;
5009 break;
5010 case IPC_SET:
5011 perms = SHM__SETATTR;
5012 break;
5013 case SHM_LOCK:
5014 case SHM_UNLOCK:
5015 perms = SHM__LOCK;
5016 break;
5017 case IPC_RMID:
5018 perms = SHM__DESTROY;
5019 break;
5020 default:
5021 return 0;
5022 }
5023
Stephen Smalley6af963f2005-05-01 08:58:39 -07005024 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 return err;
5026}
5027
5028static int selinux_shm_shmat(struct shmid_kernel *shp,
5029 char __user *shmaddr, int shmflg)
5030{
5031 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032
5033 if (shmflg & SHM_RDONLY)
5034 perms = SHM__READ;
5035 else
5036 perms = SHM__READ | SHM__WRITE;
5037
Stephen Smalley6af963f2005-05-01 08:58:39 -07005038 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039}
5040
5041/* Semaphore security operations */
5042static int selinux_sem_alloc_security(struct sem_array *sma)
5043{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005045 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005046 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 int rc;
5048
5049 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5050 if (rc)
5051 return rc;
5052
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 isec = sma->sem_perm.security;
5054
Thomas Liu2bf49692009-07-14 12:14:09 -04005055 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005056 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057
David Howells275bb412008-11-14 10:39:19 +11005058 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 SEM__CREATE, &ad);
5060 if (rc) {
5061 ipc_free_security(&sma->sem_perm);
5062 return rc;
5063 }
5064 return 0;
5065}
5066
5067static void selinux_sem_free_security(struct sem_array *sma)
5068{
5069 ipc_free_security(&sma->sem_perm);
5070}
5071
5072static int selinux_sem_associate(struct sem_array *sma, int semflg)
5073{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005075 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005076 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 isec = sma->sem_perm.security;
5079
Thomas Liu2bf49692009-07-14 12:14:09 -04005080 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 ad.u.ipc_id = sma->sem_perm.key;
5082
David Howells275bb412008-11-14 10:39:19 +11005083 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 SEM__ASSOCIATE, &ad);
5085}
5086
5087/* Note, at this point, sma is locked down */
5088static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5089{
5090 int err;
5091 u32 perms;
5092
Eric Paris828dfe12008-04-17 13:17:49 -04005093 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 case IPC_INFO:
5095 case SEM_INFO:
5096 /* No specific object, just general system-wide information. */
5097 return task_has_system(current, SYSTEM__IPC_INFO);
5098 case GETPID:
5099 case GETNCNT:
5100 case GETZCNT:
5101 perms = SEM__GETATTR;
5102 break;
5103 case GETVAL:
5104 case GETALL:
5105 perms = SEM__READ;
5106 break;
5107 case SETVAL:
5108 case SETALL:
5109 perms = SEM__WRITE;
5110 break;
5111 case IPC_RMID:
5112 perms = SEM__DESTROY;
5113 break;
5114 case IPC_SET:
5115 perms = SEM__SETATTR;
5116 break;
5117 case IPC_STAT:
5118 case SEM_STAT:
5119 perms = SEM__GETATTR | SEM__ASSOCIATE;
5120 break;
5121 default:
5122 return 0;
5123 }
5124
Stephen Smalley6af963f2005-05-01 08:58:39 -07005125 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 return err;
5127}
5128
5129static int selinux_sem_semop(struct sem_array *sma,
5130 struct sembuf *sops, unsigned nsops, int alter)
5131{
5132 u32 perms;
5133
5134 if (alter)
5135 perms = SEM__READ | SEM__WRITE;
5136 else
5137 perms = SEM__READ;
5138
Stephen Smalley6af963f2005-05-01 08:58:39 -07005139 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140}
5141
5142static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5143{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 u32 av = 0;
5145
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 av = 0;
5147 if (flag & S_IRUGO)
5148 av |= IPC__UNIX_READ;
5149 if (flag & S_IWUGO)
5150 av |= IPC__UNIX_WRITE;
5151
5152 if (av == 0)
5153 return 0;
5154
Stephen Smalley6af963f2005-05-01 08:58:39 -07005155 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156}
5157
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005158static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5159{
5160 struct ipc_security_struct *isec = ipcp->security;
5161 *secid = isec->sid;
5162}
5163
Eric Paris828dfe12008-04-17 13:17:49 -04005164static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165{
5166 if (inode)
5167 inode_doinit_with_dentry(inode, dentry);
5168}
5169
5170static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005171 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172{
David Howells275bb412008-11-14 10:39:19 +11005173 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005174 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005176 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177
5178 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005179 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 if (error)
5181 return error;
5182 }
5183
David Howells275bb412008-11-14 10:39:19 +11005184 rcu_read_lock();
5185 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186
5187 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005188 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005190 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005192 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005194 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005195 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005196 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005197 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005198 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 else
David Howells275bb412008-11-14 10:39:19 +11005200 goto invalid;
5201 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202
5203 if (!sid)
5204 return 0;
5205
Al Viro04ff9702007-03-12 16:17:58 +00005206 error = security_sid_to_context(sid, value, &len);
5207 if (error)
5208 return error;
5209 return len;
David Howells275bb412008-11-14 10:39:19 +11005210
5211invalid:
5212 rcu_read_unlock();
5213 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214}
5215
5216static int selinux_setprocattr(struct task_struct *p,
5217 char *name, void *value, size_t size)
5218{
5219 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005220 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005221 struct cred *new;
5222 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 int error;
5224 char *str = value;
5225
5226 if (current != p) {
5227 /* SELinux only allows a process to change its own
5228 security attributes. */
5229 return -EACCES;
5230 }
5231
5232 /*
5233 * Basic control over ability to set these attributes at all.
5234 * current == p, but we'll pass them separately in case the
5235 * above restriction is ever removed.
5236 */
5237 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005238 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005240 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005241 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005242 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005243 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005244 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005246 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 else
5248 error = -EINVAL;
5249 if (error)
5250 return error;
5251
5252 /* Obtain a SID for the context, if one was specified. */
5253 if (size && str[1] && str[1] != '\n') {
5254 if (str[size-1] == '\n') {
5255 str[size-1] = 0;
5256 size--;
5257 }
5258 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005259 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5260 if (!capable(CAP_MAC_ADMIN))
5261 return error;
5262 error = security_context_to_sid_force(value, size,
5263 &sid);
5264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 if (error)
5266 return error;
5267 }
5268
David Howellsd84f4f92008-11-14 10:39:23 +11005269 new = prepare_creds();
5270 if (!new)
5271 return -ENOMEM;
5272
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 /* Permission checking based on the specified context is
5274 performed during the actual operation (execve,
5275 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005276 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 checks and may_create for the file creation checks. The
5278 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005279 tsec = new->security;
5280 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005282 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005284 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005285 error = may_create_key(sid, p);
5286 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005287 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005288 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005289 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005290 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005291 } else if (!strcmp(name, "current")) {
5292 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005294 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005295
David Howellsd84f4f92008-11-14 10:39:23 +11005296 /* Only allow single threaded processes to change context */
5297 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005298 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005299 error = security_bounded_transition(tsec->sid, sid);
5300 if (error)
5301 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303
5304 /* Check permissions for the transition. */
5305 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005306 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005308 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
5310 /* Check for ptracing, and update the task SID if ok.
5311 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005312 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005314 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005315 if (tracer)
5316 ptsid = task_sid(tracer);
5317 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318
David Howellsd84f4f92008-11-14 10:39:23 +11005319 if (tracer) {
5320 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5321 PROCESS__PTRACE, NULL);
5322 if (error)
5323 goto abort_change;
5324 }
5325
5326 tsec->sid = sid;
5327 } else {
5328 error = -EINVAL;
5329 goto abort_change;
5330 }
5331
5332 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005334
5335abort_change:
5336 abort_creds(new);
5337 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338}
5339
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005340static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5341{
5342 return security_sid_to_context(secid, secdata, seclen);
5343}
5344
David Howells7bf570d2008-04-29 20:52:51 +01005345static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005346{
5347 return security_context_to_sid(secdata, seclen, secid);
5348}
5349
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005350static void selinux_release_secctx(char *secdata, u32 seclen)
5351{
Paul Moore088999e2007-08-01 11:12:58 -04005352 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005353}
5354
David P. Quigley1ee65e32009-09-03 14:25:57 -04005355/*
5356 * called with inode->i_mutex locked
5357 */
5358static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5359{
5360 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5361}
5362
5363/*
5364 * called with inode->i_mutex locked
5365 */
5366static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5367{
5368 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5369}
5370
5371static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5372{
5373 int len = 0;
5374 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5375 ctx, true);
5376 if (len < 0)
5377 return len;
5378 *ctxlen = len;
5379 return 0;
5380}
Michael LeMayd7200242006-06-22 14:47:17 -07005381#ifdef CONFIG_KEYS
5382
David Howellsd84f4f92008-11-14 10:39:23 +11005383static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005384 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005385{
David Howellsd84f4f92008-11-14 10:39:23 +11005386 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005387 struct key_security_struct *ksec;
5388
5389 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5390 if (!ksec)
5391 return -ENOMEM;
5392
David Howellsd84f4f92008-11-14 10:39:23 +11005393 tsec = cred->security;
5394 if (tsec->keycreate_sid)
5395 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005396 else
David Howellsd84f4f92008-11-14 10:39:23 +11005397 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005398
David Howells275bb412008-11-14 10:39:19 +11005399 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005400 return 0;
5401}
5402
5403static void selinux_key_free(struct key *k)
5404{
5405 struct key_security_struct *ksec = k->security;
5406
5407 k->security = NULL;
5408 kfree(ksec);
5409}
5410
5411static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005412 const struct cred *cred,
5413 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005414{
5415 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005416 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005417 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005418
5419 /* if no specific permissions are requested, we skip the
5420 permission check. No serious, additional covert channels
5421 appear to be created. */
5422 if (perm == 0)
5423 return 0;
5424
David Howellsd84f4f92008-11-14 10:39:23 +11005425 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005426
5427 key = key_ref_to_ptr(key_ref);
5428 ksec = key->security;
5429
5430 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005431}
5432
David Howells70a5bb72008-04-29 01:01:26 -07005433static int selinux_key_getsecurity(struct key *key, char **_buffer)
5434{
5435 struct key_security_struct *ksec = key->security;
5436 char *context = NULL;
5437 unsigned len;
5438 int rc;
5439
5440 rc = security_sid_to_context(ksec->sid, &context, &len);
5441 if (!rc)
5442 rc = len;
5443 *_buffer = context;
5444 return rc;
5445}
5446
Michael LeMayd7200242006-06-22 14:47:17 -07005447#endif
5448
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005450 .name = "selinux",
5451
Ingo Molnar9e488582009-05-07 19:26:19 +10005452 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005453 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005455 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 .sysctl = selinux_sysctl,
5457 .capable = selinux_capable,
5458 .quotactl = selinux_quotactl,
5459 .quota_on = selinux_quota_on,
5460 .syslog = selinux_syslog,
5461 .vm_enough_memory = selinux_vm_enough_memory,
5462
5463 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005464 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465
David Howellsa6f76f22008-11-14 10:39:24 +11005466 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005467 .bprm_committing_creds = selinux_bprm_committing_creds,
5468 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 .bprm_secureexec = selinux_bprm_secureexec,
5470
5471 .sb_alloc_security = selinux_sb_alloc_security,
5472 .sb_free_security = selinux_sb_free_security,
5473 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005474 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005475 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 .sb_statfs = selinux_sb_statfs,
5477 .sb_mount = selinux_mount,
5478 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005479 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005480 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005481 .sb_parse_opts_str = selinux_parse_opts_str,
5482
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
5484 .inode_alloc_security = selinux_inode_alloc_security,
5485 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005486 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 .inode_unlink = selinux_inode_unlink,
5490 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 .inode_rmdir = selinux_inode_rmdir,
5493 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 .inode_readlink = selinux_inode_readlink,
5496 .inode_follow_link = selinux_inode_follow_link,
5497 .inode_permission = selinux_inode_permission,
5498 .inode_setattr = selinux_inode_setattr,
5499 .inode_getattr = selinux_inode_getattr,
5500 .inode_setxattr = selinux_inode_setxattr,
5501 .inode_post_setxattr = selinux_inode_post_setxattr,
5502 .inode_getxattr = selinux_inode_getxattr,
5503 .inode_listxattr = selinux_inode_listxattr,
5504 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005505 .inode_getsecurity = selinux_inode_getsecurity,
5506 .inode_setsecurity = selinux_inode_setsecurity,
5507 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005508 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
5510 .file_permission = selinux_file_permission,
5511 .file_alloc_security = selinux_file_alloc_security,
5512 .file_free_security = selinux_file_free_security,
5513 .file_ioctl = selinux_file_ioctl,
5514 .file_mmap = selinux_file_mmap,
5515 .file_mprotect = selinux_file_mprotect,
5516 .file_lock = selinux_file_lock,
5517 .file_fcntl = selinux_file_fcntl,
5518 .file_set_fowner = selinux_file_set_fowner,
5519 .file_send_sigiotask = selinux_file_send_sigiotask,
5520 .file_receive = selinux_file_receive,
5521
Eric Paris828dfe12008-04-17 13:17:49 -04005522 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005523
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005525 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005526 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005527 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005528 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005529 .kernel_act_as = selinux_kernel_act_as,
5530 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005531 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 .task_setpgid = selinux_task_setpgid,
5533 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005534 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005535 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005537 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005538 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 .task_setrlimit = selinux_task_setrlimit,
5540 .task_setscheduler = selinux_task_setscheduler,
5541 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005542 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 .task_kill = selinux_task_kill,
5544 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005545 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546
5547 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005548 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549
5550 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5551 .msg_msg_free_security = selinux_msg_msg_free_security,
5552
5553 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5554 .msg_queue_free_security = selinux_msg_queue_free_security,
5555 .msg_queue_associate = selinux_msg_queue_associate,
5556 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5557 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5558 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5559
5560 .shm_alloc_security = selinux_shm_alloc_security,
5561 .shm_free_security = selinux_shm_free_security,
5562 .shm_associate = selinux_shm_associate,
5563 .shm_shmctl = selinux_shm_shmctl,
5564 .shm_shmat = selinux_shm_shmat,
5565
Eric Paris828dfe12008-04-17 13:17:49 -04005566 .sem_alloc_security = selinux_sem_alloc_security,
5567 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 .sem_associate = selinux_sem_associate,
5569 .sem_semctl = selinux_sem_semctl,
5570 .sem_semop = selinux_sem_semop,
5571
Eric Paris828dfe12008-04-17 13:17:49 -04005572 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
Eric Paris828dfe12008-04-17 13:17:49 -04005574 .getprocattr = selinux_getprocattr,
5575 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005577 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005578 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005579 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005580 .inode_notifysecctx = selinux_inode_notifysecctx,
5581 .inode_setsecctx = selinux_inode_setsecctx,
5582 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005583
Eric Paris828dfe12008-04-17 13:17:49 -04005584 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 .unix_may_send = selinux_socket_unix_may_send,
5586
5587 .socket_create = selinux_socket_create,
5588 .socket_post_create = selinux_socket_post_create,
5589 .socket_bind = selinux_socket_bind,
5590 .socket_connect = selinux_socket_connect,
5591 .socket_listen = selinux_socket_listen,
5592 .socket_accept = selinux_socket_accept,
5593 .socket_sendmsg = selinux_socket_sendmsg,
5594 .socket_recvmsg = selinux_socket_recvmsg,
5595 .socket_getsockname = selinux_socket_getsockname,
5596 .socket_getpeername = selinux_socket_getpeername,
5597 .socket_getsockopt = selinux_socket_getsockopt,
5598 .socket_setsockopt = selinux_socket_setsockopt,
5599 .socket_shutdown = selinux_socket_shutdown,
5600 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005601 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5602 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 .sk_alloc_security = selinux_sk_alloc_security,
5604 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005605 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005606 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005607 .sock_graft = selinux_sock_graft,
5608 .inet_conn_request = selinux_inet_conn_request,
5609 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005610 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005611 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005612 .tun_dev_create = selinux_tun_dev_create,
5613 .tun_dev_post_create = selinux_tun_dev_post_create,
5614 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005615
5616#ifdef CONFIG_SECURITY_NETWORK_XFRM
5617 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5618 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5619 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005620 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005621 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5622 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005623 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005624 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005625 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005626 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005628
5629#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005630 .key_alloc = selinux_key_alloc,
5631 .key_free = selinux_key_free,
5632 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005633 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005634#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005635
5636#ifdef CONFIG_AUDIT
5637 .audit_rule_init = selinux_audit_rule_init,
5638 .audit_rule_known = selinux_audit_rule_known,
5639 .audit_rule_match = selinux_audit_rule_match,
5640 .audit_rule_free = selinux_audit_rule_free,
5641#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642};
5643
5644static __init int selinux_init(void)
5645{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005646 if (!security_module_enable(&selinux_ops)) {
5647 selinux_enabled = 0;
5648 return 0;
5649 }
5650
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 if (!selinux_enabled) {
5652 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5653 return 0;
5654 }
5655
5656 printk(KERN_INFO "SELinux: Initializing.\n");
5657
5658 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005659 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660
James Morris7cae7e22006-03-22 00:09:22 -08005661 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5662 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005663 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 avc_init();
5665
James Morris6f0f0fd2008-07-10 17:02:07 +09005666 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005668 panic("SELinux: No initial security operations\n");
5669 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 panic("SELinux: Unable to register with kernel.\n");
5671
Eric Paris828dfe12008-04-17 13:17:49 -04005672 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005673 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005674 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005675 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005676
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 return 0;
5678}
5679
5680void selinux_complete_init(void)
5681{
Eric Parisfadcdb42007-02-22 18:11:31 -05005682 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683
5684 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005685 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005686 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 spin_lock(&sb_security_lock);
5688next_sb:
5689 if (!list_empty(&superblock_security_head)) {
5690 struct superblock_security_struct *sbsec =
5691 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005692 struct superblock_security_struct,
5693 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005697 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 down_read(&sb->s_umount);
5699 if (sb->s_root)
5700 superblock_doinit(sb, NULL);
5701 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005702 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 spin_lock(&sb_security_lock);
5704 list_del_init(&sbsec->list);
5705 goto next_sb;
5706 }
5707 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005708 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709}
5710
5711/* SELinux requires early initialization in order to label
5712 all processes and objects when they are created. */
5713security_initcall(selinux_init);
5714
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005715#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
Paul Mooreeffad8d2008-01-29 08:49:27 -05005717static struct nf_hook_ops selinux_ipv4_ops[] = {
5718 {
5719 .hook = selinux_ipv4_postroute,
5720 .owner = THIS_MODULE,
5721 .pf = PF_INET,
5722 .hooknum = NF_INET_POST_ROUTING,
5723 .priority = NF_IP_PRI_SELINUX_LAST,
5724 },
5725 {
5726 .hook = selinux_ipv4_forward,
5727 .owner = THIS_MODULE,
5728 .pf = PF_INET,
5729 .hooknum = NF_INET_FORWARD,
5730 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005731 },
5732 {
5733 .hook = selinux_ipv4_output,
5734 .owner = THIS_MODULE,
5735 .pf = PF_INET,
5736 .hooknum = NF_INET_LOCAL_OUT,
5737 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739};
5740
5741#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5742
Paul Mooreeffad8d2008-01-29 08:49:27 -05005743static struct nf_hook_ops selinux_ipv6_ops[] = {
5744 {
5745 .hook = selinux_ipv6_postroute,
5746 .owner = THIS_MODULE,
5747 .pf = PF_INET6,
5748 .hooknum = NF_INET_POST_ROUTING,
5749 .priority = NF_IP6_PRI_SELINUX_LAST,
5750 },
5751 {
5752 .hook = selinux_ipv6_forward,
5753 .owner = THIS_MODULE,
5754 .pf = PF_INET6,
5755 .hooknum = NF_INET_FORWARD,
5756 .priority = NF_IP6_PRI_SELINUX_FIRST,
5757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758};
5759
5760#endif /* IPV6 */
5761
5762static int __init selinux_nf_ip_init(void)
5763{
5764 int err = 0;
5765
5766 if (!selinux_enabled)
5767 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005768
5769 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5770
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005771 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5772 if (err)
5773 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
5775#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005776 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5777 if (err)
5778 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005780
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781out:
5782 return err;
5783}
5784
5785__initcall(selinux_nf_ip_init);
5786
5787#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5788static void selinux_nf_ip_exit(void)
5789{
Eric Parisfadcdb42007-02-22 18:11:31 -05005790 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005792 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005794 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795#endif /* IPV6 */
5796}
5797#endif
5798
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005799#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800
5801#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5802#define selinux_nf_ip_exit()
5803#endif
5804
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005805#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806
5807#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005808static int selinux_disabled;
5809
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810int selinux_disable(void)
5811{
5812 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813
5814 if (ss_initialized) {
5815 /* Not permitted after initial policy load. */
5816 return -EINVAL;
5817 }
5818
5819 if (selinux_disabled) {
5820 /* Only do this once. */
5821 return -EINVAL;
5822 }
5823
5824 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5825
5826 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005827 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828
5829 /* Reset security_ops to the secondary module, dummy or capability. */
5830 security_ops = secondary_ops;
5831
Eric Parisaf8ff042009-09-20 21:23:01 -04005832 /* Try to destroy the avc node cache */
5833 avc_disable();
5834
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 /* Unregister netfilter hooks. */
5836 selinux_nf_ip_exit();
5837
5838 /* Unregister selinuxfs. */
5839 exit_sel_fs();
5840
5841 return 0;
5842}
5843#endif