blob: 1a9768a8b644e68cb01cf5d99f953bbdf6819665 [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 Mooreeffad8d2008-01-29 08:49:27 -050016 * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
Eric Paris828dfe12008-04-17 13:17:49 -040017 * 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 unsigned int policydb_loaded_version;
95extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
James Morris4e5ab4c2006-06-09 00:33:33 -070096extern int selinux_compat_net;
James Morris20510f22007-10-16 23:31:32 -070097extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Paul Moored621d352008-01-29 08:43:36 -050099/* SECMARK reference count */
100atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400103int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105static int __init enforcing_setup(char *str)
106{
Eric Parisf5269712008-05-14 11:27:45 -0400107 unsigned long enforcing;
108 if (!strict_strtoul(str, 0, &enforcing))
109 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 return 1;
111}
112__setup("enforcing=", enforcing_setup);
113#endif
114
115#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
116int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
117
118static int __init selinux_enabled_setup(char *str)
119{
Eric Parisf5269712008-05-14 11:27:45 -0400120 unsigned long enabled;
121 if (!strict_strtoul(str, 0, &enabled))
122 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return 1;
124}
125__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400126#else
127int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#endif
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
James Morris6f0f0fd2008-07-10 17:02:07 +0900131/*
132 * Minimal support for a secondary security module,
133 * just to allow the use of the capability module.
134 */
Eric Paris828dfe12008-04-17 13:17:49 -0400135static struct security_operations *secondary_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137/* Lists of inode and superblock security structures initialized
138 before the policy was loaded. */
139static LIST_HEAD(superblock_security_head);
140static DEFINE_SPINLOCK(sb_security_lock);
141
Christoph Lametere18b8902006-12-06 20:33:20 -0800142static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800143
Paul Moored621d352008-01-29 08:43:36 -0500144/**
145 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
146 *
147 * Description:
148 * This function checks the SECMARK reference counter to see if any SECMARK
149 * targets are currently configured, if the reference counter is greater than
150 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
151 * enabled, false (0) if SECMARK is disabled.
152 *
153 */
154static int selinux_secmark_enabled(void)
155{
156 return (atomic_read(&selinux_secmark_refcount) > 0);
157}
158
David Howellsd84f4f92008-11-14 10:39:23 +1100159/*
160 * initialise the security for the init task
161 */
162static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163{
David Howells3b11a1d2008-11-14 10:39:26 +1100164 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct task_security_struct *tsec;
166
James Morris89d155e2005-10-30 14:59:21 -0800167 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100169 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
David Howellsd84f4f92008-11-14 10:39:23 +1100171 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100172 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
David Howells275bb412008-11-14 10:39:19 +1100175/*
David Howells88e67f32008-11-14 10:39:21 +1100176 * get the security ID of a set of credentials
177 */
178static inline u32 cred_sid(const struct cred *cred)
179{
180 const struct task_security_struct *tsec;
181
182 tsec = cred->security;
183 return tsec->sid;
184}
185
186/*
David Howells3b11a1d2008-11-14 10:39:26 +1100187 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100188 */
189static inline u32 task_sid(const struct task_struct *task)
190{
David Howells275bb412008-11-14 10:39:19 +1100191 u32 sid;
192
193 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100194 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100195 rcu_read_unlock();
196 return sid;
197}
198
199/*
David Howells3b11a1d2008-11-14 10:39:26 +1100200 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100201 */
202static inline u32 current_sid(void)
203{
204 const struct task_security_struct *tsec = current_cred()->security;
205
206 return tsec->sid;
207}
208
David Howells88e67f32008-11-14 10:39:21 +1100209/* Allocate and free functions for each kind of security blob. */
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211static int inode_alloc_security(struct inode *inode)
212{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100214 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Josef Bacika02fe132008-04-04 09:35:05 +1100216 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 if (!isec)
218 return -ENOMEM;
219
Eric Paris23970742006-09-25 23:32:01 -0700220 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 isec->inode = inode;
223 isec->sid = SECINITSID_UNLABELED;
224 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100225 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 inode->i_security = isec;
227
228 return 0;
229}
230
231static void inode_free_security(struct inode *inode)
232{
233 struct inode_security_struct *isec = inode->i_security;
234 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 spin_lock(&sbsec->isec_lock);
237 if (!list_empty(&isec->list))
238 list_del_init(&isec->list);
239 spin_unlock(&sbsec->isec_lock);
240
241 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800242 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245static int file_alloc_security(struct file *file)
246{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100248 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800250 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if (!fsec)
252 return -ENOMEM;
253
David Howells275bb412008-11-14 10:39:19 +1100254 fsec->sid = sid;
255 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 file->f_security = fsec;
257
258 return 0;
259}
260
261static void file_free_security(struct file *file)
262{
263 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 file->f_security = NULL;
265 kfree(fsec);
266}
267
268static int superblock_alloc_security(struct super_block *sb)
269{
270 struct superblock_security_struct *sbsec;
271
James Morris89d155e2005-10-30 14:59:21 -0800272 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 if (!sbsec)
274 return -ENOMEM;
275
Eric Parisbc7e9822006-09-25 23:32:02 -0700276 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 INIT_LIST_HEAD(&sbsec->list);
278 INIT_LIST_HEAD(&sbsec->isec_head);
279 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sbsec->sb = sb;
281 sbsec->sid = SECINITSID_UNLABELED;
282 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700283 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 sb->s_security = sbsec;
285
286 return 0;
287}
288
289static void superblock_free_security(struct super_block *sb)
290{
291 struct superblock_security_struct *sbsec = sb->s_security;
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 spin_lock(&sb_security_lock);
294 if (!list_empty(&sbsec->list))
295 list_del_init(&sbsec->list);
296 spin_unlock(&sb_security_lock);
297
298 sb->s_security = NULL;
299 kfree(sbsec);
300}
301
Al Viro7d877f32005-10-21 03:20:43 -0400302static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 struct sk_security_struct *ssec;
305
James Morris89d155e2005-10-30 14:59:21 -0800306 ssec = kzalloc(sizeof(*ssec), priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 if (!ssec)
308 return -ENOMEM;
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 ssec->peer_sid = SECINITSID_UNLABELED;
Venkat Yekkirala892c1412006-08-04 23:08:56 -0700311 ssec->sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 sk->sk_security = ssec;
313
Paul Mooref74af6e2008-02-25 11:40:33 -0500314 selinux_netlbl_sk_security_reset(ssec, family);
Paul Moore99f59ed2006-08-29 17:53:48 -0700315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return 0;
317}
318
319static void sk_free_security(struct sock *sk)
320{
321 struct sk_security_struct *ssec = sk->sk_security;
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 sk->sk_security = NULL;
Paul Moore6c5b3fc2008-10-10 10:16:33 -0400324 selinux_netlbl_sk_security_free(ssec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 kfree(ssec);
326}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328/* The security server must be initialized before
329 any labeling or access decisions can be provided. */
330extern int ss_initialized;
331
332/* The file system's label must be initialized prior to use. */
333
334static char *labeling_behaviors[6] = {
335 "uses xattr",
336 "uses transition SIDs",
337 "uses task SIDs",
338 "uses genfs_contexts",
339 "not configured for labeling",
340 "uses mountpoint labeling",
341};
342
343static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
344
345static inline int inode_doinit(struct inode *inode)
346{
347 return inode_doinit_with_dentry(inode, NULL);
348}
349
350enum {
Eric Paris31e87932007-09-19 17:19:12 -0400351 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 Opt_context = 1,
353 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500354 Opt_defcontext = 3,
355 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500356 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357};
358
Steven Whitehousea447c092008-10-13 10:46:57 +0100359static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400360 {Opt_context, CONTEXT_STR "%s"},
361 {Opt_fscontext, FSCONTEXT_STR "%s"},
362 {Opt_defcontext, DEFCONTEXT_STR "%s"},
363 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500364 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400365 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366};
367
368#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
369
Eric Parisc312feb2006-07-10 04:43:53 -0700370static int may_context_mount_sb_relabel(u32 sid,
371 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100372 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700373{
David Howells275bb412008-11-14 10:39:19 +1100374 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700375 int rc;
376
377 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
378 FILESYSTEM__RELABELFROM, NULL);
379 if (rc)
380 return rc;
381
382 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
383 FILESYSTEM__RELABELTO, NULL);
384 return rc;
385}
386
Eric Paris08089252006-07-10 04:43:55 -0700387static int may_context_mount_inode_relabel(u32 sid,
388 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100389 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700390{
David Howells275bb412008-11-14 10:39:19 +1100391 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700392 int rc;
393 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
394 FILESYSTEM__RELABELFROM, NULL);
395 if (rc)
396 return rc;
397
398 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
399 FILESYSTEM__ASSOCIATE, NULL);
400 return rc;
401}
402
Eric Parisc9180a52007-11-30 13:00:35 -0500403static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 struct superblock_security_struct *sbsec = sb->s_security;
406 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500407 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 int rc = 0;
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
411 /* Make sure that the xattr handler exists and that no
412 error other than -ENODATA is returned by getxattr on
413 the root directory. -ENODATA is ok, as this may be
414 the first boot of the SELinux kernel before we have
415 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500416 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
418 "xattr support\n", sb->s_id, sb->s_type->name);
419 rc = -EOPNOTSUPP;
420 goto out;
421 }
Eric Parisc9180a52007-11-30 13:00:35 -0500422 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 if (rc < 0 && rc != -ENODATA) {
424 if (rc == -EOPNOTSUPP)
425 printk(KERN_WARNING "SELinux: (dev %s, type "
426 "%s) has no security xattr handler\n",
427 sb->s_id, sb->s_type->name);
428 else
429 printk(KERN_WARNING "SELinux: (dev %s, type "
430 "%s) getxattr errno %d\n", sb->s_id,
431 sb->s_type->name, -rc);
432 goto out;
433 }
434 }
435
David P. Quigley11689d42009-01-16 09:22:03 -0500436 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Eric Parisc9180a52007-11-30 13:00:35 -0500438 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500439 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500441 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500442 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sb->s_id, sb->s_type->name,
444 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
David P. Quigley11689d42009-01-16 09:22:03 -0500446 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
447 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
448 sbsec->behavior == SECURITY_FS_USE_NONE ||
449 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
450 sbsec->flags &= ~SE_SBLABELSUPP;
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500453 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 /* Initialize any other inodes associated with the superblock, e.g.
456 inodes created prior to initial policy load or inodes created
457 during get_sb by a pseudo filesystem that directly
458 populates itself. */
459 spin_lock(&sbsec->isec_lock);
460next_inode:
461 if (!list_empty(&sbsec->isec_head)) {
462 struct inode_security_struct *isec =
463 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500464 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 struct inode *inode = isec->inode;
466 spin_unlock(&sbsec->isec_lock);
467 inode = igrab(inode);
468 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500469 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 inode_doinit(inode);
471 iput(inode);
472 }
473 spin_lock(&sbsec->isec_lock);
474 list_del_init(&isec->list);
475 goto next_inode;
476 }
477 spin_unlock(&sbsec->isec_lock);
478out:
Eric Parisc9180a52007-11-30 13:00:35 -0500479 return rc;
480}
481
482/*
483 * This function should allow an FS to ask what it's mount security
484 * options were so it can use those later for submounts, displaying
485 * mount options, or whatever.
486 */
487static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500488 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500489{
490 int rc = 0, i;
491 struct superblock_security_struct *sbsec = sb->s_security;
492 char *context = NULL;
493 u32 len;
494 char tmp;
495
Eric Parise0007522008-03-05 10:31:54 -0500496 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500497
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500498 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500499 return -EINVAL;
500
501 if (!ss_initialized)
502 return -EINVAL;
503
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500504 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500505 /* count the number of mount options for this sb */
506 for (i = 0; i < 8; i++) {
507 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500508 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500509 tmp >>= 1;
510 }
David P. Quigley11689d42009-01-16 09:22:03 -0500511 /* Check if the Label support flag is set */
512 if (sbsec->flags & SE_SBLABELSUPP)
513 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500514
Eric Parise0007522008-03-05 10:31:54 -0500515 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
516 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500517 rc = -ENOMEM;
518 goto out_free;
519 }
520
Eric Parise0007522008-03-05 10:31:54 -0500521 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
522 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500523 rc = -ENOMEM;
524 goto out_free;
525 }
526
527 i = 0;
528 if (sbsec->flags & FSCONTEXT_MNT) {
529 rc = security_sid_to_context(sbsec->sid, &context, &len);
530 if (rc)
531 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500532 opts->mnt_opts[i] = context;
533 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500534 }
535 if (sbsec->flags & CONTEXT_MNT) {
536 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
537 if (rc)
538 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500539 opts->mnt_opts[i] = context;
540 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500541 }
542 if (sbsec->flags & DEFCONTEXT_MNT) {
543 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
544 if (rc)
545 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500546 opts->mnt_opts[i] = context;
547 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500548 }
549 if (sbsec->flags & ROOTCONTEXT_MNT) {
550 struct inode *root = sbsec->sb->s_root->d_inode;
551 struct inode_security_struct *isec = root->i_security;
552
553 rc = security_sid_to_context(isec->sid, &context, &len);
554 if (rc)
555 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500556 opts->mnt_opts[i] = context;
557 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500558 }
David P. Quigley11689d42009-01-16 09:22:03 -0500559 if (sbsec->flags & SE_SBLABELSUPP) {
560 opts->mnt_opts[i] = NULL;
561 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
562 }
Eric Parisc9180a52007-11-30 13:00:35 -0500563
Eric Parise0007522008-03-05 10:31:54 -0500564 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500565
566 return 0;
567
568out_free:
Eric Parise0007522008-03-05 10:31:54 -0500569 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500570 return rc;
571}
572
573static int bad_option(struct superblock_security_struct *sbsec, char flag,
574 u32 old_sid, u32 new_sid)
575{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500576 char mnt_flags = sbsec->flags & SE_MNTMASK;
577
Eric Parisc9180a52007-11-30 13:00:35 -0500578 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500579 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500580 if (!(sbsec->flags & flag) ||
581 (old_sid != new_sid))
582 return 1;
583
584 /* check if we were passed the same options twice,
585 * aka someone passed context=a,context=b
586 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500587 if (!(sbsec->flags & SE_SBINITIALIZED))
588 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500589 return 1;
590 return 0;
591}
Eric Parise0007522008-03-05 10:31:54 -0500592
Eric Parisc9180a52007-11-30 13:00:35 -0500593/*
594 * Allow filesystems with binary mount data to explicitly set mount point
595 * labeling information.
596 */
Eric Parise0007522008-03-05 10:31:54 -0500597static int selinux_set_mnt_opts(struct super_block *sb,
598 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500599{
David Howells275bb412008-11-14 10:39:19 +1100600 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500601 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500602 struct superblock_security_struct *sbsec = sb->s_security;
603 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000604 struct inode *inode = sbsec->sb->s_root->d_inode;
605 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500606 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
607 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500608 char **mount_options = opts->mnt_opts;
609 int *flags = opts->mnt_opts_flags;
610 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500611
612 mutex_lock(&sbsec->lock);
613
614 if (!ss_initialized) {
615 if (!num_opts) {
616 /* Defer initialization until selinux_complete_init,
617 after the initial policy is loaded and the security
618 server is ready to handle calls. */
619 spin_lock(&sb_security_lock);
620 if (list_empty(&sbsec->list))
621 list_add(&sbsec->list, &superblock_security_head);
622 spin_unlock(&sb_security_lock);
623 goto out;
624 }
625 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400626 printk(KERN_WARNING "SELinux: Unable to set superblock options "
627 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500628 goto out;
629 }
630
631 /*
Eric Parise0007522008-03-05 10:31:54 -0500632 * Binary mount data FS will come through this function twice. Once
633 * from an explicit call and once from the generic calls from the vfs.
634 * Since the generic VFS calls will not contain any security mount data
635 * we need to skip the double mount verification.
636 *
637 * This does open a hole in which we will not notice if the first
638 * mount using this sb set explict options and a second mount using
639 * this sb does not set any security options. (The first options
640 * will be used for both mounts)
641 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500642 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500643 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400644 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500645
646 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500647 * parse the mount options, check if they are valid sids.
648 * also check if someone is trying to mount the same sb more
649 * than once with different security options.
650 */
651 for (i = 0; i < num_opts; i++) {
652 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500653
654 if (flags[i] == SE_SBLABELSUPP)
655 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500656 rc = security_context_to_sid(mount_options[i],
657 strlen(mount_options[i]), &sid);
658 if (rc) {
659 printk(KERN_WARNING "SELinux: security_context_to_sid"
660 "(%s) failed for (dev %s, type %s) errno=%d\n",
661 mount_options[i], sb->s_id, name, rc);
662 goto out;
663 }
664 switch (flags[i]) {
665 case FSCONTEXT_MNT:
666 fscontext_sid = sid;
667
668 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
669 fscontext_sid))
670 goto out_double_mount;
671
672 sbsec->flags |= FSCONTEXT_MNT;
673 break;
674 case CONTEXT_MNT:
675 context_sid = sid;
676
677 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
678 context_sid))
679 goto out_double_mount;
680
681 sbsec->flags |= CONTEXT_MNT;
682 break;
683 case ROOTCONTEXT_MNT:
684 rootcontext_sid = sid;
685
686 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
687 rootcontext_sid))
688 goto out_double_mount;
689
690 sbsec->flags |= ROOTCONTEXT_MNT;
691
692 break;
693 case DEFCONTEXT_MNT:
694 defcontext_sid = sid;
695
696 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
697 defcontext_sid))
698 goto out_double_mount;
699
700 sbsec->flags |= DEFCONTEXT_MNT;
701
702 break;
703 default:
704 rc = -EINVAL;
705 goto out;
706 }
707 }
708
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500709 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500710 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500711 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500712 goto out_double_mount;
713 rc = 0;
714 goto out;
715 }
716
James Morris089be432008-07-15 18:32:49 +1000717 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500718 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500719
720 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500721 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500722 if (rc) {
723 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000724 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500725 goto out;
726 }
727
728 /* sets the context of the superblock for the fs being mounted. */
729 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100730 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500731 if (rc)
732 goto out;
733
734 sbsec->sid = fscontext_sid;
735 }
736
737 /*
738 * Switch to using mount point labeling behavior.
739 * sets the label used on all file below the mountpoint, and will set
740 * the superblock context if not already set.
741 */
742 if (context_sid) {
743 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100744 rc = may_context_mount_sb_relabel(context_sid, sbsec,
745 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500746 if (rc)
747 goto out;
748 sbsec->sid = context_sid;
749 } else {
David Howells275bb412008-11-14 10:39:19 +1100750 rc = may_context_mount_inode_relabel(context_sid, sbsec,
751 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500752 if (rc)
753 goto out;
754 }
755 if (!rootcontext_sid)
756 rootcontext_sid = context_sid;
757
758 sbsec->mntpoint_sid = context_sid;
759 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
760 }
761
762 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100763 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
764 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500765 if (rc)
766 goto out;
767
768 root_isec->sid = rootcontext_sid;
769 root_isec->initialized = 1;
770 }
771
772 if (defcontext_sid) {
773 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
774 rc = -EINVAL;
775 printk(KERN_WARNING "SELinux: defcontext option is "
776 "invalid for this filesystem type\n");
777 goto out;
778 }
779
780 if (defcontext_sid != sbsec->def_sid) {
781 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100782 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500783 if (rc)
784 goto out;
785 }
786
787 sbsec->def_sid = defcontext_sid;
788 }
789
790 rc = sb_finish_set_opts(sb);
791out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700792 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500794out_double_mount:
795 rc = -EINVAL;
796 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
797 "security settings for (dev %s, type %s)\n", sb->s_id, name);
798 goto out;
799}
800
801static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
802 struct super_block *newsb)
803{
804 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
805 struct superblock_security_struct *newsbsec = newsb->s_security;
806
807 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
808 int set_context = (oldsbsec->flags & CONTEXT_MNT);
809 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
810
Eric Paris0f5e6422008-04-21 16:24:11 -0400811 /*
812 * if the parent was able to be mounted it clearly had no special lsm
813 * mount options. thus we can safely put this sb on the list and deal
814 * with it later
815 */
816 if (!ss_initialized) {
817 spin_lock(&sb_security_lock);
818 if (list_empty(&newsbsec->list))
819 list_add(&newsbsec->list, &superblock_security_head);
820 spin_unlock(&sb_security_lock);
821 return;
822 }
Eric Parisc9180a52007-11-30 13:00:35 -0500823
Eric Parisc9180a52007-11-30 13:00:35 -0500824 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500825 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500826
Eric Paris5a552612008-04-09 14:08:35 -0400827 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500828 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400829 return;
830
Eric Parisc9180a52007-11-30 13:00:35 -0500831 mutex_lock(&newsbsec->lock);
832
833 newsbsec->flags = oldsbsec->flags;
834
835 newsbsec->sid = oldsbsec->sid;
836 newsbsec->def_sid = oldsbsec->def_sid;
837 newsbsec->behavior = oldsbsec->behavior;
838
839 if (set_context) {
840 u32 sid = oldsbsec->mntpoint_sid;
841
842 if (!set_fscontext)
843 newsbsec->sid = sid;
844 if (!set_rootcontext) {
845 struct inode *newinode = newsb->s_root->d_inode;
846 struct inode_security_struct *newisec = newinode->i_security;
847 newisec->sid = sid;
848 }
849 newsbsec->mntpoint_sid = sid;
850 }
851 if (set_rootcontext) {
852 const struct inode *oldinode = oldsb->s_root->d_inode;
853 const struct inode_security_struct *oldisec = oldinode->i_security;
854 struct inode *newinode = newsb->s_root->d_inode;
855 struct inode_security_struct *newisec = newinode->i_security;
856
857 newisec->sid = oldisec->sid;
858 }
859
860 sb_finish_set_opts(newsb);
861 mutex_unlock(&newsbsec->lock);
862}
863
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200864static int selinux_parse_opts_str(char *options,
865 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500866{
Eric Parise0007522008-03-05 10:31:54 -0500867 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500868 char *context = NULL, *defcontext = NULL;
869 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500870 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500871
Eric Parise0007522008-03-05 10:31:54 -0500872 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500873
874 /* Standard string-based options. */
875 while ((p = strsep(&options, "|")) != NULL) {
876 int token;
877 substring_t args[MAX_OPT_ARGS];
878
879 if (!*p)
880 continue;
881
882 token = match_token(p, tokens, args);
883
884 switch (token) {
885 case Opt_context:
886 if (context || defcontext) {
887 rc = -EINVAL;
888 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
889 goto out_err;
890 }
891 context = match_strdup(&args[0]);
892 if (!context) {
893 rc = -ENOMEM;
894 goto out_err;
895 }
896 break;
897
898 case Opt_fscontext:
899 if (fscontext) {
900 rc = -EINVAL;
901 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
902 goto out_err;
903 }
904 fscontext = match_strdup(&args[0]);
905 if (!fscontext) {
906 rc = -ENOMEM;
907 goto out_err;
908 }
909 break;
910
911 case Opt_rootcontext:
912 if (rootcontext) {
913 rc = -EINVAL;
914 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
915 goto out_err;
916 }
917 rootcontext = match_strdup(&args[0]);
918 if (!rootcontext) {
919 rc = -ENOMEM;
920 goto out_err;
921 }
922 break;
923
924 case Opt_defcontext:
925 if (context || defcontext) {
926 rc = -EINVAL;
927 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
928 goto out_err;
929 }
930 defcontext = match_strdup(&args[0]);
931 if (!defcontext) {
932 rc = -ENOMEM;
933 goto out_err;
934 }
935 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500936 case Opt_labelsupport:
937 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500938 default:
939 rc = -EINVAL;
940 printk(KERN_WARNING "SELinux: unknown mount option\n");
941 goto out_err;
942
943 }
944 }
945
Eric Parise0007522008-03-05 10:31:54 -0500946 rc = -ENOMEM;
947 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
948 if (!opts->mnt_opts)
949 goto out_err;
950
951 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
952 if (!opts->mnt_opts_flags) {
953 kfree(opts->mnt_opts);
954 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500955 }
956
Eric Parise0007522008-03-05 10:31:54 -0500957 if (fscontext) {
958 opts->mnt_opts[num_mnt_opts] = fscontext;
959 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
960 }
961 if (context) {
962 opts->mnt_opts[num_mnt_opts] = context;
963 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
964 }
965 if (rootcontext) {
966 opts->mnt_opts[num_mnt_opts] = rootcontext;
967 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
968 }
969 if (defcontext) {
970 opts->mnt_opts[num_mnt_opts] = defcontext;
971 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
972 }
973
974 opts->num_mnt_opts = num_mnt_opts;
975 return 0;
976
Eric Parisc9180a52007-11-30 13:00:35 -0500977out_err:
978 kfree(context);
979 kfree(defcontext);
980 kfree(fscontext);
981 kfree(rootcontext);
982 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
Eric Parise0007522008-03-05 10:31:54 -0500984/*
985 * string mount options parsing and call set the sbsec
986 */
987static int superblock_doinit(struct super_block *sb, void *data)
988{
989 int rc = 0;
990 char *options = data;
991 struct security_mnt_opts opts;
992
993 security_init_mnt_opts(&opts);
994
995 if (!data)
996 goto out;
997
998 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
999
1000 rc = selinux_parse_opts_str(options, &opts);
1001 if (rc)
1002 goto out_err;
1003
1004out:
1005 rc = selinux_set_mnt_opts(sb, &opts);
1006
1007out_err:
1008 security_free_mnt_opts(&opts);
1009 return rc;
1010}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Adrian Bunk3583a712008-07-22 20:21:23 +03001012static void selinux_write_opts(struct seq_file *m,
1013 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +10001014{
1015 int i;
1016 char *prefix;
1017
1018 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -05001019 char *has_comma;
1020
1021 if (opts->mnt_opts[i])
1022 has_comma = strchr(opts->mnt_opts[i], ',');
1023 else
1024 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +10001025
1026 switch (opts->mnt_opts_flags[i]) {
1027 case CONTEXT_MNT:
1028 prefix = CONTEXT_STR;
1029 break;
1030 case FSCONTEXT_MNT:
1031 prefix = FSCONTEXT_STR;
1032 break;
1033 case ROOTCONTEXT_MNT:
1034 prefix = ROOTCONTEXT_STR;
1035 break;
1036 case DEFCONTEXT_MNT:
1037 prefix = DEFCONTEXT_STR;
1038 break;
David P. Quigley11689d42009-01-16 09:22:03 -05001039 case SE_SBLABELSUPP:
1040 seq_putc(m, ',');
1041 seq_puts(m, LABELSUPP_STR);
1042 continue;
Eric Paris2069f452008-07-04 09:47:13 +10001043 default:
1044 BUG();
1045 };
1046 /* we need a comma before each option */
1047 seq_putc(m, ',');
1048 seq_puts(m, prefix);
1049 if (has_comma)
1050 seq_putc(m, '\"');
1051 seq_puts(m, opts->mnt_opts[i]);
1052 if (has_comma)
1053 seq_putc(m, '\"');
1054 }
1055}
1056
1057static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1058{
1059 struct security_mnt_opts opts;
1060 int rc;
1061
1062 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001063 if (rc) {
1064 /* before policy load we may get EINVAL, don't show anything */
1065 if (rc == -EINVAL)
1066 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001067 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001068 }
Eric Paris2069f452008-07-04 09:47:13 +10001069
1070 selinux_write_opts(m, &opts);
1071
1072 security_free_mnt_opts(&opts);
1073
1074 return rc;
1075}
1076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077static inline u16 inode_mode_to_security_class(umode_t mode)
1078{
1079 switch (mode & S_IFMT) {
1080 case S_IFSOCK:
1081 return SECCLASS_SOCK_FILE;
1082 case S_IFLNK:
1083 return SECCLASS_LNK_FILE;
1084 case S_IFREG:
1085 return SECCLASS_FILE;
1086 case S_IFBLK:
1087 return SECCLASS_BLK_FILE;
1088 case S_IFDIR:
1089 return SECCLASS_DIR;
1090 case S_IFCHR:
1091 return SECCLASS_CHR_FILE;
1092 case S_IFIFO:
1093 return SECCLASS_FIFO_FILE;
1094
1095 }
1096
1097 return SECCLASS_FILE;
1098}
1099
James Morris13402582005-09-30 14:24:34 -04001100static inline int default_protocol_stream(int protocol)
1101{
1102 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1103}
1104
1105static inline int default_protocol_dgram(int protocol)
1106{
1107 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1108}
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1111{
1112 switch (family) {
1113 case PF_UNIX:
1114 switch (type) {
1115 case SOCK_STREAM:
1116 case SOCK_SEQPACKET:
1117 return SECCLASS_UNIX_STREAM_SOCKET;
1118 case SOCK_DGRAM:
1119 return SECCLASS_UNIX_DGRAM_SOCKET;
1120 }
1121 break;
1122 case PF_INET:
1123 case PF_INET6:
1124 switch (type) {
1125 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001126 if (default_protocol_stream(protocol))
1127 return SECCLASS_TCP_SOCKET;
1128 else
1129 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001131 if (default_protocol_dgram(protocol))
1132 return SECCLASS_UDP_SOCKET;
1133 else
1134 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001135 case SOCK_DCCP:
1136 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001137 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 return SECCLASS_RAWIP_SOCKET;
1139 }
1140 break;
1141 case PF_NETLINK:
1142 switch (protocol) {
1143 case NETLINK_ROUTE:
1144 return SECCLASS_NETLINK_ROUTE_SOCKET;
1145 case NETLINK_FIREWALL:
1146 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001147 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1149 case NETLINK_NFLOG:
1150 return SECCLASS_NETLINK_NFLOG_SOCKET;
1151 case NETLINK_XFRM:
1152 return SECCLASS_NETLINK_XFRM_SOCKET;
1153 case NETLINK_SELINUX:
1154 return SECCLASS_NETLINK_SELINUX_SOCKET;
1155 case NETLINK_AUDIT:
1156 return SECCLASS_NETLINK_AUDIT_SOCKET;
1157 case NETLINK_IP6_FW:
1158 return SECCLASS_NETLINK_IP6FW_SOCKET;
1159 case NETLINK_DNRTMSG:
1160 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001161 case NETLINK_KOBJECT_UEVENT:
1162 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 default:
1164 return SECCLASS_NETLINK_SOCKET;
1165 }
1166 case PF_PACKET:
1167 return SECCLASS_PACKET_SOCKET;
1168 case PF_KEY:
1169 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001170 case PF_APPLETALK:
1171 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173
1174 return SECCLASS_SOCKET;
1175}
1176
1177#ifdef CONFIG_PROC_FS
1178static int selinux_proc_get_sid(struct proc_dir_entry *de,
1179 u16 tclass,
1180 u32 *sid)
1181{
1182 int buflen, rc;
1183 char *buffer, *path, *end;
1184
Eric Paris828dfe12008-04-17 13:17:49 -04001185 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 if (!buffer)
1187 return -ENOMEM;
1188
1189 buflen = PAGE_SIZE;
1190 end = buffer+buflen;
1191 *--end = '\0';
1192 buflen--;
1193 path = end-1;
1194 *path = '/';
1195 while (de && de != de->parent) {
1196 buflen -= de->namelen + 1;
1197 if (buflen < 0)
1198 break;
1199 end -= de->namelen;
1200 memcpy(end, de->name, de->namelen);
1201 *--end = '/';
1202 path = end;
1203 de = de->parent;
1204 }
1205 rc = security_genfs_sid("proc", path, tclass, sid);
1206 free_page((unsigned long)buffer);
1207 return rc;
1208}
1209#else
1210static int selinux_proc_get_sid(struct proc_dir_entry *de,
1211 u16 tclass,
1212 u32 *sid)
1213{
1214 return -EINVAL;
1215}
1216#endif
1217
1218/* The inode's security attributes must be initialized before first use. */
1219static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1220{
1221 struct superblock_security_struct *sbsec = NULL;
1222 struct inode_security_struct *isec = inode->i_security;
1223 u32 sid;
1224 struct dentry *dentry;
1225#define INITCONTEXTLEN 255
1226 char *context = NULL;
1227 unsigned len = 0;
1228 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 if (isec->initialized)
1231 goto out;
1232
Eric Paris23970742006-09-25 23:32:01 -07001233 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001235 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001238 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 /* Defer initialization until selinux_complete_init,
1240 after the initial policy is loaded and the security
1241 server is ready to handle calls. */
1242 spin_lock(&sbsec->isec_lock);
1243 if (list_empty(&isec->list))
1244 list_add(&isec->list, &sbsec->isec_head);
1245 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001246 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 }
1248
1249 switch (sbsec->behavior) {
1250 case SECURITY_FS_USE_XATTR:
1251 if (!inode->i_op->getxattr) {
1252 isec->sid = sbsec->def_sid;
1253 break;
1254 }
1255
1256 /* Need a dentry, since the xattr API requires one.
1257 Life would be simpler if we could just pass the inode. */
1258 if (opt_dentry) {
1259 /* Called from d_instantiate or d_splice_alias. */
1260 dentry = dget(opt_dentry);
1261 } else {
1262 /* Called from selinux_complete_init, try to find a dentry. */
1263 dentry = d_find_alias(inode);
1264 }
1265 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001266 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001267 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001269 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
1271
1272 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001273 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (!context) {
1275 rc = -ENOMEM;
1276 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001277 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 }
1279 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1280 context, len);
1281 if (rc == -ERANGE) {
1282 /* Need a larger buffer. Query for the right size. */
1283 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1284 NULL, 0);
1285 if (rc < 0) {
1286 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001287 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 }
1289 kfree(context);
1290 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001291 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (!context) {
1293 rc = -ENOMEM;
1294 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001295 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
1297 rc = inode->i_op->getxattr(dentry,
1298 XATTR_NAME_SELINUX,
1299 context, len);
1300 }
1301 dput(dentry);
1302 if (rc < 0) {
1303 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001304 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001305 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 -rc, inode->i_sb->s_id, inode->i_ino);
1307 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001308 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 }
1310 /* Map ENODATA to the default file SID */
1311 sid = sbsec->def_sid;
1312 rc = 0;
1313 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001314 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001315 sbsec->def_sid,
1316 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001318 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001320 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 inode->i_sb->s_id, inode->i_ino);
1322 kfree(context);
1323 /* Leave with the unlabeled SID */
1324 rc = 0;
1325 break;
1326 }
1327 }
1328 kfree(context);
1329 isec->sid = sid;
1330 break;
1331 case SECURITY_FS_USE_TASK:
1332 isec->sid = isec->task_sid;
1333 break;
1334 case SECURITY_FS_USE_TRANS:
1335 /* Default to the fs SID. */
1336 isec->sid = sbsec->sid;
1337
1338 /* Try to obtain a transition SID. */
1339 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1340 rc = security_transition_sid(isec->task_sid,
1341 sbsec->sid,
1342 isec->sclass,
1343 &sid);
1344 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001345 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 isec->sid = sid;
1347 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001348 case SECURITY_FS_USE_MNTPOINT:
1349 isec->sid = sbsec->mntpoint_sid;
1350 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001352 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 isec->sid = sbsec->sid;
1354
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001355 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 struct proc_inode *proci = PROC_I(inode);
1357 if (proci->pde) {
1358 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1359 rc = selinux_proc_get_sid(proci->pde,
1360 isec->sclass,
1361 &sid);
1362 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001363 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 isec->sid = sid;
1365 }
1366 }
1367 break;
1368 }
1369
1370 isec->initialized = 1;
1371
Eric Paris23970742006-09-25 23:32:01 -07001372out_unlock:
1373 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374out:
1375 if (isec->sclass == SECCLASS_FILE)
1376 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return rc;
1378}
1379
1380/* Convert a Linux signal to an access vector. */
1381static inline u32 signal_to_av(int sig)
1382{
1383 u32 perm = 0;
1384
1385 switch (sig) {
1386 case SIGCHLD:
1387 /* Commonly granted from child to parent. */
1388 perm = PROCESS__SIGCHLD;
1389 break;
1390 case SIGKILL:
1391 /* Cannot be caught or ignored */
1392 perm = PROCESS__SIGKILL;
1393 break;
1394 case SIGSTOP:
1395 /* Cannot be caught or ignored */
1396 perm = PROCESS__SIGSTOP;
1397 break;
1398 default:
1399 /* All other signals. */
1400 perm = PROCESS__SIGNAL;
1401 break;
1402 }
1403
1404 return perm;
1405}
1406
David Howells275bb412008-11-14 10:39:19 +11001407/*
David Howellsd84f4f92008-11-14 10:39:23 +11001408 * Check permission between a pair of credentials
1409 * fork check, ptrace check, etc.
1410 */
1411static int cred_has_perm(const struct cred *actor,
1412 const struct cred *target,
1413 u32 perms)
1414{
1415 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1416
1417 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1418}
1419
1420/*
David Howells88e67f32008-11-14 10:39:21 +11001421 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001422 * fork check, ptrace check, etc.
1423 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001424 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001425 */
1426static int task_has_perm(const struct task_struct *tsk1,
1427 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 u32 perms)
1429{
David Howells275bb412008-11-14 10:39:19 +11001430 const struct task_security_struct *__tsec1, *__tsec2;
1431 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
David Howells275bb412008-11-14 10:39:19 +11001433 rcu_read_lock();
1434 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1435 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1436 rcu_read_unlock();
1437 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438}
1439
David Howells3b11a1d2008-11-14 10:39:26 +11001440/*
1441 * Check permission between current and another task, e.g. signal checks,
1442 * fork check, ptrace check, etc.
1443 * current is the actor and tsk2 is the target
1444 * - this uses current's subjective creds
1445 */
1446static int current_has_perm(const struct task_struct *tsk,
1447 u32 perms)
1448{
1449 u32 sid, tsid;
1450
1451 sid = current_sid();
1452 tsid = task_sid(tsk);
1453 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1454}
1455
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001456#if CAP_LAST_CAP > 63
1457#error Fix SELinux to handle capabilities > 63.
1458#endif
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460/* Check whether a task is allowed to use a capability. */
1461static int task_has_capability(struct task_struct *tsk,
David Howells3699c532009-01-06 22:27:01 +00001462 const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001463 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001466 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001467 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001468 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001469 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001470 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Eric Paris828dfe12008-04-17 13:17:49 -04001472 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 ad.tsk = tsk;
1474 ad.u.cap = cap;
1475
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001476 switch (CAP_TO_INDEX(cap)) {
1477 case 0:
1478 sclass = SECCLASS_CAPABILITY;
1479 break;
1480 case 1:
1481 sclass = SECCLASS_CAPABILITY2;
1482 break;
1483 default:
1484 printk(KERN_ERR
1485 "SELinux: out of range capability %d\n", cap);
1486 BUG();
1487 }
Eric Paris06112162008-11-11 22:02:50 +11001488
David Howells275bb412008-11-14 10:39:19 +11001489 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001490 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001491 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001492 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493}
1494
1495/* Check whether a task is allowed to use a system operation. */
1496static int task_has_system(struct task_struct *tsk,
1497 u32 perms)
1498{
David Howells275bb412008-11-14 10:39:19 +11001499 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
David Howells275bb412008-11-14 10:39:19 +11001501 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 SECCLASS_SYSTEM, perms, NULL);
1503}
1504
1505/* Check whether a task has a particular permission to an inode.
1506 The 'adp' parameter is optional and allows other audit
1507 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001508static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 struct inode *inode,
1510 u32 perms,
1511 struct avc_audit_data *adp)
1512{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 struct inode_security_struct *isec;
1514 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001515 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Eric Paris828dfe12008-04-17 13:17:49 -04001517 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001518 return 0;
1519
David Howells88e67f32008-11-14 10:39:21 +11001520 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 isec = inode->i_security;
1522
1523 if (!adp) {
1524 adp = &ad;
1525 AVC_AUDIT_DATA_INIT(&ad, FS);
1526 ad.u.fs.inode = inode;
1527 }
1528
David Howells275bb412008-11-14 10:39:19 +11001529 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530}
1531
1532/* Same as inode_has_perm, but pass explicit audit data containing
1533 the dentry to help the auditing code to more easily generate the
1534 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001535static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 struct vfsmount *mnt,
1537 struct dentry *dentry,
1538 u32 av)
1539{
1540 struct inode *inode = dentry->d_inode;
1541 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001542
Eric Paris828dfe12008-04-17 13:17:49 -04001543 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001544 ad.u.fs.path.mnt = mnt;
1545 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001546 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547}
1548
1549/* Check whether a task can use an open file descriptor to
1550 access an inode in a given way. Check access to the
1551 descriptor itself, and then use dentry_has_perm to
1552 check a particular permission to the file.
1553 Access to the descriptor is implicitly granted if it
1554 has the same SID as the process. If av is zero, then
1555 access to the file is not checked, e.g. for cases
1556 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001557static int file_has_perm(const struct cred *cred,
1558 struct file *file,
1559 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001562 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001564 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 int rc;
1566
1567 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001568 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
David Howells275bb412008-11-14 10:39:19 +11001570 if (sid != fsec->sid) {
1571 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 SECCLASS_FD,
1573 FD__USE,
1574 &ad);
1575 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001576 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
1578
1579 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001580 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001582 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
David Howells88e67f32008-11-14 10:39:21 +11001584out:
1585 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586}
1587
1588/* Check whether a task can create a file. */
1589static int may_create(struct inode *dir,
1590 struct dentry *dentry,
1591 u16 tclass)
1592{
David Howells275bb412008-11-14 10:39:19 +11001593 const struct cred *cred = current_cred();
1594 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 struct inode_security_struct *dsec;
1596 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001597 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 struct avc_audit_data ad;
1599 int rc;
1600
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 dsec = dir->i_security;
1602 sbsec = dir->i_sb->s_security;
1603
David Howells275bb412008-11-14 10:39:19 +11001604 sid = tsec->sid;
1605 newsid = tsec->create_sid;
1606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001608 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
David Howells275bb412008-11-14 10:39:19 +11001610 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 DIR__ADD_NAME | DIR__SEARCH,
1612 &ad);
1613 if (rc)
1614 return rc;
1615
David Howells275bb412008-11-14 10:39:19 +11001616 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
1617 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (rc)
1619 return rc;
1620 }
1621
David Howells275bb412008-11-14 10:39:19 +11001622 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (rc)
1624 return rc;
1625
1626 return avc_has_perm(newsid, sbsec->sid,
1627 SECCLASS_FILESYSTEM,
1628 FILESYSTEM__ASSOCIATE, &ad);
1629}
1630
Michael LeMay4eb582c2006-06-26 00:24:57 -07001631/* Check whether a task can create a key. */
1632static int may_create_key(u32 ksid,
1633 struct task_struct *ctx)
1634{
David Howells275bb412008-11-14 10:39:19 +11001635 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001636
David Howells275bb412008-11-14 10:39:19 +11001637 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001638}
1639
Eric Paris828dfe12008-04-17 13:17:49 -04001640#define MAY_LINK 0
1641#define MAY_UNLINK 1
1642#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644/* Check whether a task can link, unlink, or rmdir a file/directory. */
1645static int may_link(struct inode *dir,
1646 struct dentry *dentry,
1647 int kind)
1648
1649{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 struct inode_security_struct *dsec, *isec;
1651 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001652 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 u32 av;
1654 int rc;
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 dsec = dir->i_security;
1657 isec = dentry->d_inode->i_security;
1658
1659 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001660 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 av = DIR__SEARCH;
1663 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001664 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 if (rc)
1666 return rc;
1667
1668 switch (kind) {
1669 case MAY_LINK:
1670 av = FILE__LINK;
1671 break;
1672 case MAY_UNLINK:
1673 av = FILE__UNLINK;
1674 break;
1675 case MAY_RMDIR:
1676 av = DIR__RMDIR;
1677 break;
1678 default:
Eric Paris744ba352008-04-17 11:52:44 -04001679 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1680 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 return 0;
1682 }
1683
David Howells275bb412008-11-14 10:39:19 +11001684 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return rc;
1686}
1687
1688static inline int may_rename(struct inode *old_dir,
1689 struct dentry *old_dentry,
1690 struct inode *new_dir,
1691 struct dentry *new_dentry)
1692{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1694 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001695 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 u32 av;
1697 int old_is_dir, new_is_dir;
1698 int rc;
1699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 old_dsec = old_dir->i_security;
1701 old_isec = old_dentry->d_inode->i_security;
1702 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1703 new_dsec = new_dir->i_security;
1704
1705 AVC_AUDIT_DATA_INIT(&ad, FS);
1706
Jan Blunck44707fd2008-02-14 19:38:33 -08001707 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001708 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1710 if (rc)
1711 return rc;
David Howells275bb412008-11-14 10:39:19 +11001712 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 old_isec->sclass, FILE__RENAME, &ad);
1714 if (rc)
1715 return rc;
1716 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001717 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 old_isec->sclass, DIR__REPARENT, &ad);
1719 if (rc)
1720 return rc;
1721 }
1722
Jan Blunck44707fd2008-02-14 19:38:33 -08001723 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 av = DIR__ADD_NAME | DIR__SEARCH;
1725 if (new_dentry->d_inode)
1726 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001727 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (rc)
1729 return rc;
1730 if (new_dentry->d_inode) {
1731 new_isec = new_dentry->d_inode->i_security;
1732 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001733 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 new_isec->sclass,
1735 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1736 if (rc)
1737 return rc;
1738 }
1739
1740 return 0;
1741}
1742
1743/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001744static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 struct super_block *sb,
1746 u32 perms,
1747 struct avc_audit_data *ad)
1748{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001750 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001753 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754}
1755
1756/* Convert a Linux mode and permission mask to an access vector. */
1757static inline u32 file_mask_to_av(int mode, int mask)
1758{
1759 u32 av = 0;
1760
1761 if ((mode & S_IFMT) != S_IFDIR) {
1762 if (mask & MAY_EXEC)
1763 av |= FILE__EXECUTE;
1764 if (mask & MAY_READ)
1765 av |= FILE__READ;
1766
1767 if (mask & MAY_APPEND)
1768 av |= FILE__APPEND;
1769 else if (mask & MAY_WRITE)
1770 av |= FILE__WRITE;
1771
1772 } else {
1773 if (mask & MAY_EXEC)
1774 av |= DIR__SEARCH;
1775 if (mask & MAY_WRITE)
1776 av |= DIR__WRITE;
1777 if (mask & MAY_READ)
1778 av |= DIR__READ;
1779 }
1780
1781 return av;
1782}
1783
1784/* Convert a Linux file to an access vector. */
1785static inline u32 file_to_av(struct file *file)
1786{
1787 u32 av = 0;
1788
1789 if (file->f_mode & FMODE_READ)
1790 av |= FILE__READ;
1791 if (file->f_mode & FMODE_WRITE) {
1792 if (file->f_flags & O_APPEND)
1793 av |= FILE__APPEND;
1794 else
1795 av |= FILE__WRITE;
1796 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001797 if (!av) {
1798 /*
1799 * Special file opened with flags 3 for ioctl-only use.
1800 */
1801 av = FILE__IOCTL;
1802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 return av;
1805}
1806
Eric Paris8b6a5a32008-10-29 17:06:46 -04001807/*
1808 * Convert a file to an access vector and include the correct open
1809 * open permission.
1810 */
1811static inline u32 open_file_to_av(struct file *file)
1812{
1813 u32 av = file_to_av(file);
1814
1815 if (selinux_policycap_openperm) {
1816 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1817 /*
1818 * lnk files and socks do not really have an 'open'
1819 */
1820 if (S_ISREG(mode))
1821 av |= FILE__OPEN;
1822 else if (S_ISCHR(mode))
1823 av |= CHR_FILE__OPEN;
1824 else if (S_ISBLK(mode))
1825 av |= BLK_FILE__OPEN;
1826 else if (S_ISFIFO(mode))
1827 av |= FIFO_FILE__OPEN;
1828 else if (S_ISDIR(mode))
1829 av |= DIR__OPEN;
1830 else
1831 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1832 "unknown mode:%o\n", __func__, mode);
1833 }
1834 return av;
1835}
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837/* Hook functions begin here. */
1838
David Howells5cd9c582008-08-14 11:37:28 +01001839static int selinux_ptrace_may_access(struct task_struct *child,
1840 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 int rc;
1843
David Howells5cd9c582008-08-14 11:37:28 +01001844 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if (rc)
1846 return rc;
1847
Stephen Smalley006ebb42008-05-19 08:32:49 -04001848 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001849 u32 sid = current_sid();
1850 u32 csid = task_sid(child);
1851 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001852 }
1853
David Howells3b11a1d2008-11-14 10:39:26 +11001854 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001855}
1856
1857static int selinux_ptrace_traceme(struct task_struct *parent)
1858{
1859 int rc;
1860
1861 rc = secondary_ops->ptrace_traceme(parent);
1862 if (rc)
1863 return rc;
1864
1865 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001869 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
1871 int error;
1872
David Howells3b11a1d2008-11-14 10:39:26 +11001873 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (error)
1875 return error;
1876
1877 return secondary_ops->capget(target, effective, inheritable, permitted);
1878}
1879
David Howellsd84f4f92008-11-14 10:39:23 +11001880static int selinux_capset(struct cred *new, const struct cred *old,
1881 const kernel_cap_t *effective,
1882 const kernel_cap_t *inheritable,
1883 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
1885 int error;
1886
David Howellsd84f4f92008-11-14 10:39:23 +11001887 error = secondary_ops->capset(new, old,
1888 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (error)
1890 return error;
1891
David Howellsd84f4f92008-11-14 10:39:23 +11001892 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893}
1894
David Howells3699c532009-01-06 22:27:01 +00001895static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
1896 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897{
1898 int rc;
1899
David Howells3699c532009-01-06 22:27:01 +00001900 rc = secondary_ops->capable(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (rc)
1902 return rc;
1903
David Howells3699c532009-01-06 22:27:01 +00001904 return task_has_capability(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905}
1906
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001907static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1908{
1909 int buflen, rc;
1910 char *buffer, *path, *end;
1911
1912 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001913 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001914 if (!buffer)
1915 goto out;
1916
1917 buflen = PAGE_SIZE;
1918 end = buffer+buflen;
1919 *--end = '\0';
1920 buflen--;
1921 path = end-1;
1922 *path = '/';
1923 while (table) {
1924 const char *name = table->procname;
1925 size_t namelen = strlen(name);
1926 buflen -= namelen + 1;
1927 if (buflen < 0)
1928 goto out_free;
1929 end -= namelen;
1930 memcpy(end, name, namelen);
1931 *--end = '/';
1932 path = end;
1933 table = table->parent;
1934 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001935 buflen -= 4;
1936 if (buflen < 0)
1937 goto out_free;
1938 end -= 4;
1939 memcpy(end, "/sys", 4);
1940 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001941 rc = security_genfs_sid("proc", path, tclass, sid);
1942out_free:
1943 free_page((unsigned long)buffer);
1944out:
1945 return rc;
1946}
1947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948static int selinux_sysctl(ctl_table *table, int op)
1949{
1950 int error = 0;
1951 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001952 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 int rc;
1954
1955 rc = secondary_ops->sysctl(table, op);
1956 if (rc)
1957 return rc;
1958
David Howells275bb412008-11-14 10:39:19 +11001959 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001961 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1962 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
1964 /* Default to the well-defined sysctl SID. */
1965 tsid = SECINITSID_SYSCTL;
1966 }
1967
1968 /* The op values are "defined" in sysctl.c, thereby creating
1969 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001970 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11001971 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 SECCLASS_DIR, DIR__SEARCH, NULL);
1973 } else {
1974 av = 0;
1975 if (op & 004)
1976 av |= FILE__READ;
1977 if (op & 002)
1978 av |= FILE__WRITE;
1979 if (av)
David Howells275bb412008-11-14 10:39:19 +11001980 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984 return error;
1985}
1986
1987static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1988{
David Howells88e67f32008-11-14 10:39:21 +11001989 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 int rc = 0;
1991
1992 if (!sb)
1993 return 0;
1994
1995 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001996 case Q_SYNC:
1997 case Q_QUOTAON:
1998 case Q_QUOTAOFF:
1999 case Q_SETINFO:
2000 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11002001 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002002 break;
2003 case Q_GETFMT:
2004 case Q_GETINFO:
2005 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11002006 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002007 break;
2008 default:
2009 rc = 0; /* let the kernel handle invalid cmds */
2010 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 }
2012 return rc;
2013}
2014
2015static int selinux_quota_on(struct dentry *dentry)
2016{
David Howells88e67f32008-11-14 10:39:21 +11002017 const struct cred *cred = current_cred();
2018
2019 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020}
2021
2022static int selinux_syslog(int type)
2023{
2024 int rc;
2025
2026 rc = secondary_ops->syslog(type);
2027 if (rc)
2028 return rc;
2029
2030 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04002031 case 3: /* Read last kernel messages */
2032 case 10: /* Return size of the log buffer */
2033 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
2034 break;
2035 case 6: /* Disable logging to console */
2036 case 7: /* Enable logging to console */
2037 case 8: /* Set level of messages printed to console */
2038 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
2039 break;
2040 case 0: /* Close log */
2041 case 1: /* Open log */
2042 case 2: /* Read from log */
2043 case 4: /* Read/clear last kernel messages */
2044 case 5: /* Clear ring buffer */
2045 default:
2046 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2047 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 }
2049 return rc;
2050}
2051
2052/*
2053 * Check that a process has enough memory to allocate a new virtual
2054 * mapping. 0 means there is enough memory for the allocation to
2055 * succeed and -ENOMEM implies there is not.
2056 *
2057 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
2058 * if the capability is granted, but __vm_enough_memory requires 1 if
2059 * the capability is granted.
2060 *
2061 * Do not audit the selinux permission check, as this is applied to all
2062 * processes that allocate mappings.
2063 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002064static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
2066 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
David Howells3699c532009-01-06 22:27:01 +00002068 rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
2069 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (rc == 0)
2071 cap_sys_admin = 1;
2072
Alan Cox34b4e4a2007-08-22 14:01:28 -07002073 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074}
2075
2076/* binprm security operations */
2077
David Howellsa6f76f22008-11-14 10:39:24 +11002078static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
David Howellsa6f76f22008-11-14 10:39:24 +11002080 const struct task_security_struct *old_tsec;
2081 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 struct avc_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11002084 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 int rc;
2086
David Howellsa6f76f22008-11-14 10:39:24 +11002087 rc = secondary_ops->bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 if (rc)
2089 return rc;
2090
David Howellsa6f76f22008-11-14 10:39:24 +11002091 /* SELinux context only depends on initial program or script and not
2092 * the script interpreter */
2093 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 return 0;
2095
David Howellsa6f76f22008-11-14 10:39:24 +11002096 old_tsec = current_security();
2097 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 isec = inode->i_security;
2099
2100 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002101 new_tsec->sid = old_tsec->sid;
2102 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Michael LeMay28eba5b2006-06-27 02:53:42 -07002104 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002105 new_tsec->create_sid = 0;
2106 new_tsec->keycreate_sid = 0;
2107 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
David Howellsa6f76f22008-11-14 10:39:24 +11002109 if (old_tsec->exec_sid) {
2110 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002112 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 } else {
2114 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002115 rc = security_transition_sid(old_tsec->sid, isec->sid,
2116 SECCLASS_PROCESS, &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 if (rc)
2118 return rc;
2119 }
2120
2121 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002122 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Josef Sipek3d5ff522006-12-08 02:37:38 -08002124 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002125 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
David Howellsa6f76f22008-11-14 10:39:24 +11002127 if (new_tsec->sid == old_tsec->sid) {
2128 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2130 if (rc)
2131 return rc;
2132 } else {
2133 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002134 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2136 if (rc)
2137 return rc;
2138
David Howellsa6f76f22008-11-14 10:39:24 +11002139 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2141 if (rc)
2142 return rc;
2143
David Howellsa6f76f22008-11-14 10:39:24 +11002144 /* Check for shared state */
2145 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2146 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2147 SECCLASS_PROCESS, PROCESS__SHARE,
2148 NULL);
2149 if (rc)
2150 return -EPERM;
2151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
David Howellsa6f76f22008-11-14 10:39:24 +11002153 /* Make sure that anyone attempting to ptrace over a task that
2154 * changes its SID has the appropriate permit */
2155 if (bprm->unsafe &
2156 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2157 struct task_struct *tracer;
2158 struct task_security_struct *sec;
2159 u32 ptsid = 0;
2160
2161 rcu_read_lock();
2162 tracer = tracehook_tracer_task(current);
2163 if (likely(tracer != NULL)) {
2164 sec = __task_cred(tracer)->security;
2165 ptsid = sec->sid;
2166 }
2167 rcu_read_unlock();
2168
2169 if (ptsid != 0) {
2170 rc = avc_has_perm(ptsid, new_tsec->sid,
2171 SECCLASS_PROCESS,
2172 PROCESS__PTRACE, NULL);
2173 if (rc)
2174 return -EPERM;
2175 }
2176 }
2177
2178 /* Clear any possibly unsafe personality bits on exec: */
2179 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 }
2181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return 0;
2183}
2184
Eric Paris828dfe12008-04-17 13:17:49 -04002185static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
2187 return secondary_ops->bprm_check_security(bprm);
2188}
2189
Eric Paris828dfe12008-04-17 13:17:49 -04002190static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191{
David Howells275bb412008-11-14 10:39:19 +11002192 const struct cred *cred = current_cred();
2193 const struct task_security_struct *tsec = cred->security;
2194 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 int atsecure = 0;
2196
David Howells275bb412008-11-14 10:39:19 +11002197 sid = tsec->sid;
2198 osid = tsec->osid;
2199
2200 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 /* Enable secure mode for SIDs transitions unless
2202 the noatsecure permission is granted between
2203 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002204 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002205 SECCLASS_PROCESS,
2206 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 }
2208
2209 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2210}
2211
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212extern struct vfsmount *selinuxfs_mount;
2213extern struct dentry *selinux_null;
2214
2215/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002216static inline void flush_unauthorized_files(const struct cred *cred,
2217 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218{
2219 struct avc_audit_data ad;
2220 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002221 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002222 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002224 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002226 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 if (tty) {
2228 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002229 if (!list_empty(&tty->tty_files)) {
2230 struct inode *inode;
2231
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 /* Revalidate access to controlling tty.
2233 Use inode_has_perm on the tty inode directly rather
2234 than using file_has_perm, as this particular open
2235 file may belong to another process and we are only
2236 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002237 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2238 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002239 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002241 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 }
2243 }
2244 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002245 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002247 /* Reset controlling tty. */
2248 if (drop_tty)
2249 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
2251 /* Revalidate access to inherited open files. */
2252
Eric Paris828dfe12008-04-17 13:17:49 -04002253 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 spin_lock(&files->file_lock);
2256 for (;;) {
2257 unsigned long set, i;
2258 int fd;
2259
2260 j++;
2261 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002262 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002263 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002265 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 if (!set)
2267 continue;
2268 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002269 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if (set & 1) {
2271 file = fget(i);
2272 if (!file)
2273 continue;
David Howells88e67f32008-11-14 10:39:21 +11002274 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 file,
2276 file_to_av(file))) {
2277 sys_close(i);
2278 fd = get_unused_fd();
2279 if (fd != i) {
2280 if (fd >= 0)
2281 put_unused_fd(fd);
2282 fput(file);
2283 continue;
2284 }
2285 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002286 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 } else {
David Howells745ca242008-11-14 10:39:22 +11002288 devnull = dentry_open(
2289 dget(selinux_null),
2290 mntget(selinuxfs_mount),
2291 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002292 if (IS_ERR(devnull)) {
2293 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 put_unused_fd(fd);
2295 fput(file);
2296 continue;
2297 }
2298 }
2299 fd_install(fd, devnull);
2300 }
2301 fput(file);
2302 }
2303 }
2304 spin_lock(&files->file_lock);
2305
2306 }
2307 spin_unlock(&files->file_lock);
2308}
2309
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310/*
David Howellsa6f76f22008-11-14 10:39:24 +11002311 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 */
David Howellsa6f76f22008-11-14 10:39:24 +11002313static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314{
David Howellsa6f76f22008-11-14 10:39:24 +11002315 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 int rc, i;
2318
David Howellsa6f76f22008-11-14 10:39:24 +11002319 secondary_ops->bprm_committing_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
David Howellsa6f76f22008-11-14 10:39:24 +11002321 new_tsec = bprm->cred->security;
2322 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 return;
2324
2325 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002326 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
David Howellsa6f76f22008-11-14 10:39:24 +11002328 /* Always clear parent death signal on SID transitions. */
2329 current->pdeath_signal = 0;
2330
2331 /* Check whether the new SID can inherit resource limits from the old
2332 * SID. If not, reset all soft limits to the lower of the current
2333 * task's hard limit and the init task's soft limit.
2334 *
2335 * Note that the setting of hard limits (even to lower them) can be
2336 * controlled by the setrlimit check. The inclusion of the init task's
2337 * soft limit into the computation is to avoid resetting soft limits
2338 * higher than the default soft limit for cases where the default is
2339 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2340 */
2341 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2342 PROCESS__RLIMITINH, NULL);
2343 if (rc) {
2344 for (i = 0; i < RLIM_NLIMITS; i++) {
2345 rlim = current->signal->rlim + i;
2346 initrlim = init_task.signal->rlim + i;
2347 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2348 }
2349 update_rlimit_cpu(rlim->rlim_cur);
2350 }
2351}
2352
2353/*
2354 * Clean up the process immediately after the installation of new credentials
2355 * due to exec
2356 */
2357static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2358{
2359 const struct task_security_struct *tsec = current_security();
2360 struct itimerval itimer;
2361 struct sighand_struct *psig;
2362 u32 osid, sid;
2363 int rc, i;
2364 unsigned long flags;
2365
2366 secondary_ops->bprm_committed_creds(bprm);
2367
2368 osid = tsec->osid;
2369 sid = tsec->sid;
2370
2371 if (sid == osid)
2372 return;
2373
2374 /* Check whether the new SID can inherit signal state from the old SID.
2375 * If not, clear itimers to avoid subsequent signal generation and
2376 * flush and unblock signals.
2377 *
2378 * This must occur _after_ the task SID has been updated so that any
2379 * kill done after the flush will be checked against the new SID.
2380 */
2381 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 if (rc) {
2383 memset(&itimer, 0, sizeof itimer);
2384 for (i = 0; i < 3; i++)
2385 do_setitimer(i, &itimer, NULL);
2386 flush_signals(current);
2387 spin_lock_irq(&current->sighand->siglock);
2388 flush_signal_handlers(current, 1);
2389 sigemptyset(&current->blocked);
2390 recalc_sigpending();
2391 spin_unlock_irq(&current->sighand->siglock);
2392 }
2393
David Howellsa6f76f22008-11-14 10:39:24 +11002394 /* Wake up the parent if it is waiting so that it can recheck
2395 * wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002396 read_lock_irq(&tasklist_lock);
2397 psig = current->parent->sighand;
2398 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002400 spin_unlock_irqrestore(&psig->siglock, flags);
2401 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402}
2403
2404/* superblock security operations */
2405
2406static int selinux_sb_alloc_security(struct super_block *sb)
2407{
2408 return superblock_alloc_security(sb);
2409}
2410
2411static void selinux_sb_free_security(struct super_block *sb)
2412{
2413 superblock_free_security(sb);
2414}
2415
2416static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2417{
2418 if (plen > olen)
2419 return 0;
2420
2421 return !memcmp(prefix, option, plen);
2422}
2423
2424static inline int selinux_option(char *option, int len)
2425{
Eric Paris832cbd92008-04-01 13:24:09 -04002426 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2427 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2428 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002429 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2430 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431}
2432
2433static inline void take_option(char **to, char *from, int *first, int len)
2434{
2435 if (!*first) {
2436 **to = ',';
2437 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002438 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 *first = 0;
2440 memcpy(*to, from, len);
2441 *to += len;
2442}
2443
Eric Paris828dfe12008-04-17 13:17:49 -04002444static inline void take_selinux_option(char **to, char *from, int *first,
2445 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002446{
2447 int current_size = 0;
2448
2449 if (!*first) {
2450 **to = '|';
2451 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002452 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002453 *first = 0;
2454
2455 while (current_size < len) {
2456 if (*from != '"') {
2457 **to = *from;
2458 *to += 1;
2459 }
2460 from += 1;
2461 current_size += 1;
2462 }
2463}
2464
Eric Parise0007522008-03-05 10:31:54 -05002465static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466{
2467 int fnosec, fsec, rc = 0;
2468 char *in_save, *in_curr, *in_end;
2469 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002470 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
2472 in_curr = orig;
2473 sec_curr = copy;
2474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2476 if (!nosec) {
2477 rc = -ENOMEM;
2478 goto out;
2479 }
2480
2481 nosec_save = nosec;
2482 fnosec = fsec = 1;
2483 in_save = in_end = orig;
2484
2485 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002486 if (*in_end == '"')
2487 open_quote = !open_quote;
2488 if ((*in_end == ',' && open_quote == 0) ||
2489 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 int len = in_end - in_curr;
2491
2492 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002493 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 else
2495 take_option(&nosec, in_curr, &fnosec, len);
2496
2497 in_curr = in_end + 1;
2498 }
2499 } while (*in_end++);
2500
Eric Paris6931dfc2005-06-30 02:58:51 -07002501 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002502 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503out:
2504 return rc;
2505}
2506
James Morris12204e22008-12-19 10:44:42 +11002507static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508{
David Howells88e67f32008-11-14 10:39:21 +11002509 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 struct avc_audit_data ad;
2511 int rc;
2512
2513 rc = superblock_doinit(sb, data);
2514 if (rc)
2515 return rc;
2516
James Morris74192242008-12-19 11:41:10 +11002517 /* Allow all mounts performed by the kernel */
2518 if (flags & MS_KERNMOUNT)
2519 return 0;
2520
Eric Paris828dfe12008-04-17 13:17:49 -04002521 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002522 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002523 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524}
2525
David Howells726c3342006-06-23 02:02:58 -07002526static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527{
David Howells88e67f32008-11-14 10:39:21 +11002528 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 struct avc_audit_data ad;
2530
Eric Paris828dfe12008-04-17 13:17:49 -04002531 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002532 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002533 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534}
2535
Eric Paris828dfe12008-04-17 13:17:49 -04002536static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002537 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002538 char *type,
2539 unsigned long flags,
2540 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541{
David Howells88e67f32008-11-14 10:39:21 +11002542 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 int rc;
2544
Al Virob5266eb2008-03-22 17:48:24 -04002545 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 if (rc)
2547 return rc;
2548
2549 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002550 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002551 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 else
David Howells88e67f32008-11-14 10:39:21 +11002553 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002554 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555}
2556
2557static int selinux_umount(struct vfsmount *mnt, int flags)
2558{
David Howells88e67f32008-11-14 10:39:21 +11002559 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 int rc;
2561
2562 rc = secondary_ops->sb_umount(mnt, flags);
2563 if (rc)
2564 return rc;
2565
David Howells88e67f32008-11-14 10:39:21 +11002566 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002567 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568}
2569
2570/* inode security operations */
2571
2572static int selinux_inode_alloc_security(struct inode *inode)
2573{
2574 return inode_alloc_security(inode);
2575}
2576
2577static void selinux_inode_free_security(struct inode *inode)
2578{
2579 inode_free_security(inode);
2580}
2581
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002582static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2583 char **name, void **value,
2584 size_t *len)
2585{
David Howells275bb412008-11-14 10:39:19 +11002586 const struct cred *cred = current_cred();
2587 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002588 struct inode_security_struct *dsec;
2589 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002590 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002591 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002592 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002593
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002594 dsec = dir->i_security;
2595 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002596
David Howells275bb412008-11-14 10:39:19 +11002597 sid = tsec->sid;
2598 newsid = tsec->create_sid;
2599
2600 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
2601 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002602 inode_mode_to_security_class(inode->i_mode),
2603 &newsid);
2604 if (rc) {
2605 printk(KERN_WARNING "%s: "
2606 "security_transition_sid failed, rc=%d (dev=%s "
2607 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002608 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002609 -rc, inode->i_sb->s_id, inode->i_ino);
2610 return rc;
2611 }
2612 }
2613
Eric Paris296fddf2006-09-25 23:32:00 -07002614 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002615 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002616 struct inode_security_struct *isec = inode->i_security;
2617 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2618 isec->sid = newsid;
2619 isec->initialized = 1;
2620 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002621
Stephen Smalley8aad3872006-03-22 00:09:13 -08002622 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002623 return -EOPNOTSUPP;
2624
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002625 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002626 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002627 if (!namep)
2628 return -ENOMEM;
2629 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002630 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002631
2632 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002633 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002634 if (rc) {
2635 kfree(namep);
2636 return rc;
2637 }
2638 *value = context;
2639 *len = clen;
2640 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002641
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002642 return 0;
2643}
2644
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2646{
2647 return may_create(dir, dentry, SECCLASS_FILE);
2648}
2649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2651{
2652 int rc;
2653
Eric Paris828dfe12008-04-17 13:17:49 -04002654 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 if (rc)
2656 return rc;
2657 return may_link(dir, old_dentry, MAY_LINK);
2658}
2659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2661{
2662 int rc;
2663
2664 rc = secondary_ops->inode_unlink(dir, dentry);
2665 if (rc)
2666 return rc;
2667 return may_link(dir, dentry, MAY_UNLINK);
2668}
2669
2670static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2671{
2672 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2673}
2674
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2676{
2677 return may_create(dir, dentry, SECCLASS_DIR);
2678}
2679
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2681{
2682 return may_link(dir, dentry, MAY_RMDIR);
2683}
2684
2685static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2686{
2687 int rc;
2688
2689 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2690 if (rc)
2691 return rc;
2692
2693 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2694}
2695
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002697 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698{
2699 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2700}
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702static int selinux_inode_readlink(struct dentry *dentry)
2703{
David Howells88e67f32008-11-14 10:39:21 +11002704 const struct cred *cred = current_cred();
2705
2706 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707}
2708
2709static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2710{
David Howells88e67f32008-11-14 10:39:21 +11002711 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 int rc;
2713
Eric Paris828dfe12008-04-17 13:17:49 -04002714 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 if (rc)
2716 return rc;
David Howells88e67f32008-11-14 10:39:21 +11002717 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718}
2719
Al Virob77b0642008-07-17 09:37:02 -04002720static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721{
David Howells88e67f32008-11-14 10:39:21 +11002722 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 int rc;
2724
Al Virob77b0642008-07-17 09:37:02 -04002725 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 if (rc)
2727 return rc;
2728
2729 if (!mask) {
2730 /* No permission to check. Existence test. */
2731 return 0;
2732 }
2733
David Howells88e67f32008-11-14 10:39:21 +11002734 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002735 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736}
2737
2738static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2739{
David Howells88e67f32008-11-14 10:39:21 +11002740 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 int rc;
2742
2743 rc = secondary_ops->inode_setattr(dentry, iattr);
2744 if (rc)
2745 return rc;
2746
2747 if (iattr->ia_valid & ATTR_FORCE)
2748 return 0;
2749
2750 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2751 ATTR_ATIME_SET | ATTR_MTIME_SET))
David Howells88e67f32008-11-14 10:39:21 +11002752 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
David Howells88e67f32008-11-14 10:39:21 +11002754 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755}
2756
2757static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2758{
David Howells88e67f32008-11-14 10:39:21 +11002759 const struct cred *cred = current_cred();
2760
2761 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762}
2763
David Howells8f0cfa52008-04-29 00:59:41 -07002764static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002765{
David Howells88e67f32008-11-14 10:39:21 +11002766 const struct cred *cred = current_cred();
2767
Serge E. Hallynb5376772007-10-16 23:31:36 -07002768 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2769 sizeof XATTR_SECURITY_PREFIX - 1)) {
2770 if (!strcmp(name, XATTR_NAME_CAPS)) {
2771 if (!capable(CAP_SETFCAP))
2772 return -EPERM;
2773 } else if (!capable(CAP_SYS_ADMIN)) {
2774 /* A different attribute in the security namespace.
2775 Restrict to administrator. */
2776 return -EPERM;
2777 }
2778 }
2779
2780 /* Not an attribute we recognize, so just check the
2781 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002782 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002783}
2784
David Howells8f0cfa52008-04-29 00:59:41 -07002785static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2786 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 struct inode *inode = dentry->d_inode;
2789 struct inode_security_struct *isec = inode->i_security;
2790 struct superblock_security_struct *sbsec;
2791 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002792 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 int rc = 0;
2794
Serge E. Hallynb5376772007-10-16 23:31:36 -07002795 if (strcmp(name, XATTR_NAME_SELINUX))
2796 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
2798 sbsec = inode->i_sb->s_security;
2799 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2800 return -EOPNOTSUPP;
2801
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302802 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 return -EPERM;
2804
Eric Paris828dfe12008-04-17 13:17:49 -04002805 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002806 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
David Howells275bb412008-11-14 10:39:19 +11002808 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 FILE__RELABELFROM, &ad);
2810 if (rc)
2811 return rc;
2812
2813 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002814 if (rc == -EINVAL) {
2815 if (!capable(CAP_MAC_ADMIN))
2816 return rc;
2817 rc = security_context_to_sid_force(value, size, &newsid);
2818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 if (rc)
2820 return rc;
2821
David Howells275bb412008-11-14 10:39:19 +11002822 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 FILE__RELABELTO, &ad);
2824 if (rc)
2825 return rc;
2826
David Howells275bb412008-11-14 10:39:19 +11002827 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002828 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 if (rc)
2830 return rc;
2831
2832 return avc_has_perm(newsid,
2833 sbsec->sid,
2834 SECCLASS_FILESYSTEM,
2835 FILESYSTEM__ASSOCIATE,
2836 &ad);
2837}
2838
David Howells8f0cfa52008-04-29 00:59:41 -07002839static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002840 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002841 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842{
2843 struct inode *inode = dentry->d_inode;
2844 struct inode_security_struct *isec = inode->i_security;
2845 u32 newsid;
2846 int rc;
2847
2848 if (strcmp(name, XATTR_NAME_SELINUX)) {
2849 /* Not an attribute we recognize, so nothing to do. */
2850 return;
2851 }
2852
Stephen Smalley12b29f32008-05-07 13:03:20 -04002853 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002855 printk(KERN_ERR "SELinux: unable to map context to SID"
2856 "for (%s, %lu), rc=%d\n",
2857 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 return;
2859 }
2860
2861 isec->sid = newsid;
2862 return;
2863}
2864
David Howells8f0cfa52008-04-29 00:59:41 -07002865static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866{
David Howells88e67f32008-11-14 10:39:21 +11002867 const struct cred *cred = current_cred();
2868
2869 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870}
2871
Eric Paris828dfe12008-04-17 13:17:49 -04002872static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873{
David Howells88e67f32008-11-14 10:39:21 +11002874 const struct cred *cred = current_cred();
2875
2876 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877}
2878
David Howells8f0cfa52008-04-29 00:59:41 -07002879static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002881 if (strcmp(name, XATTR_NAME_SELINUX))
2882 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 /* No one is allowed to remove a SELinux security label.
2885 You can change the label, but all data must be labeled. */
2886 return -EACCES;
2887}
2888
James Morrisd381d8a2005-10-30 14:59:22 -08002889/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002890 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002891 *
2892 * Permission check is handled by selinux_inode_getxattr hook.
2893 */
David P. Quigley42492592008-02-04 22:29:39 -08002894static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895{
David P. Quigley42492592008-02-04 22:29:39 -08002896 u32 size;
2897 int error;
2898 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002901 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2902 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002904 /*
2905 * If the caller has CAP_MAC_ADMIN, then get the raw context
2906 * value even if it is not defined by current policy; otherwise,
2907 * use the in-core value under current policy.
2908 * Use the non-auditing forms of the permission checks since
2909 * getxattr may be called by unprivileged processes commonly
2910 * and lack of permission just means that we fall back to the
2911 * in-core context value, not a denial.
2912 */
David Howells3699c532009-01-06 22:27:01 +00002913 error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
2914 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002915 if (!error)
2916 error = security_sid_to_context_force(isec->sid, &context,
2917 &size);
2918 else
2919 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002920 if (error)
2921 return error;
2922 error = size;
2923 if (alloc) {
2924 *buffer = context;
2925 goto out_nofree;
2926 }
2927 kfree(context);
2928out_nofree:
2929 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930}
2931
2932static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002933 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934{
2935 struct inode_security_struct *isec = inode->i_security;
2936 u32 newsid;
2937 int rc;
2938
2939 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2940 return -EOPNOTSUPP;
2941
2942 if (!value || !size)
2943 return -EACCES;
2944
Eric Paris828dfe12008-04-17 13:17:49 -04002945 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 if (rc)
2947 return rc;
2948
2949 isec->sid = newsid;
2950 return 0;
2951}
2952
2953static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2954{
2955 const int len = sizeof(XATTR_NAME_SELINUX);
2956 if (buffer && len <= buffer_size)
2957 memcpy(buffer, XATTR_NAME_SELINUX, len);
2958 return len;
2959}
2960
Serge E. Hallynb5376772007-10-16 23:31:36 -07002961static int selinux_inode_need_killpriv(struct dentry *dentry)
2962{
2963 return secondary_ops->inode_need_killpriv(dentry);
2964}
2965
2966static int selinux_inode_killpriv(struct dentry *dentry)
2967{
2968 return secondary_ops->inode_killpriv(dentry);
2969}
2970
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02002971static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2972{
2973 struct inode_security_struct *isec = inode->i_security;
2974 *secid = isec->sid;
2975}
2976
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977/* file security operations */
2978
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002979static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980{
David Howells88e67f32008-11-14 10:39:21 +11002981 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002982 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002983 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
2985 if (!mask) {
2986 /* No permission to check. Existence test. */
2987 return 0;
2988 }
2989
2990 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2991 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2992 mask |= MAY_APPEND;
2993
David Howells88e67f32008-11-14 10:39:21 +11002994 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002995 file_mask_to_av(inode->i_mode, mask));
2996 if (rc)
2997 return rc;
2998
2999 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000}
3001
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003002static int selinux_file_permission(struct file *file, int mask)
3003{
3004 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003005 struct file_security_struct *fsec = file->f_security;
3006 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003007 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003008
3009 if (!mask) {
3010 /* No permission to check. Existence test. */
3011 return 0;
3012 }
3013
David Howells275bb412008-11-14 10:39:19 +11003014 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003015 && fsec->pseqno == avc_policy_seqno())
3016 return selinux_netlbl_inode_permission(inode, mask);
3017
3018 return selinux_revalidate_file_permission(file, mask);
3019}
3020
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021static int selinux_file_alloc_security(struct file *file)
3022{
3023 return file_alloc_security(file);
3024}
3025
3026static void selinux_file_free_security(struct file *file)
3027{
3028 file_free_security(file);
3029}
3030
3031static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3032 unsigned long arg)
3033{
David Howells88e67f32008-11-14 10:39:21 +11003034 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04003035 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Stephen Smalley242631c2008-06-05 09:21:28 -04003037 if (_IOC_DIR(cmd) & _IOC_WRITE)
3038 av |= FILE__WRITE;
3039 if (_IOC_DIR(cmd) & _IOC_READ)
3040 av |= FILE__READ;
3041 if (!av)
3042 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
David Howells88e67f32008-11-14 10:39:21 +11003044 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045}
3046
3047static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3048{
David Howells88e67f32008-11-14 10:39:21 +11003049 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003050 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003051
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052#ifndef CONFIG_PPC32
3053 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3054 /*
3055 * We are making executable an anonymous mapping or a
3056 * private file mapping that will also be writable.
3057 * This has an additional check.
3058 */
David Howellsd84f4f92008-11-14 10:39:23 +11003059 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003061 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 }
3063#endif
3064
3065 if (file) {
3066 /* read access is always possible with a mapping */
3067 u32 av = FILE__READ;
3068
3069 /* write access only matters if the mapping is shared */
3070 if (shared && (prot & PROT_WRITE))
3071 av |= FILE__WRITE;
3072
3073 if (prot & PROT_EXEC)
3074 av |= FILE__EXECUTE;
3075
David Howells88e67f32008-11-14 10:39:21 +11003076 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 }
David Howellsd84f4f92008-11-14 10:39:23 +11003078
3079error:
3080 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081}
3082
3083static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003084 unsigned long prot, unsigned long flags,
3085 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086{
Eric Parised032182007-06-28 15:55:21 -04003087 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003088 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
Eric Parised032182007-06-28 15:55:21 -04003090 if (addr < mmap_min_addr)
3091 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3092 MEMPROTECT__MMAP_ZERO, NULL);
3093 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 return rc;
3095
3096 if (selinux_checkreqprot)
3097 prot = reqprot;
3098
3099 return file_map_prot_check(file, prot,
3100 (flags & MAP_TYPE) == MAP_SHARED);
3101}
3102
3103static int selinux_file_mprotect(struct vm_area_struct *vma,
3104 unsigned long reqprot,
3105 unsigned long prot)
3106{
David Howells88e67f32008-11-14 10:39:21 +11003107 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 int rc;
3109
3110 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3111 if (rc)
3112 return rc;
3113
3114 if (selinux_checkreqprot)
3115 prot = reqprot;
3116
3117#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003118 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3119 rc = 0;
3120 if (vma->vm_start >= vma->vm_mm->start_brk &&
3121 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003122 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003123 } else if (!vma->vm_file &&
3124 vma->vm_start <= vma->vm_mm->start_stack &&
3125 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003126 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003127 } else if (vma->vm_file && vma->anon_vma) {
3128 /*
3129 * We are making executable a file mapping that has
3130 * had some COW done. Since pages might have been
3131 * written, check ability to execute the possibly
3132 * modified content. This typically should only
3133 * occur for text relocations.
3134 */
David Howellsd84f4f92008-11-14 10:39:23 +11003135 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003136 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003137 if (rc)
3138 return rc;
3139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140#endif
3141
3142 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3143}
3144
3145static int selinux_file_lock(struct file *file, unsigned int cmd)
3146{
David Howells88e67f32008-11-14 10:39:21 +11003147 const struct cred *cred = current_cred();
3148
3149 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150}
3151
3152static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3153 unsigned long arg)
3154{
David Howells88e67f32008-11-14 10:39:21 +11003155 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 int err = 0;
3157
3158 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003159 case F_SETFL:
3160 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3161 err = -EINVAL;
3162 break;
3163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
Eric Paris828dfe12008-04-17 13:17:49 -04003165 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003166 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003168 }
3169 /* fall through */
3170 case F_SETOWN:
3171 case F_SETSIG:
3172 case F_GETFL:
3173 case F_GETOWN:
3174 case F_GETSIG:
3175 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003176 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003177 break;
3178 case F_GETLK:
3179 case F_SETLK:
3180 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003182 case F_GETLK64:
3183 case F_SETLK64:
3184 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003186 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3187 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003189 }
David Howells88e67f32008-11-14 10:39:21 +11003190 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003191 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 }
3193
3194 return err;
3195}
3196
3197static int selinux_file_set_fowner(struct file *file)
3198{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 struct file_security_struct *fsec;
3200
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003202 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 return 0;
3205}
3206
3207static int selinux_file_send_sigiotask(struct task_struct *tsk,
3208 struct fown_struct *fown, int signum)
3209{
Eric Paris828dfe12008-04-17 13:17:49 -04003210 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003211 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 struct file_security_struct *fsec;
3214
3215 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003216 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 fsec = file->f_security;
3219
3220 if (!signum)
3221 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3222 else
3223 perm = signal_to_av(signum);
3224
David Howells275bb412008-11-14 10:39:19 +11003225 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 SECCLASS_PROCESS, perm, NULL);
3227}
3228
3229static int selinux_file_receive(struct file *file)
3230{
David Howells88e67f32008-11-14 10:39:21 +11003231 const struct cred *cred = current_cred();
3232
3233 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234}
3235
David Howells745ca242008-11-14 10:39:22 +11003236static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003237{
3238 struct file_security_struct *fsec;
3239 struct inode *inode;
3240 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003241
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003242 inode = file->f_path.dentry->d_inode;
3243 fsec = file->f_security;
3244 isec = inode->i_security;
3245 /*
3246 * Save inode label and policy sequence number
3247 * at open-time so that selinux_file_permission
3248 * can determine whether revalidation is necessary.
3249 * Task label is already saved in the file security
3250 * struct as its SID.
3251 */
3252 fsec->isid = isec->sid;
3253 fsec->pseqno = avc_policy_seqno();
3254 /*
3255 * Since the inode label or policy seqno may have changed
3256 * between the selinux_inode_permission check and the saving
3257 * of state above, recheck that access is still permitted.
3258 * Otherwise, access might never be revalidated against the
3259 * new inode label or new policy.
3260 * This check is not redundant - do not remove.
3261 */
David Howells88e67f32008-11-14 10:39:21 +11003262 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003263}
3264
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265/* task security operations */
3266
3267static int selinux_task_create(unsigned long clone_flags)
3268{
3269 int rc;
3270
3271 rc = secondary_ops->task_create(clone_flags);
3272 if (rc)
3273 return rc;
3274
David Howells3b11a1d2008-11-14 10:39:26 +11003275 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276}
3277
David Howellsf1752ee2008-11-14 10:39:17 +11003278/*
3279 * detach and free the LSM part of a set of credentials
3280 */
3281static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282{
David Howellsf1752ee2008-11-14 10:39:17 +11003283 struct task_security_struct *tsec = cred->security;
3284 cred->security = NULL;
3285 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286}
3287
David Howellsd84f4f92008-11-14 10:39:23 +11003288/*
3289 * prepare a new set of credentials for modification
3290 */
3291static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3292 gfp_t gfp)
3293{
3294 const struct task_security_struct *old_tsec;
3295 struct task_security_struct *tsec;
3296
3297 old_tsec = old->security;
3298
3299 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3300 if (!tsec)
3301 return -ENOMEM;
3302
3303 new->security = tsec;
3304 return 0;
3305}
3306
3307/*
3308 * commit new credentials
3309 */
3310static void selinux_cred_commit(struct cred *new, const struct cred *old)
3311{
3312 secondary_ops->cred_commit(new, old);
3313}
3314
David Howells3a3b7ce2008-11-14 10:39:28 +11003315/*
3316 * set the security data for a kernel service
3317 * - all the creation contexts are set to unlabelled
3318 */
3319static int selinux_kernel_act_as(struct cred *new, u32 secid)
3320{
3321 struct task_security_struct *tsec = new->security;
3322 u32 sid = current_sid();
3323 int ret;
3324
3325 ret = avc_has_perm(sid, secid,
3326 SECCLASS_KERNEL_SERVICE,
3327 KERNEL_SERVICE__USE_AS_OVERRIDE,
3328 NULL);
3329 if (ret == 0) {
3330 tsec->sid = secid;
3331 tsec->create_sid = 0;
3332 tsec->keycreate_sid = 0;
3333 tsec->sockcreate_sid = 0;
3334 }
3335 return ret;
3336}
3337
3338/*
3339 * set the file creation context in a security record to the same as the
3340 * objective context of the specified inode
3341 */
3342static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3343{
3344 struct inode_security_struct *isec = inode->i_security;
3345 struct task_security_struct *tsec = new->security;
3346 u32 sid = current_sid();
3347 int ret;
3348
3349 ret = avc_has_perm(sid, isec->sid,
3350 SECCLASS_KERNEL_SERVICE,
3351 KERNEL_SERVICE__CREATE_FILES_AS,
3352 NULL);
3353
3354 if (ret == 0)
3355 tsec->create_sid = isec->sid;
3356 return 0;
3357}
3358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3360{
3361 /* Since setuid only affects the current process, and
3362 since the SELinux controls are not based on the Linux
3363 identity attributes, SELinux does not need to control
3364 this operation. However, SELinux does control the use
3365 of the CAP_SETUID and CAP_SETGID capabilities using the
3366 capable hook. */
3367 return 0;
3368}
3369
David Howellsd84f4f92008-11-14 10:39:23 +11003370static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3371 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372{
David Howellsd84f4f92008-11-14 10:39:23 +11003373 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374}
3375
3376static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3377{
3378 /* See the comment for setuid above. */
3379 return 0;
3380}
3381
3382static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3383{
David Howells3b11a1d2008-11-14 10:39:26 +11003384 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385}
3386
3387static int selinux_task_getpgid(struct task_struct *p)
3388{
David Howells3b11a1d2008-11-14 10:39:26 +11003389 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390}
3391
3392static int selinux_task_getsid(struct task_struct *p)
3393{
David Howells3b11a1d2008-11-14 10:39:26 +11003394 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395}
3396
David Quigleyf9008e42006-06-30 01:55:46 -07003397static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3398{
David Howells275bb412008-11-14 10:39:19 +11003399 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003400}
3401
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402static int selinux_task_setgroups(struct group_info *group_info)
3403{
3404 /* See the comment for setuid above. */
3405 return 0;
3406}
3407
3408static int selinux_task_setnice(struct task_struct *p, int nice)
3409{
3410 int rc;
3411
3412 rc = secondary_ops->task_setnice(p, nice);
3413 if (rc)
3414 return rc;
3415
David Howells3b11a1d2008-11-14 10:39:26 +11003416 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417}
3418
James Morris03e68062006-06-23 02:03:58 -07003419static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3420{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003421 int rc;
3422
3423 rc = secondary_ops->task_setioprio(p, ioprio);
3424 if (rc)
3425 return rc;
3426
David Howells3b11a1d2008-11-14 10:39:26 +11003427 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003428}
3429
David Quigleya1836a42006-06-30 01:55:49 -07003430static int selinux_task_getioprio(struct task_struct *p)
3431{
David Howells3b11a1d2008-11-14 10:39:26 +11003432 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003433}
3434
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3436{
3437 struct rlimit *old_rlim = current->signal->rlim + resource;
3438 int rc;
3439
3440 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3441 if (rc)
3442 return rc;
3443
3444 /* Control the ability to change the hard limit (whether
3445 lowering or raising it), so that the hard limit can
3446 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003447 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003449 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
3451 return 0;
3452}
3453
3454static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3455{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003456 int rc;
3457
3458 rc = secondary_ops->task_setscheduler(p, policy, lp);
3459 if (rc)
3460 return rc;
3461
David Howells3b11a1d2008-11-14 10:39:26 +11003462 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463}
3464
3465static int selinux_task_getscheduler(struct task_struct *p)
3466{
David Howells3b11a1d2008-11-14 10:39:26 +11003467 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468}
3469
David Quigley35601542006-06-23 02:04:01 -07003470static int selinux_task_movememory(struct task_struct *p)
3471{
David Howells3b11a1d2008-11-14 10:39:26 +11003472 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003473}
3474
David Quigleyf9008e42006-06-30 01:55:46 -07003475static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3476 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477{
3478 u32 perm;
3479 int rc;
3480
David Quigleyf9008e42006-06-30 01:55:46 -07003481 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 if (rc)
3483 return rc;
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 if (!sig)
3486 perm = PROCESS__SIGNULL; /* null signal; existence test */
3487 else
3488 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003489 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003490 rc = avc_has_perm(secid, task_sid(p),
3491 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003492 else
David Howells3b11a1d2008-11-14 10:39:26 +11003493 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003494 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495}
3496
3497static int selinux_task_prctl(int option,
3498 unsigned long arg2,
3499 unsigned long arg3,
3500 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003501 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502{
3503 /* The current prctl operations do not appear to require
3504 any SELinux controls since they merely observe or modify
3505 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003506 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507}
3508
3509static int selinux_task_wait(struct task_struct *p)
3510{
Eric Paris8a535142007-10-22 16:10:31 -04003511 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512}
3513
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514static void selinux_task_to_inode(struct task_struct *p,
3515 struct inode *inode)
3516{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003518 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
David Howells275bb412008-11-14 10:39:19 +11003520 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522}
3523
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003525static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3526 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527{
3528 int offset, ihlen, ret = -EINVAL;
3529 struct iphdr _iph, *ih;
3530
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003531 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3533 if (ih == NULL)
3534 goto out;
3535
3536 ihlen = ih->ihl * 4;
3537 if (ihlen < sizeof(_iph))
3538 goto out;
3539
3540 ad->u.net.v4info.saddr = ih->saddr;
3541 ad->u.net.v4info.daddr = ih->daddr;
3542 ret = 0;
3543
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003544 if (proto)
3545 *proto = ih->protocol;
3546
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003548 case IPPROTO_TCP: {
3549 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
Eric Paris828dfe12008-04-17 13:17:49 -04003551 if (ntohs(ih->frag_off) & IP_OFFSET)
3552 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
3554 offset += ihlen;
3555 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3556 if (th == NULL)
3557 break;
3558
3559 ad->u.net.sport = th->source;
3560 ad->u.net.dport = th->dest;
3561 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
Eric Paris828dfe12008-04-17 13:17:49 -04003564 case IPPROTO_UDP: {
3565 struct udphdr _udph, *uh;
3566
3567 if (ntohs(ih->frag_off) & IP_OFFSET)
3568 break;
3569
3570 offset += ihlen;
3571 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3572 if (uh == NULL)
3573 break;
3574
3575 ad->u.net.sport = uh->source;
3576 ad->u.net.dport = uh->dest;
3577 break;
3578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579
James Morris2ee92d42006-11-13 16:09:01 -08003580 case IPPROTO_DCCP: {
3581 struct dccp_hdr _dccph, *dh;
3582
3583 if (ntohs(ih->frag_off) & IP_OFFSET)
3584 break;
3585
3586 offset += ihlen;
3587 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3588 if (dh == NULL)
3589 break;
3590
3591 ad->u.net.sport = dh->dccph_sport;
3592 ad->u.net.dport = dh->dccph_dport;
3593 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003594 }
James Morris2ee92d42006-11-13 16:09:01 -08003595
Eric Paris828dfe12008-04-17 13:17:49 -04003596 default:
3597 break;
3598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599out:
3600 return ret;
3601}
3602
3603#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3604
3605/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003606static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3607 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608{
3609 u8 nexthdr;
3610 int ret = -EINVAL, offset;
3611 struct ipv6hdr _ipv6h, *ip6;
3612
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003613 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3615 if (ip6 == NULL)
3616 goto out;
3617
3618 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3619 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3620 ret = 0;
3621
3622 nexthdr = ip6->nexthdr;
3623 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003624 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 if (offset < 0)
3626 goto out;
3627
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003628 if (proto)
3629 *proto = nexthdr;
3630
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 switch (nexthdr) {
3632 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003633 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634
3635 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3636 if (th == NULL)
3637 break;
3638
3639 ad->u.net.sport = th->source;
3640 ad->u.net.dport = th->dest;
3641 break;
3642 }
3643
3644 case IPPROTO_UDP: {
3645 struct udphdr _udph, *uh;
3646
3647 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3648 if (uh == NULL)
3649 break;
3650
3651 ad->u.net.sport = uh->source;
3652 ad->u.net.dport = uh->dest;
3653 break;
3654 }
3655
James Morris2ee92d42006-11-13 16:09:01 -08003656 case IPPROTO_DCCP: {
3657 struct dccp_hdr _dccph, *dh;
3658
3659 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3660 if (dh == NULL)
3661 break;
3662
3663 ad->u.net.sport = dh->dccph_sport;
3664 ad->u.net.dport = dh->dccph_dport;
3665 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003666 }
James Morris2ee92d42006-11-13 16:09:01 -08003667
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 /* includes fragments */
3669 default:
3670 break;
3671 }
3672out:
3673 return ret;
3674}
3675
3676#endif /* IPV6 */
3677
3678static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003679 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680{
David Howellscf9481e2008-07-27 21:31:07 +10003681 char *addrp;
3682 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
3684 switch (ad->u.net.family) {
3685 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003686 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003687 if (ret)
3688 goto parse_error;
3689 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3690 &ad->u.net.v4info.daddr);
3691 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
3693#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3694 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003695 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003696 if (ret)
3697 goto parse_error;
3698 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3699 &ad->u.net.v6info.daddr);
3700 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701#endif /* IPV6 */
3702 default:
David Howellscf9481e2008-07-27 21:31:07 +10003703 addrp = NULL;
3704 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 }
3706
David Howellscf9481e2008-07-27 21:31:07 +10003707parse_error:
3708 printk(KERN_WARNING
3709 "SELinux: failure in selinux_parse_skb(),"
3710 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003712
3713okay:
3714 if (_addrp)
3715 *_addrp = addrp;
3716 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717}
3718
Paul Moore4f6a9932007-03-01 14:35:22 -05003719/**
Paul Moore220deb92008-01-29 08:38:23 -05003720 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003721 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003722 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003723 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003724 *
3725 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003726 * Check the various different forms of network peer labeling and determine
3727 * the peer label/SID for the packet; most of the magic actually occurs in
3728 * the security server function security_net_peersid_cmp(). The function
3729 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3730 * or -EACCES if @sid is invalid due to inconsistencies with the different
3731 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003732 *
3733 */
Paul Moore220deb92008-01-29 08:38:23 -05003734static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003735{
Paul Moore71f1cb02008-01-29 08:51:16 -05003736 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003737 u32 xfrm_sid;
3738 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003739 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003740
3741 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003742 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003743
Paul Moore71f1cb02008-01-29 08:51:16 -05003744 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3745 if (unlikely(err)) {
3746 printk(KERN_WARNING
3747 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3748 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003749 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003750 }
Paul Moore220deb92008-01-29 08:38:23 -05003751
3752 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003753}
3754
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755/* socket security operations */
3756static int socket_has_perm(struct task_struct *task, struct socket *sock,
3757 u32 perms)
3758{
3759 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003761 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 int err = 0;
3763
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 isec = SOCK_INODE(sock)->i_security;
3765
3766 if (isec->sid == SECINITSID_KERNEL)
3767 goto out;
David Howells275bb412008-11-14 10:39:19 +11003768 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
Eric Paris828dfe12008-04-17 13:17:49 -04003770 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003772 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773
3774out:
3775 return err;
3776}
3777
3778static int selinux_socket_create(int family, int type,
3779 int protocol, int kern)
3780{
David Howells275bb412008-11-14 10:39:19 +11003781 const struct cred *cred = current_cred();
3782 const struct task_security_struct *tsec = cred->security;
3783 u32 sid, newsid;
3784 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786
3787 if (kern)
3788 goto out;
3789
David Howells275bb412008-11-14 10:39:19 +11003790 sid = tsec->sid;
3791 newsid = tsec->sockcreate_sid ?: sid;
3792
3793 secclass = socket_type_to_security_class(family, type, protocol);
3794 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795
3796out:
3797 return err;
3798}
3799
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003800static int selinux_socket_post_create(struct socket *sock, int family,
3801 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802{
David Howells275bb412008-11-14 10:39:19 +11003803 const struct cred *cred = current_cred();
3804 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003806 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003807 u32 sid, newsid;
3808 int err = 0;
3809
3810 sid = tsec->sid;
3811 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
3813 isec = SOCK_INODE(sock)->i_security;
3814
David Howells275bb412008-11-14 10:39:19 +11003815 if (kern)
3816 isec->sid = SECINITSID_KERNEL;
3817 else if (newsid)
3818 isec->sid = newsid;
3819 else
3820 isec->sid = sid;
3821
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 isec->initialized = 1;
3824
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003825 if (sock->sk) {
3826 sksec = sock->sk->sk_security;
3827 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003828 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003829 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003830 }
3831
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003832 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833}
3834
3835/* Range of port numbers used to automatically bind.
3836 Need to determine whether we should perform a name_bind
3837 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838
3839static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3840{
3841 u16 family;
3842 int err;
3843
3844 err = socket_has_perm(current, sock, SOCKET__BIND);
3845 if (err)
3846 goto out;
3847
3848 /*
3849 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003850 * Multiple address binding for SCTP is not supported yet: we just
3851 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 */
3853 family = sock->sk->sk_family;
3854 if (family == PF_INET || family == PF_INET6) {
3855 char *addrp;
3856 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 struct avc_audit_data ad;
3858 struct sockaddr_in *addr4 = NULL;
3859 struct sockaddr_in6 *addr6 = NULL;
3860 unsigned short snum;
3861 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003862 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 isec = SOCK_INODE(sock)->i_security;
3865
3866 if (family == PF_INET) {
3867 addr4 = (struct sockaddr_in *)address;
3868 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 addrp = (char *)&addr4->sin_addr.s_addr;
3870 } else {
3871 addr6 = (struct sockaddr_in6 *)address;
3872 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 addrp = (char *)&addr6->sin6_addr.s6_addr;
3874 }
3875
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003876 if (snum) {
3877 int low, high;
3878
3879 inet_get_local_port_range(&low, &high);
3880
3881 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003882 err = sel_netport_sid(sk->sk_protocol,
3883 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003884 if (err)
3885 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003886 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003887 ad.u.net.sport = htons(snum);
3888 ad.u.net.family = family;
3889 err = avc_has_perm(isec->sid, sid,
3890 isec->sclass,
3891 SOCKET__NAME_BIND, &ad);
3892 if (err)
3893 goto out;
3894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 }
Eric Paris828dfe12008-04-17 13:17:49 -04003896
3897 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003898 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 node_perm = TCP_SOCKET__NODE_BIND;
3900 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003901
James Morris13402582005-09-30 14:24:34 -04003902 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 node_perm = UDP_SOCKET__NODE_BIND;
3904 break;
James Morris2ee92d42006-11-13 16:09:01 -08003905
3906 case SECCLASS_DCCP_SOCKET:
3907 node_perm = DCCP_SOCKET__NODE_BIND;
3908 break;
3909
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 default:
3911 node_perm = RAWIP_SOCKET__NODE_BIND;
3912 break;
3913 }
Eric Paris828dfe12008-04-17 13:17:49 -04003914
Paul Moore224dfbd2008-01-29 08:38:13 -05003915 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 if (err)
3917 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003918
3919 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 ad.u.net.sport = htons(snum);
3921 ad.u.net.family = family;
3922
3923 if (family == PF_INET)
3924 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3925 else
3926 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3927
3928 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003929 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 if (err)
3931 goto out;
3932 }
3933out:
3934 return err;
3935}
3936
3937static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3938{
Paul Moore014ab192008-10-10 10:16:33 -04003939 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 struct inode_security_struct *isec;
3941 int err;
3942
3943 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3944 if (err)
3945 return err;
3946
3947 /*
James Morris2ee92d42006-11-13 16:09:01 -08003948 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 */
3950 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003951 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3952 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 struct avc_audit_data ad;
3954 struct sockaddr_in *addr4 = NULL;
3955 struct sockaddr_in6 *addr6 = NULL;
3956 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003957 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958
3959 if (sk->sk_family == PF_INET) {
3960 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003961 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 return -EINVAL;
3963 snum = ntohs(addr4->sin_port);
3964 } else {
3965 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003966 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return -EINVAL;
3968 snum = ntohs(addr6->sin6_port);
3969 }
3970
Paul Moore3e112172008-04-10 10:48:14 -04003971 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 if (err)
3973 goto out;
3974
James Morris2ee92d42006-11-13 16:09:01 -08003975 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3976 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3977
Eric Paris828dfe12008-04-17 13:17:49 -04003978 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 ad.u.net.dport = htons(snum);
3980 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003981 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 if (err)
3983 goto out;
3984 }
3985
Paul Moore014ab192008-10-10 10:16:33 -04003986 err = selinux_netlbl_socket_connect(sk, address);
3987
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988out:
3989 return err;
3990}
3991
3992static int selinux_socket_listen(struct socket *sock, int backlog)
3993{
3994 return socket_has_perm(current, sock, SOCKET__LISTEN);
3995}
3996
3997static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3998{
3999 int err;
4000 struct inode_security_struct *isec;
4001 struct inode_security_struct *newisec;
4002
4003 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
4004 if (err)
4005 return err;
4006
4007 newisec = SOCK_INODE(newsock)->i_security;
4008
4009 isec = SOCK_INODE(sock)->i_security;
4010 newisec->sclass = isec->sclass;
4011 newisec->sid = isec->sid;
4012 newisec->initialized = 1;
4013
4014 return 0;
4015}
4016
4017static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04004018 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004020 int rc;
4021
4022 rc = socket_has_perm(current, sock, SOCKET__WRITE);
4023 if (rc)
4024 return rc;
4025
4026 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027}
4028
4029static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4030 int size, int flags)
4031{
4032 return socket_has_perm(current, sock, SOCKET__READ);
4033}
4034
4035static int selinux_socket_getsockname(struct socket *sock)
4036{
4037 return socket_has_perm(current, sock, SOCKET__GETATTR);
4038}
4039
4040static int selinux_socket_getpeername(struct socket *sock)
4041{
4042 return socket_has_perm(current, sock, SOCKET__GETATTR);
4043}
4044
Eric Paris828dfe12008-04-17 13:17:49 -04004045static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046{
Paul Mooref8687af2006-10-30 15:22:15 -08004047 int err;
4048
4049 err = socket_has_perm(current, sock, SOCKET__SETOPT);
4050 if (err)
4051 return err;
4052
4053 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054}
4055
4056static int selinux_socket_getsockopt(struct socket *sock, int level,
4057 int optname)
4058{
4059 return socket_has_perm(current, sock, SOCKET__GETOPT);
4060}
4061
4062static int selinux_socket_shutdown(struct socket *sock, int how)
4063{
4064 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
4065}
4066
4067static int selinux_socket_unix_stream_connect(struct socket *sock,
4068 struct socket *other,
4069 struct sock *newsk)
4070{
4071 struct sk_security_struct *ssec;
4072 struct inode_security_struct *isec;
4073 struct inode_security_struct *other_isec;
4074 struct avc_audit_data ad;
4075 int err;
4076
4077 err = secondary_ops->unix_stream_connect(sock, other, newsk);
4078 if (err)
4079 return err;
4080
4081 isec = SOCK_INODE(sock)->i_security;
4082 other_isec = SOCK_INODE(other)->i_security;
4083
Eric Paris828dfe12008-04-17 13:17:49 -04004084 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 ad.u.net.sk = other->sk;
4086
4087 err = avc_has_perm(isec->sid, other_isec->sid,
4088 isec->sclass,
4089 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4090 if (err)
4091 return err;
4092
4093 /* connecting socket */
4094 ssec = sock->sk->sk_security;
4095 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004096
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 /* server child socket */
4098 ssec = newsk->sk_security;
4099 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004100 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4101
4102 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103}
4104
4105static int selinux_socket_unix_may_send(struct socket *sock,
4106 struct socket *other)
4107{
4108 struct inode_security_struct *isec;
4109 struct inode_security_struct *other_isec;
4110 struct avc_audit_data ad;
4111 int err;
4112
4113 isec = SOCK_INODE(sock)->i_security;
4114 other_isec = SOCK_INODE(other)->i_security;
4115
Eric Paris828dfe12008-04-17 13:17:49 -04004116 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 ad.u.net.sk = other->sk;
4118
4119 err = avc_has_perm(isec->sid, other_isec->sid,
4120 isec->sclass, SOCKET__SENDTO, &ad);
4121 if (err)
4122 return err;
4123
4124 return 0;
4125}
4126
Paul Mooreeffad8d2008-01-29 08:49:27 -05004127static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4128 u32 peer_sid,
4129 struct avc_audit_data *ad)
4130{
4131 int err;
4132 u32 if_sid;
4133 u32 node_sid;
4134
4135 err = sel_netif_sid(ifindex, &if_sid);
4136 if (err)
4137 return err;
4138 err = avc_has_perm(peer_sid, if_sid,
4139 SECCLASS_NETIF, NETIF__INGRESS, ad);
4140 if (err)
4141 return err;
4142
4143 err = sel_netnode_sid(addrp, family, &node_sid);
4144 if (err)
4145 return err;
4146 return avc_has_perm(peer_sid, node_sid,
4147 SECCLASS_NODE, NODE__RECVFROM, ad);
4148}
4149
Paul Moore220deb92008-01-29 08:38:23 -05004150static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4151 struct sk_buff *skb,
4152 struct avc_audit_data *ad,
4153 u16 family,
4154 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155{
Paul Moore220deb92008-01-29 08:38:23 -05004156 int err;
4157 struct sk_security_struct *sksec = sk->sk_security;
4158 u16 sk_class;
4159 u32 netif_perm, node_perm, recv_perm;
4160 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004161
Paul Moore220deb92008-01-29 08:38:23 -05004162 sk_sid = sksec->sid;
4163 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164
Paul Moore220deb92008-01-29 08:38:23 -05004165 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 case SECCLASS_UDP_SOCKET:
4167 netif_perm = NETIF__UDP_RECV;
4168 node_perm = NODE__UDP_RECV;
4169 recv_perm = UDP_SOCKET__RECV_MSG;
4170 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 case SECCLASS_TCP_SOCKET:
4172 netif_perm = NETIF__TCP_RECV;
4173 node_perm = NODE__TCP_RECV;
4174 recv_perm = TCP_SOCKET__RECV_MSG;
4175 break;
James Morris2ee92d42006-11-13 16:09:01 -08004176 case SECCLASS_DCCP_SOCKET:
4177 netif_perm = NETIF__DCCP_RECV;
4178 node_perm = NODE__DCCP_RECV;
4179 recv_perm = DCCP_SOCKET__RECV_MSG;
4180 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 default:
4182 netif_perm = NETIF__RAWIP_RECV;
4183 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004184 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 break;
4186 }
4187
Paul Moore220deb92008-01-29 08:38:23 -05004188 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004190 return err;
4191 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4192 if (err)
4193 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004194
Paul Moore224dfbd2008-01-29 08:38:13 -05004195 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004197 return err;
4198 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004200 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201
Paul Moore220deb92008-01-29 08:38:23 -05004202 if (!recv_perm)
4203 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004204 err = sel_netport_sid(sk->sk_protocol,
4205 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004206 if (unlikely(err)) {
4207 printk(KERN_WARNING
4208 "SELinux: failure in"
4209 " selinux_sock_rcv_skb_iptables_compat(),"
4210 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004211 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004212 }
Paul Moore220deb92008-01-29 08:38:23 -05004213 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4214}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Paul Moore220deb92008-01-29 08:38:23 -05004216static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004217 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004218{
Paul Moore277d3422008-12-31 12:54:11 -05004219 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004220 struct sk_security_struct *sksec = sk->sk_security;
4221 u32 peer_sid;
4222 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004223 struct avc_audit_data ad;
4224 char *addrp;
4225
4226 AVC_AUDIT_DATA_INIT(&ad, NET);
4227 ad.u.net.netif = skb->iif;
4228 ad.u.net.family = family;
4229 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4230 if (err)
4231 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004232
4233 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004234 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004235 family, addrp);
Paul Moore277d3422008-12-31 12:54:11 -05004236 else if (selinux_secmark_enabled())
Paul Moore220deb92008-01-29 08:38:23 -05004237 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004238 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004239 if (err)
4240 return err;
4241
4242 if (selinux_policycap_netpeer) {
4243 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004245 return err;
4246 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004247 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004248 if (err)
4249 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004250 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004251 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004252 if (err)
4253 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004254 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004256
James Morris4e5ab4c2006-06-09 00:33:33 -07004257 return err;
4258}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004259
James Morris4e5ab4c2006-06-09 00:33:33 -07004260static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4261{
Paul Moore220deb92008-01-29 08:38:23 -05004262 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004263 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004264 u16 family = sk->sk_family;
4265 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004266 struct avc_audit_data ad;
4267 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004268 u8 secmark_active;
4269 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004270
James Morris4e5ab4c2006-06-09 00:33:33 -07004271 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004272 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004273
4274 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004275 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004276 family = PF_INET;
4277
Paul Moored8395c82008-10-10 10:16:30 -04004278 /* If any sort of compatibility mode is enabled then handoff processing
4279 * to the selinux_sock_rcv_skb_compat() function to deal with the
4280 * special handling. We do this in an attempt to keep this function
4281 * as fast and as clean as possible. */
4282 if (selinux_compat_net || !selinux_policycap_netpeer)
4283 return selinux_sock_rcv_skb_compat(sk, skb, family);
4284
4285 secmark_active = selinux_secmark_enabled();
4286 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4287 if (!secmark_active && !peerlbl_active)
4288 return 0;
4289
James Morris4e5ab4c2006-06-09 00:33:33 -07004290 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004291 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004292 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004293 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004294 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004295 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004296
Paul Moored8395c82008-10-10 10:16:30 -04004297 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004298 u32 peer_sid;
4299
4300 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4301 if (err)
4302 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004303 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4304 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004305 if (err) {
4306 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004307 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004308 }
Paul Moored621d352008-01-29 08:43:36 -05004309 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4310 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004311 if (err)
4312 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004313 }
4314
Paul Moored8395c82008-10-10 10:16:30 -04004315 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004316 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4317 PACKET__RECV, &ad);
4318 if (err)
4319 return err;
4320 }
4321
Paul Moored621d352008-01-29 08:43:36 -05004322 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323}
4324
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004325static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4326 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327{
4328 int err = 0;
4329 char *scontext;
4330 u32 scontext_len;
4331 struct sk_security_struct *ssec;
4332 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004333 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
4335 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004336
Paul Moore3de4bab2006-11-17 17:38:54 -05004337 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4338 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004339 ssec = sock->sk->sk_security;
4340 peer_sid = ssec->peer_sid;
4341 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004342 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 err = -ENOPROTOOPT;
4344 goto out;
4345 }
4346
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004347 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4348
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 if (err)
4350 goto out;
4351
4352 if (scontext_len > len) {
4353 err = -ERANGE;
4354 goto out_len;
4355 }
4356
4357 if (copy_to_user(optval, scontext, scontext_len))
4358 err = -EFAULT;
4359
4360out_len:
4361 if (put_user(scontext_len, optlen))
4362 err = -EFAULT;
4363
4364 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004365out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 return err;
4367}
4368
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004369static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004370{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004371 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004372 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004373
Paul Mooreaa862902008-10-10 10:16:29 -04004374 if (skb && skb->protocol == htons(ETH_P_IP))
4375 family = PF_INET;
4376 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4377 family = PF_INET6;
4378 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004379 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004380 else
4381 goto out;
4382
4383 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02004384 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004385 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004386 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004387
Paul Moore75e22912008-01-29 08:38:04 -05004388out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004389 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004390 if (peer_secid == SECSID_NULL)
4391 return -EINVAL;
4392 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004393}
4394
Al Viro7d877f32005-10-21 03:20:43 -04004395static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396{
4397 return sk_alloc_security(sk, family, priority);
4398}
4399
4400static void selinux_sk_free_security(struct sock *sk)
4401{
4402 sk_free_security(sk);
4403}
4404
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004405static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4406{
4407 struct sk_security_struct *ssec = sk->sk_security;
4408 struct sk_security_struct *newssec = newsk->sk_security;
4409
4410 newssec->sid = ssec->sid;
4411 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004412 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004413
Paul Mooref74af6e2008-02-25 11:40:33 -05004414 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004415}
4416
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004417static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004418{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004419 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004420 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004421 else {
4422 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004423
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004424 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004425 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004426}
4427
Eric Paris828dfe12008-04-17 13:17:49 -04004428static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004429{
4430 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4431 struct sk_security_struct *sksec = sk->sk_security;
4432
David Woodhouse2148ccc2006-09-29 15:50:25 -07004433 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4434 sk->sk_family == PF_UNIX)
4435 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004436 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004437}
4438
Adrian Bunk9a673e52006-08-15 00:03:53 -07004439static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4440 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004441{
4442 struct sk_security_struct *sksec = sk->sk_security;
4443 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004444 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004445 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004446 u32 peersid;
4447
Paul Mooreaa862902008-10-10 10:16:29 -04004448 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4449 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4450 family = PF_INET;
4451
4452 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004453 if (err)
4454 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004455 if (peersid == SECSID_NULL) {
4456 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004457 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004458 return 0;
4459 }
4460
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004461 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4462 if (err)
4463 return err;
4464
4465 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004466 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004467 return 0;
4468}
4469
Adrian Bunk9a673e52006-08-15 00:03:53 -07004470static void selinux_inet_csk_clone(struct sock *newsk,
4471 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004472{
4473 struct sk_security_struct *newsksec = newsk->sk_security;
4474
4475 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004476 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004477 /* NOTE: Ideally, we should also get the isec->sid for the
4478 new socket in sync, but we don't have the isec available yet.
4479 So we will wait until sock_graft to do it, by which
4480 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004481
Paul Moore9f2ad662006-11-17 17:38:53 -05004482 /* We don't need to take any sort of lock here as we are the only
4483 * thread with access to newsksec */
4484 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004485}
4486
Paul Moore014ab192008-10-10 10:16:33 -04004487static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004488{
Paul Mooreaa862902008-10-10 10:16:29 -04004489 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004490 struct sk_security_struct *sksec = sk->sk_security;
4491
Paul Mooreaa862902008-10-10 10:16:29 -04004492 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4493 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4494 family = PF_INET;
4495
4496 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004497
4498 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004499}
4500
Adrian Bunk9a673e52006-08-15 00:03:53 -07004501static void selinux_req_classify_flow(const struct request_sock *req,
4502 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004503{
4504 fl->secid = req->secid;
4505}
4506
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4508{
4509 int err = 0;
4510 u32 perm;
4511 struct nlmsghdr *nlh;
4512 struct socket *sock = sk->sk_socket;
4513 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004514
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 if (skb->len < NLMSG_SPACE(0)) {
4516 err = -EINVAL;
4517 goto out;
4518 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004519 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004520
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4522 if (err) {
4523 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004524 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 "SELinux: unrecognized netlink message"
4526 " type=%hu for sclass=%hu\n",
4527 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004528 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 err = 0;
4530 }
4531
4532 /* Ignore */
4533 if (err == -ENOENT)
4534 err = 0;
4535 goto out;
4536 }
4537
4538 err = socket_has_perm(current, sock, perm);
4539out:
4540 return err;
4541}
4542
4543#ifdef CONFIG_NETFILTER
4544
Paul Mooreeffad8d2008-01-29 08:49:27 -05004545static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4546 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547{
Paul Mooredfaebe92008-10-10 10:16:31 -04004548 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004549 char *addrp;
4550 u32 peer_sid;
4551 struct avc_audit_data ad;
4552 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004553 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004554 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004555
Paul Mooreeffad8d2008-01-29 08:49:27 -05004556 if (!selinux_policycap_netpeer)
4557 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004558
Paul Mooreeffad8d2008-01-29 08:49:27 -05004559 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004560 netlbl_active = netlbl_enabled();
4561 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004562 if (!secmark_active && !peerlbl_active)
4563 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004564
Paul Moored8395c82008-10-10 10:16:30 -04004565 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4566 return NF_DROP;
4567
Paul Mooreeffad8d2008-01-29 08:49:27 -05004568 AVC_AUDIT_DATA_INIT(&ad, NET);
4569 ad.u.net.netif = ifindex;
4570 ad.u.net.family = family;
4571 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4572 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573
Paul Mooredfaebe92008-10-10 10:16:31 -04004574 if (peerlbl_active) {
4575 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4576 peer_sid, &ad);
4577 if (err) {
4578 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004579 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004580 }
4581 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004582
4583 if (secmark_active)
4584 if (avc_has_perm(peer_sid, skb->secmark,
4585 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4586 return NF_DROP;
4587
Paul Moore948bf852008-10-10 10:16:32 -04004588 if (netlbl_active)
4589 /* we do this in the FORWARD path and not the POST_ROUTING
4590 * path because we want to make sure we apply the necessary
4591 * labeling before IPsec is applied so we can leverage AH
4592 * protection */
4593 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4594 return NF_DROP;
4595
Paul Mooreeffad8d2008-01-29 08:49:27 -05004596 return NF_ACCEPT;
4597}
4598
4599static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4600 struct sk_buff *skb,
4601 const struct net_device *in,
4602 const struct net_device *out,
4603 int (*okfn)(struct sk_buff *))
4604{
4605 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4606}
4607
4608#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4609static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4610 struct sk_buff *skb,
4611 const struct net_device *in,
4612 const struct net_device *out,
4613 int (*okfn)(struct sk_buff *))
4614{
4615 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4616}
4617#endif /* IPV6 */
4618
Paul Moore948bf852008-10-10 10:16:32 -04004619static unsigned int selinux_ip_output(struct sk_buff *skb,
4620 u16 family)
4621{
4622 u32 sid;
4623
4624 if (!netlbl_enabled())
4625 return NF_ACCEPT;
4626
4627 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4628 * because we want to make sure we apply the necessary labeling
4629 * before IPsec is applied so we can leverage AH protection */
4630 if (skb->sk) {
4631 struct sk_security_struct *sksec = skb->sk->sk_security;
4632 sid = sksec->sid;
4633 } else
4634 sid = SECINITSID_KERNEL;
4635 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4636 return NF_DROP;
4637
4638 return NF_ACCEPT;
4639}
4640
4641static unsigned int selinux_ipv4_output(unsigned int hooknum,
4642 struct sk_buff *skb,
4643 const struct net_device *in,
4644 const struct net_device *out,
4645 int (*okfn)(struct sk_buff *))
4646{
4647 return selinux_ip_output(skb, PF_INET);
4648}
4649
Paul Mooreeffad8d2008-01-29 08:49:27 -05004650static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4651 int ifindex,
4652 struct avc_audit_data *ad,
4653 u16 family, char *addrp)
4654{
4655 int err;
4656 struct sk_security_struct *sksec = sk->sk_security;
4657 u16 sk_class;
4658 u32 netif_perm, node_perm, send_perm;
4659 u32 port_sid, node_sid, if_sid, sk_sid;
4660
4661 sk_sid = sksec->sid;
4662 sk_class = sksec->sclass;
4663
4664 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 case SECCLASS_UDP_SOCKET:
4666 netif_perm = NETIF__UDP_SEND;
4667 node_perm = NODE__UDP_SEND;
4668 send_perm = UDP_SOCKET__SEND_MSG;
4669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 case SECCLASS_TCP_SOCKET:
4671 netif_perm = NETIF__TCP_SEND;
4672 node_perm = NODE__TCP_SEND;
4673 send_perm = TCP_SOCKET__SEND_MSG;
4674 break;
James Morris2ee92d42006-11-13 16:09:01 -08004675 case SECCLASS_DCCP_SOCKET:
4676 netif_perm = NETIF__DCCP_SEND;
4677 node_perm = NODE__DCCP_SEND;
4678 send_perm = DCCP_SOCKET__SEND_MSG;
4679 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 default:
4681 netif_perm = NETIF__RAWIP_SEND;
4682 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004683 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 break;
4685 }
4686
Paul Mooreeffad8d2008-01-29 08:49:27 -05004687 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004688 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004689 return err;
4690 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4691 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004692
Paul Moore224dfbd2008-01-29 08:38:13 -05004693 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004694 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004695 return err;
4696 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004697 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004698 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699
Paul Mooreeffad8d2008-01-29 08:49:27 -05004700 if (send_perm != 0)
4701 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702
Paul Moore3e112172008-04-10 10:48:14 -04004703 err = sel_netport_sid(sk->sk_protocol,
4704 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004705 if (unlikely(err)) {
4706 printk(KERN_WARNING
4707 "SELinux: failure in"
4708 " selinux_ip_postroute_iptables_compat(),"
4709 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004710 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004711 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004712 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004713}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714
Paul Mooreeffad8d2008-01-29 08:49:27 -05004715static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4716 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004717 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004718{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004719 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004720 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004721 struct avc_audit_data ad;
4722 char *addrp;
4723 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004724
Paul Mooreeffad8d2008-01-29 08:49:27 -05004725 if (sk == NULL)
4726 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004727 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004728
Paul Moored8395c82008-10-10 10:16:30 -04004729 AVC_AUDIT_DATA_INIT(&ad, NET);
4730 ad.u.net.netif = ifindex;
4731 ad.u.net.family = family;
4732 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4733 return NF_DROP;
4734
Paul Mooreeffad8d2008-01-29 08:49:27 -05004735 if (selinux_compat_net) {
4736 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004737 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004738 return NF_DROP;
Paul Moore277d3422008-12-31 12:54:11 -05004739 } else if (selinux_secmark_enabled()) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004740 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004741 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004742 return NF_DROP;
4743 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004744
Paul Mooreeffad8d2008-01-29 08:49:27 -05004745 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004746 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004747 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004748
Paul Mooreeffad8d2008-01-29 08:49:27 -05004749 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750}
4751
Paul Mooreeffad8d2008-01-29 08:49:27 -05004752static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4753 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004755 u32 secmark_perm;
4756 u32 peer_sid;
4757 struct sock *sk;
4758 struct avc_audit_data ad;
4759 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004760 u8 secmark_active;
4761 u8 peerlbl_active;
4762
Paul Mooreeffad8d2008-01-29 08:49:27 -05004763 /* If any sort of compatibility mode is enabled then handoff processing
4764 * to the selinux_ip_postroute_compat() function to deal with the
4765 * special handling. We do this in an attempt to keep this function
4766 * as fast and as clean as possible. */
4767 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004768 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004769#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004770 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4771 * packet transformation so allow the packet to pass without any checks
4772 * since we'll have another chance to perform access control checks
4773 * when the packet is on it's final way out.
4774 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4775 * is NULL, in this case go ahead and apply access control. */
4776 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4777 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004778#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004779 secmark_active = selinux_secmark_enabled();
4780 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4781 if (!secmark_active && !peerlbl_active)
4782 return NF_ACCEPT;
4783
Paul Moored8395c82008-10-10 10:16:30 -04004784 /* if the packet is being forwarded then get the peer label from the
4785 * packet itself; otherwise check to see if it is from a local
4786 * application or the kernel, if from an application get the peer label
4787 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004788 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004789 if (sk == NULL) {
4790 switch (family) {
4791 case PF_INET:
4792 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4793 secmark_perm = PACKET__FORWARD_OUT;
4794 else
4795 secmark_perm = PACKET__SEND;
4796 break;
4797 case PF_INET6:
4798 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4799 secmark_perm = PACKET__FORWARD_OUT;
4800 else
4801 secmark_perm = PACKET__SEND;
4802 break;
4803 default:
4804 return NF_DROP;
4805 }
4806 if (secmark_perm == PACKET__FORWARD_OUT) {
4807 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4808 return NF_DROP;
4809 } else
4810 peer_sid = SECINITSID_KERNEL;
4811 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004812 struct sk_security_struct *sksec = sk->sk_security;
4813 peer_sid = sksec->sid;
4814 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004815 }
4816
Paul Moored8395c82008-10-10 10:16:30 -04004817 AVC_AUDIT_DATA_INIT(&ad, NET);
4818 ad.u.net.netif = ifindex;
4819 ad.u.net.family = family;
4820 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4821 return NF_DROP;
4822
Paul Mooreeffad8d2008-01-29 08:49:27 -05004823 if (secmark_active)
4824 if (avc_has_perm(peer_sid, skb->secmark,
4825 SECCLASS_PACKET, secmark_perm, &ad))
4826 return NF_DROP;
4827
4828 if (peerlbl_active) {
4829 u32 if_sid;
4830 u32 node_sid;
4831
4832 if (sel_netif_sid(ifindex, &if_sid))
4833 return NF_DROP;
4834 if (avc_has_perm(peer_sid, if_sid,
4835 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4836 return NF_DROP;
4837
4838 if (sel_netnode_sid(addrp, family, &node_sid))
4839 return NF_DROP;
4840 if (avc_has_perm(peer_sid, node_sid,
4841 SECCLASS_NODE, NODE__SENDTO, &ad))
4842 return NF_DROP;
4843 }
4844
4845 return NF_ACCEPT;
4846}
4847
4848static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4849 struct sk_buff *skb,
4850 const struct net_device *in,
4851 const struct net_device *out,
4852 int (*okfn)(struct sk_buff *))
4853{
4854 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855}
4856
4857#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004858static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4859 struct sk_buff *skb,
4860 const struct net_device *in,
4861 const struct net_device *out,
4862 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004864 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866#endif /* IPV6 */
4867
4868#endif /* CONFIG_NETFILTER */
4869
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4871{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 int err;
4873
4874 err = secondary_ops->netlink_send(sk, skb);
4875 if (err)
4876 return err;
4877
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4879 err = selinux_nlmsg_perm(sk, skb);
4880
4881 return err;
4882}
4883
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004884static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004886 int err;
4887 struct avc_audit_data ad;
4888
4889 err = secondary_ops->netlink_recv(skb, capability);
4890 if (err)
4891 return err;
4892
4893 AVC_AUDIT_DATA_INIT(&ad, CAP);
4894 ad.u.cap = capability;
4895
4896 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004897 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898}
4899
4900static int ipc_alloc_security(struct task_struct *task,
4901 struct kern_ipc_perm *perm,
4902 u16 sclass)
4903{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004905 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
James Morris89d155e2005-10-30 14:59:21 -08004907 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 if (!isec)
4909 return -ENOMEM;
4910
David Howells275bb412008-11-14 10:39:19 +11004911 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004913 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 perm->security = isec;
4915
4916 return 0;
4917}
4918
4919static void ipc_free_security(struct kern_ipc_perm *perm)
4920{
4921 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 perm->security = NULL;
4923 kfree(isec);
4924}
4925
4926static int msg_msg_alloc_security(struct msg_msg *msg)
4927{
4928 struct msg_security_struct *msec;
4929
James Morris89d155e2005-10-30 14:59:21 -08004930 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 if (!msec)
4932 return -ENOMEM;
4933
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 msec->sid = SECINITSID_UNLABELED;
4935 msg->security = msec;
4936
4937 return 0;
4938}
4939
4940static void msg_msg_free_security(struct msg_msg *msg)
4941{
4942 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943
4944 msg->security = NULL;
4945 kfree(msec);
4946}
4947
4948static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004949 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 struct ipc_security_struct *isec;
4952 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004953 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 isec = ipc_perms->security;
4956
4957 AVC_AUDIT_DATA_INIT(&ad, IPC);
4958 ad.u.ipc_id = ipc_perms->key;
4959
David Howells275bb412008-11-14 10:39:19 +11004960 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961}
4962
4963static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4964{
4965 return msg_msg_alloc_security(msg);
4966}
4967
4968static void selinux_msg_msg_free_security(struct msg_msg *msg)
4969{
4970 msg_msg_free_security(msg);
4971}
4972
4973/* message queue security operations */
4974static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4975{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 struct ipc_security_struct *isec;
4977 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004978 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 int rc;
4980
4981 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4982 if (rc)
4983 return rc;
4984
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 isec = msq->q_perm.security;
4986
4987 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004988 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
David Howells275bb412008-11-14 10:39:19 +11004990 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 MSGQ__CREATE, &ad);
4992 if (rc) {
4993 ipc_free_security(&msq->q_perm);
4994 return rc;
4995 }
4996 return 0;
4997}
4998
4999static void selinux_msg_queue_free_security(struct msg_queue *msq)
5000{
5001 ipc_free_security(&msq->q_perm);
5002}
5003
5004static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
5005{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 struct ipc_security_struct *isec;
5007 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005008 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 isec = msq->q_perm.security;
5011
5012 AVC_AUDIT_DATA_INIT(&ad, IPC);
5013 ad.u.ipc_id = msq->q_perm.key;
5014
David Howells275bb412008-11-14 10:39:19 +11005015 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 MSGQ__ASSOCIATE, &ad);
5017}
5018
5019static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
5020{
5021 int err;
5022 int perms;
5023
Eric Paris828dfe12008-04-17 13:17:49 -04005024 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 case IPC_INFO:
5026 case MSG_INFO:
5027 /* No specific object, just general system-wide information. */
5028 return task_has_system(current, SYSTEM__IPC_INFO);
5029 case IPC_STAT:
5030 case MSG_STAT:
5031 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
5032 break;
5033 case IPC_SET:
5034 perms = MSGQ__SETATTR;
5035 break;
5036 case IPC_RMID:
5037 perms = MSGQ__DESTROY;
5038 break;
5039 default:
5040 return 0;
5041 }
5042
Stephen Smalley6af963f2005-05-01 08:58:39 -07005043 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 return err;
5045}
5046
5047static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
5048{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 struct ipc_security_struct *isec;
5050 struct msg_security_struct *msec;
5051 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005052 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 int rc;
5054
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 isec = msq->q_perm.security;
5056 msec = msg->security;
5057
5058 /*
5059 * First time through, need to assign label to the message
5060 */
5061 if (msec->sid == SECINITSID_UNLABELED) {
5062 /*
5063 * Compute new sid based on current process and
5064 * message queue this message will be stored in
5065 */
David Howells275bb412008-11-14 10:39:19 +11005066 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 &msec->sid);
5068 if (rc)
5069 return rc;
5070 }
5071
5072 AVC_AUDIT_DATA_INIT(&ad, IPC);
5073 ad.u.ipc_id = msq->q_perm.key;
5074
5075 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005076 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 MSGQ__WRITE, &ad);
5078 if (!rc)
5079 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005080 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5081 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 if (!rc)
5083 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005084 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5085 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086
5087 return rc;
5088}
5089
5090static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5091 struct task_struct *target,
5092 long type, int mode)
5093{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 struct ipc_security_struct *isec;
5095 struct msg_security_struct *msec;
5096 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005097 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 int rc;
5099
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 isec = msq->q_perm.security;
5101 msec = msg->security;
5102
5103 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005104 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105
David Howells275bb412008-11-14 10:39:19 +11005106 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 SECCLASS_MSGQ, MSGQ__READ, &ad);
5108 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005109 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 SECCLASS_MSG, MSG__RECEIVE, &ad);
5111 return rc;
5112}
5113
5114/* Shared Memory security operations */
5115static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5116{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 struct ipc_security_struct *isec;
5118 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005119 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 int rc;
5121
5122 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5123 if (rc)
5124 return rc;
5125
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 isec = shp->shm_perm.security;
5127
5128 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005129 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130
David Howells275bb412008-11-14 10:39:19 +11005131 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 SHM__CREATE, &ad);
5133 if (rc) {
5134 ipc_free_security(&shp->shm_perm);
5135 return rc;
5136 }
5137 return 0;
5138}
5139
5140static void selinux_shm_free_security(struct shmid_kernel *shp)
5141{
5142 ipc_free_security(&shp->shm_perm);
5143}
5144
5145static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5146{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 struct ipc_security_struct *isec;
5148 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005149 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 isec = shp->shm_perm.security;
5152
5153 AVC_AUDIT_DATA_INIT(&ad, IPC);
5154 ad.u.ipc_id = shp->shm_perm.key;
5155
David Howells275bb412008-11-14 10:39:19 +11005156 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 SHM__ASSOCIATE, &ad);
5158}
5159
5160/* Note, at this point, shp is locked down */
5161static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5162{
5163 int perms;
5164 int err;
5165
Eric Paris828dfe12008-04-17 13:17:49 -04005166 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 case IPC_INFO:
5168 case SHM_INFO:
5169 /* No specific object, just general system-wide information. */
5170 return task_has_system(current, SYSTEM__IPC_INFO);
5171 case IPC_STAT:
5172 case SHM_STAT:
5173 perms = SHM__GETATTR | SHM__ASSOCIATE;
5174 break;
5175 case IPC_SET:
5176 perms = SHM__SETATTR;
5177 break;
5178 case SHM_LOCK:
5179 case SHM_UNLOCK:
5180 perms = SHM__LOCK;
5181 break;
5182 case IPC_RMID:
5183 perms = SHM__DESTROY;
5184 break;
5185 default:
5186 return 0;
5187 }
5188
Stephen Smalley6af963f2005-05-01 08:58:39 -07005189 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 return err;
5191}
5192
5193static int selinux_shm_shmat(struct shmid_kernel *shp,
5194 char __user *shmaddr, int shmflg)
5195{
5196 u32 perms;
5197 int rc;
5198
5199 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5200 if (rc)
5201 return rc;
5202
5203 if (shmflg & SHM_RDONLY)
5204 perms = SHM__READ;
5205 else
5206 perms = SHM__READ | SHM__WRITE;
5207
Stephen Smalley6af963f2005-05-01 08:58:39 -07005208 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209}
5210
5211/* Semaphore security operations */
5212static int selinux_sem_alloc_security(struct sem_array *sma)
5213{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 struct ipc_security_struct *isec;
5215 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005216 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 int rc;
5218
5219 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5220 if (rc)
5221 return rc;
5222
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 isec = sma->sem_perm.security;
5224
5225 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005226 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227
David Howells275bb412008-11-14 10:39:19 +11005228 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 SEM__CREATE, &ad);
5230 if (rc) {
5231 ipc_free_security(&sma->sem_perm);
5232 return rc;
5233 }
5234 return 0;
5235}
5236
5237static void selinux_sem_free_security(struct sem_array *sma)
5238{
5239 ipc_free_security(&sma->sem_perm);
5240}
5241
5242static int selinux_sem_associate(struct sem_array *sma, int semflg)
5243{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 struct ipc_security_struct *isec;
5245 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005246 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 isec = sma->sem_perm.security;
5249
5250 AVC_AUDIT_DATA_INIT(&ad, IPC);
5251 ad.u.ipc_id = sma->sem_perm.key;
5252
David Howells275bb412008-11-14 10:39:19 +11005253 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 SEM__ASSOCIATE, &ad);
5255}
5256
5257/* Note, at this point, sma is locked down */
5258static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5259{
5260 int err;
5261 u32 perms;
5262
Eric Paris828dfe12008-04-17 13:17:49 -04005263 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 case IPC_INFO:
5265 case SEM_INFO:
5266 /* No specific object, just general system-wide information. */
5267 return task_has_system(current, SYSTEM__IPC_INFO);
5268 case GETPID:
5269 case GETNCNT:
5270 case GETZCNT:
5271 perms = SEM__GETATTR;
5272 break;
5273 case GETVAL:
5274 case GETALL:
5275 perms = SEM__READ;
5276 break;
5277 case SETVAL:
5278 case SETALL:
5279 perms = SEM__WRITE;
5280 break;
5281 case IPC_RMID:
5282 perms = SEM__DESTROY;
5283 break;
5284 case IPC_SET:
5285 perms = SEM__SETATTR;
5286 break;
5287 case IPC_STAT:
5288 case SEM_STAT:
5289 perms = SEM__GETATTR | SEM__ASSOCIATE;
5290 break;
5291 default:
5292 return 0;
5293 }
5294
Stephen Smalley6af963f2005-05-01 08:58:39 -07005295 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 return err;
5297}
5298
5299static int selinux_sem_semop(struct sem_array *sma,
5300 struct sembuf *sops, unsigned nsops, int alter)
5301{
5302 u32 perms;
5303
5304 if (alter)
5305 perms = SEM__READ | SEM__WRITE;
5306 else
5307 perms = SEM__READ;
5308
Stephen Smalley6af963f2005-05-01 08:58:39 -07005309 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310}
5311
5312static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5313{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 u32 av = 0;
5315
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 av = 0;
5317 if (flag & S_IRUGO)
5318 av |= IPC__UNIX_READ;
5319 if (flag & S_IWUGO)
5320 av |= IPC__UNIX_WRITE;
5321
5322 if (av == 0)
5323 return 0;
5324
Stephen Smalley6af963f2005-05-01 08:58:39 -07005325 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326}
5327
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02005328static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5329{
5330 struct ipc_security_struct *isec = ipcp->security;
5331 *secid = isec->sid;
5332}
5333
Eric Paris828dfe12008-04-17 13:17:49 -04005334static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335{
5336 if (inode)
5337 inode_doinit_with_dentry(inode, dentry);
5338}
5339
5340static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005341 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342{
David Howells275bb412008-11-14 10:39:19 +11005343 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005344 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005346 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347
5348 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005349 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 if (error)
5351 return error;
5352 }
5353
David Howells275bb412008-11-14 10:39:19 +11005354 rcu_read_lock();
5355 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356
5357 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005358 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005360 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005362 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005364 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005365 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005366 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005367 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005368 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 else
David Howells275bb412008-11-14 10:39:19 +11005370 goto invalid;
5371 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372
5373 if (!sid)
5374 return 0;
5375
Al Viro04ff9702007-03-12 16:17:58 +00005376 error = security_sid_to_context(sid, value, &len);
5377 if (error)
5378 return error;
5379 return len;
David Howells275bb412008-11-14 10:39:19 +11005380
5381invalid:
5382 rcu_read_unlock();
5383 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384}
5385
5386static int selinux_setprocattr(struct task_struct *p,
5387 char *name, void *value, size_t size)
5388{
5389 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005390 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005391 struct cred *new;
5392 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 int error;
5394 char *str = value;
5395
5396 if (current != p) {
5397 /* SELinux only allows a process to change its own
5398 security attributes. */
5399 return -EACCES;
5400 }
5401
5402 /*
5403 * Basic control over ability to set these attributes at all.
5404 * current == p, but we'll pass them separately in case the
5405 * above restriction is ever removed.
5406 */
5407 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005408 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005410 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005411 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005412 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005413 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005414 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005416 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 else
5418 error = -EINVAL;
5419 if (error)
5420 return error;
5421
5422 /* Obtain a SID for the context, if one was specified. */
5423 if (size && str[1] && str[1] != '\n') {
5424 if (str[size-1] == '\n') {
5425 str[size-1] = 0;
5426 size--;
5427 }
5428 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005429 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5430 if (!capable(CAP_MAC_ADMIN))
5431 return error;
5432 error = security_context_to_sid_force(value, size,
5433 &sid);
5434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 if (error)
5436 return error;
5437 }
5438
David Howellsd84f4f92008-11-14 10:39:23 +11005439 new = prepare_creds();
5440 if (!new)
5441 return -ENOMEM;
5442
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 /* Permission checking based on the specified context is
5444 performed during the actual operation (execve,
5445 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005446 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 checks and may_create for the file creation checks. The
5448 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005449 tsec = new->security;
5450 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005452 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005454 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005455 error = may_create_key(sid, p);
5456 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005457 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005458 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005459 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005460 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005461 } else if (!strcmp(name, "current")) {
5462 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005464 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005465
David Howellsd84f4f92008-11-14 10:39:23 +11005466 /* Only allow single threaded processes to change context */
5467 error = -EPERM;
5468 if (!is_single_threaded(p)) {
5469 error = security_bounded_transition(tsec->sid, sid);
5470 if (error)
5471 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473
5474 /* Check permissions for the transition. */
5475 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005476 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005478 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
5480 /* Check for ptracing, and update the task SID if ok.
5481 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005482 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005484 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005485 if (tracer)
5486 ptsid = task_sid(tracer);
5487 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
David Howellsd84f4f92008-11-14 10:39:23 +11005489 if (tracer) {
5490 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5491 PROCESS__PTRACE, NULL);
5492 if (error)
5493 goto abort_change;
5494 }
5495
5496 tsec->sid = sid;
5497 } else {
5498 error = -EINVAL;
5499 goto abort_change;
5500 }
5501
5502 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005504
5505abort_change:
5506 abort_creds(new);
5507 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508}
5509
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005510static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5511{
5512 return security_sid_to_context(secid, secdata, seclen);
5513}
5514
David Howells7bf570d2008-04-29 20:52:51 +01005515static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005516{
5517 return security_context_to_sid(secdata, seclen, secid);
5518}
5519
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005520static void selinux_release_secctx(char *secdata, u32 seclen)
5521{
Paul Moore088999e2007-08-01 11:12:58 -04005522 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005523}
5524
Michael LeMayd7200242006-06-22 14:47:17 -07005525#ifdef CONFIG_KEYS
5526
David Howellsd84f4f92008-11-14 10:39:23 +11005527static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005528 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005529{
David Howellsd84f4f92008-11-14 10:39:23 +11005530 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005531 struct key_security_struct *ksec;
5532
5533 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5534 if (!ksec)
5535 return -ENOMEM;
5536
David Howellsd84f4f92008-11-14 10:39:23 +11005537 tsec = cred->security;
5538 if (tsec->keycreate_sid)
5539 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005540 else
David Howellsd84f4f92008-11-14 10:39:23 +11005541 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005542
David Howells275bb412008-11-14 10:39:19 +11005543 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005544 return 0;
5545}
5546
5547static void selinux_key_free(struct key *k)
5548{
5549 struct key_security_struct *ksec = k->security;
5550
5551 k->security = NULL;
5552 kfree(ksec);
5553}
5554
5555static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005556 const struct cred *cred,
5557 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005558{
5559 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005560 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005561 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005562
5563 /* if no specific permissions are requested, we skip the
5564 permission check. No serious, additional covert channels
5565 appear to be created. */
5566 if (perm == 0)
5567 return 0;
5568
David Howellsd84f4f92008-11-14 10:39:23 +11005569 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005570
5571 key = key_ref_to_ptr(key_ref);
5572 ksec = key->security;
5573
5574 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005575}
5576
David Howells70a5bb72008-04-29 01:01:26 -07005577static int selinux_key_getsecurity(struct key *key, char **_buffer)
5578{
5579 struct key_security_struct *ksec = key->security;
5580 char *context = NULL;
5581 unsigned len;
5582 int rc;
5583
5584 rc = security_sid_to_context(ksec->sid, &context, &len);
5585 if (!rc)
5586 rc = len;
5587 *_buffer = context;
5588 return rc;
5589}
5590
Michael LeMayd7200242006-06-22 14:47:17 -07005591#endif
5592
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005594 .name = "selinux",
5595
David Howells5cd9c582008-08-14 11:37:28 +01005596 .ptrace_may_access = selinux_ptrace_may_access,
5597 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005599 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 .sysctl = selinux_sysctl,
5601 .capable = selinux_capable,
5602 .quotactl = selinux_quotactl,
5603 .quota_on = selinux_quota_on,
5604 .syslog = selinux_syslog,
5605 .vm_enough_memory = selinux_vm_enough_memory,
5606
5607 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005608 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609
David Howellsa6f76f22008-11-14 10:39:24 +11005610 .bprm_set_creds = selinux_bprm_set_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 .bprm_check_security = selinux_bprm_check_security,
David Howellsa6f76f22008-11-14 10:39:24 +11005612 .bprm_committing_creds = selinux_bprm_committing_creds,
5613 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 .bprm_secureexec = selinux_bprm_secureexec,
5615
5616 .sb_alloc_security = selinux_sb_alloc_security,
5617 .sb_free_security = selinux_sb_free_security,
5618 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005619 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005620 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 .sb_statfs = selinux_sb_statfs,
5622 .sb_mount = selinux_mount,
5623 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005624 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005625 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005626 .sb_parse_opts_str = selinux_parse_opts_str,
5627
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628
5629 .inode_alloc_security = selinux_inode_alloc_security,
5630 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005631 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 .inode_unlink = selinux_inode_unlink,
5635 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .inode_rmdir = selinux_inode_rmdir,
5638 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 .inode_readlink = selinux_inode_readlink,
5641 .inode_follow_link = selinux_inode_follow_link,
5642 .inode_permission = selinux_inode_permission,
5643 .inode_setattr = selinux_inode_setattr,
5644 .inode_getattr = selinux_inode_getattr,
5645 .inode_setxattr = selinux_inode_setxattr,
5646 .inode_post_setxattr = selinux_inode_post_setxattr,
5647 .inode_getxattr = selinux_inode_getxattr,
5648 .inode_listxattr = selinux_inode_listxattr,
5649 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005650 .inode_getsecurity = selinux_inode_getsecurity,
5651 .inode_setsecurity = selinux_inode_setsecurity,
5652 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005653 .inode_need_killpriv = selinux_inode_need_killpriv,
5654 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005655 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656
5657 .file_permission = selinux_file_permission,
5658 .file_alloc_security = selinux_file_alloc_security,
5659 .file_free_security = selinux_file_free_security,
5660 .file_ioctl = selinux_file_ioctl,
5661 .file_mmap = selinux_file_mmap,
5662 .file_mprotect = selinux_file_mprotect,
5663 .file_lock = selinux_file_lock,
5664 .file_fcntl = selinux_file_fcntl,
5665 .file_set_fowner = selinux_file_set_fowner,
5666 .file_send_sigiotask = selinux_file_send_sigiotask,
5667 .file_receive = selinux_file_receive,
5668
Eric Paris828dfe12008-04-17 13:17:49 -04005669 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005670
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005672 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005673 .cred_prepare = selinux_cred_prepare,
5674 .cred_commit = selinux_cred_commit,
David Howells3a3b7ce2008-11-14 10:39:28 +11005675 .kernel_act_as = selinux_kernel_act_as,
5676 .kernel_create_files_as = selinux_kernel_create_files_as,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005678 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 .task_setgid = selinux_task_setgid,
5680 .task_setpgid = selinux_task_setpgid,
5681 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005682 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005683 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 .task_setgroups = selinux_task_setgroups,
5685 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005686 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005687 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 .task_setrlimit = selinux_task_setrlimit,
5689 .task_setscheduler = selinux_task_setscheduler,
5690 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005691 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 .task_kill = selinux_task_kill,
5693 .task_wait = selinux_task_wait,
5694 .task_prctl = selinux_task_prctl,
Eric Paris828dfe12008-04-17 13:17:49 -04005695 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696
5697 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005698 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699
5700 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5701 .msg_msg_free_security = selinux_msg_msg_free_security,
5702
5703 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5704 .msg_queue_free_security = selinux_msg_queue_free_security,
5705 .msg_queue_associate = selinux_msg_queue_associate,
5706 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5707 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5708 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5709
5710 .shm_alloc_security = selinux_shm_alloc_security,
5711 .shm_free_security = selinux_shm_free_security,
5712 .shm_associate = selinux_shm_associate,
5713 .shm_shmctl = selinux_shm_shmctl,
5714 .shm_shmat = selinux_shm_shmat,
5715
Eric Paris828dfe12008-04-17 13:17:49 -04005716 .sem_alloc_security = selinux_sem_alloc_security,
5717 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718 .sem_associate = selinux_sem_associate,
5719 .sem_semctl = selinux_sem_semctl,
5720 .sem_semop = selinux_sem_semop,
5721
Eric Paris828dfe12008-04-17 13:17:49 -04005722 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
Eric Paris828dfe12008-04-17 13:17:49 -04005724 .getprocattr = selinux_getprocattr,
5725 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005727 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005728 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005729 .release_secctx = selinux_release_secctx,
5730
Eric Paris828dfe12008-04-17 13:17:49 -04005731 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 .unix_may_send = selinux_socket_unix_may_send,
5733
5734 .socket_create = selinux_socket_create,
5735 .socket_post_create = selinux_socket_post_create,
5736 .socket_bind = selinux_socket_bind,
5737 .socket_connect = selinux_socket_connect,
5738 .socket_listen = selinux_socket_listen,
5739 .socket_accept = selinux_socket_accept,
5740 .socket_sendmsg = selinux_socket_sendmsg,
5741 .socket_recvmsg = selinux_socket_recvmsg,
5742 .socket_getsockname = selinux_socket_getsockname,
5743 .socket_getpeername = selinux_socket_getpeername,
5744 .socket_getsockopt = selinux_socket_getsockopt,
5745 .socket_setsockopt = selinux_socket_setsockopt,
5746 .socket_shutdown = selinux_socket_shutdown,
5747 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005748 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5749 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 .sk_alloc_security = selinux_sk_alloc_security,
5751 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005752 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005753 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005754 .sock_graft = selinux_sock_graft,
5755 .inet_conn_request = selinux_inet_conn_request,
5756 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005757 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005758 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005759
5760#ifdef CONFIG_SECURITY_NETWORK_XFRM
5761 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5762 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5763 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005764 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005765 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5766 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005767 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005768 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005769 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005770 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005772
5773#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005774 .key_alloc = selinux_key_alloc,
5775 .key_free = selinux_key_free,
5776 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005777 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005778#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005779
5780#ifdef CONFIG_AUDIT
5781 .audit_rule_init = selinux_audit_rule_init,
5782 .audit_rule_known = selinux_audit_rule_known,
5783 .audit_rule_match = selinux_audit_rule_match,
5784 .audit_rule_free = selinux_audit_rule_free,
5785#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786};
5787
5788static __init int selinux_init(void)
5789{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005790 if (!security_module_enable(&selinux_ops)) {
5791 selinux_enabled = 0;
5792 return 0;
5793 }
5794
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 if (!selinux_enabled) {
5796 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5797 return 0;
5798 }
5799
5800 printk(KERN_INFO "SELinux: Initializing.\n");
5801
5802 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005803 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804
James Morris7cae7e22006-03-22 00:09:22 -08005805 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5806 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005807 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808 avc_init();
5809
James Morris6f0f0fd2008-07-10 17:02:07 +09005810 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005812 panic("SELinux: No initial security operations\n");
5813 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814 panic("SELinux: Unable to register with kernel.\n");
5815
Eric Paris828dfe12008-04-17 13:17:49 -04005816 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005817 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005818 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005819 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005820
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 return 0;
5822}
5823
5824void selinux_complete_init(void)
5825{
Eric Parisfadcdb42007-02-22 18:11:31 -05005826 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827
5828 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005829 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005830 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 spin_lock(&sb_security_lock);
5832next_sb:
5833 if (!list_empty(&superblock_security_head)) {
5834 struct superblock_security_struct *sbsec =
5835 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005836 struct superblock_security_struct,
5837 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005841 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842 down_read(&sb->s_umount);
5843 if (sb->s_root)
5844 superblock_doinit(sb, NULL);
5845 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005846 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 spin_lock(&sb_security_lock);
5848 list_del_init(&sbsec->list);
5849 goto next_sb;
5850 }
5851 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005852 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853}
5854
5855/* SELinux requires early initialization in order to label
5856 all processes and objects when they are created. */
5857security_initcall(selinux_init);
5858
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005859#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860
Paul Mooreeffad8d2008-01-29 08:49:27 -05005861static struct nf_hook_ops selinux_ipv4_ops[] = {
5862 {
5863 .hook = selinux_ipv4_postroute,
5864 .owner = THIS_MODULE,
5865 .pf = PF_INET,
5866 .hooknum = NF_INET_POST_ROUTING,
5867 .priority = NF_IP_PRI_SELINUX_LAST,
5868 },
5869 {
5870 .hook = selinux_ipv4_forward,
5871 .owner = THIS_MODULE,
5872 .pf = PF_INET,
5873 .hooknum = NF_INET_FORWARD,
5874 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005875 },
5876 {
5877 .hook = selinux_ipv4_output,
5878 .owner = THIS_MODULE,
5879 .pf = PF_INET,
5880 .hooknum = NF_INET_LOCAL_OUT,
5881 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883};
5884
5885#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5886
Paul Mooreeffad8d2008-01-29 08:49:27 -05005887static struct nf_hook_ops selinux_ipv6_ops[] = {
5888 {
5889 .hook = selinux_ipv6_postroute,
5890 .owner = THIS_MODULE,
5891 .pf = PF_INET6,
5892 .hooknum = NF_INET_POST_ROUTING,
5893 .priority = NF_IP6_PRI_SELINUX_LAST,
5894 },
5895 {
5896 .hook = selinux_ipv6_forward,
5897 .owner = THIS_MODULE,
5898 .pf = PF_INET6,
5899 .hooknum = NF_INET_FORWARD,
5900 .priority = NF_IP6_PRI_SELINUX_FIRST,
5901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902};
5903
5904#endif /* IPV6 */
5905
5906static int __init selinux_nf_ip_init(void)
5907{
5908 int err = 0;
5909
5910 if (!selinux_enabled)
5911 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005912
5913 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5914
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005915 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5916 if (err)
5917 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918
5919#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005920 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5921 if (err)
5922 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005924
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925out:
5926 return err;
5927}
5928
5929__initcall(selinux_nf_ip_init);
5930
5931#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5932static void selinux_nf_ip_exit(void)
5933{
Eric Parisfadcdb42007-02-22 18:11:31 -05005934 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005936 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005938 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939#endif /* IPV6 */
5940}
5941#endif
5942
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005943#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944
5945#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5946#define selinux_nf_ip_exit()
5947#endif
5948
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005949#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
5951#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005952static int selinux_disabled;
5953
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954int selinux_disable(void)
5955{
5956 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957
5958 if (ss_initialized) {
5959 /* Not permitted after initial policy load. */
5960 return -EINVAL;
5961 }
5962
5963 if (selinux_disabled) {
5964 /* Only do this once. */
5965 return -EINVAL;
5966 }
5967
5968 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5969
5970 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005971 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972
5973 /* Reset security_ops to the secondary module, dummy or capability. */
5974 security_ops = secondary_ops;
5975
5976 /* Unregister netfilter hooks. */
5977 selinux_nf_ip_exit();
5978
5979 /* Unregister selinuxfs. */
5980 exit_sel_fs();
5981
5982 return 0;
5983}
5984#endif