blob: 3f3de565c24261e61f17dff2c72cc76a889f0407 [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
Eric Parisc9180a52007-11-30 13:00:35 -050092#define NUM_SEL_MNT_OPTS 4
93
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159/* Allocate and free functions for each kind of security blob. */
160
David Howellsf1752ee2008-11-14 10:39:17 +1100161static int cred_alloc_security(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 struct task_security_struct *tsec;
164
James Morris89d155e2005-10-30 14:59:21 -0800165 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 if (!tsec)
167 return -ENOMEM;
168
Roland McGrath03563572008-03-26 15:46:39 -0700169 tsec->osid = tsec->sid = SECINITSID_UNLABELED;
David Howellsf1752ee2008-11-14 10:39:17 +1100170 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 return 0;
173}
174
David Howells275bb412008-11-14 10:39:19 +1100175/*
176 * get the security ID of a task
177 */
178static inline u32 task_sid(const struct task_struct *task)
179{
180 const struct task_security_struct *tsec;
181 u32 sid;
182
183 rcu_read_lock();
184 tsec = __task_cred(task)->security;
185 sid = tsec->sid;
186 rcu_read_unlock();
187 return sid;
188}
189
190/*
191 * get the security ID of the current task
192 */
193static inline u32 current_sid(void)
194{
195 const struct task_security_struct *tsec = current_cred()->security;
196
197 return tsec->sid;
198}
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200static int inode_alloc_security(struct inode *inode)
201{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100203 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Josef Bacika02fe132008-04-04 09:35:05 +1100205 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (!isec)
207 return -ENOMEM;
208
Eric Paris23970742006-09-25 23:32:01 -0700209 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 isec->inode = inode;
212 isec->sid = SECINITSID_UNLABELED;
213 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100214 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 inode->i_security = isec;
216
217 return 0;
218}
219
220static void inode_free_security(struct inode *inode)
221{
222 struct inode_security_struct *isec = inode->i_security;
223 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 spin_lock(&sbsec->isec_lock);
226 if (!list_empty(&isec->list))
227 list_del_init(&isec->list);
228 spin_unlock(&sbsec->isec_lock);
229
230 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800231 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
233
234static int file_alloc_security(struct file *file)
235{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100237 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800239 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (!fsec)
241 return -ENOMEM;
242
David Howells275bb412008-11-14 10:39:19 +1100243 fsec->sid = sid;
244 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 file->f_security = fsec;
246
247 return 0;
248}
249
250static void file_free_security(struct file *file)
251{
252 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 file->f_security = NULL;
254 kfree(fsec);
255}
256
257static int superblock_alloc_security(struct super_block *sb)
258{
259 struct superblock_security_struct *sbsec;
260
James Morris89d155e2005-10-30 14:59:21 -0800261 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 if (!sbsec)
263 return -ENOMEM;
264
Eric Parisbc7e9822006-09-25 23:32:02 -0700265 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 INIT_LIST_HEAD(&sbsec->list);
267 INIT_LIST_HEAD(&sbsec->isec_head);
268 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sbsec->sb = sb;
270 sbsec->sid = SECINITSID_UNLABELED;
271 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700272 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 sb->s_security = sbsec;
274
275 return 0;
276}
277
278static void superblock_free_security(struct super_block *sb)
279{
280 struct superblock_security_struct *sbsec = sb->s_security;
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 spin_lock(&sb_security_lock);
283 if (!list_empty(&sbsec->list))
284 list_del_init(&sbsec->list);
285 spin_unlock(&sb_security_lock);
286
287 sb->s_security = NULL;
288 kfree(sbsec);
289}
290
Al Viro7d877f32005-10-21 03:20:43 -0400291static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
293 struct sk_security_struct *ssec;
294
James Morris89d155e2005-10-30 14:59:21 -0800295 ssec = kzalloc(sizeof(*ssec), priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if (!ssec)
297 return -ENOMEM;
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 ssec->peer_sid = SECINITSID_UNLABELED;
Venkat Yekkirala892c1412006-08-04 23:08:56 -0700300 ssec->sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 sk->sk_security = ssec;
302
Paul Mooref74af6e2008-02-25 11:40:33 -0500303 selinux_netlbl_sk_security_reset(ssec, family);
Paul Moore99f59ed2006-08-29 17:53:48 -0700304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return 0;
306}
307
308static void sk_free_security(struct sock *sk)
309{
310 struct sk_security_struct *ssec = sk->sk_security;
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 sk->sk_security = NULL;
Paul Moore6c5b3fc2008-10-10 10:16:33 -0400313 selinux_netlbl_sk_security_free(ssec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 kfree(ssec);
315}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317/* The security server must be initialized before
318 any labeling or access decisions can be provided. */
319extern int ss_initialized;
320
321/* The file system's label must be initialized prior to use. */
322
323static char *labeling_behaviors[6] = {
324 "uses xattr",
325 "uses transition SIDs",
326 "uses task SIDs",
327 "uses genfs_contexts",
328 "not configured for labeling",
329 "uses mountpoint labeling",
330};
331
332static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
333
334static inline int inode_doinit(struct inode *inode)
335{
336 return inode_doinit_with_dentry(inode, NULL);
337}
338
339enum {
Eric Paris31e87932007-09-19 17:19:12 -0400340 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 Opt_context = 1,
342 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500343 Opt_defcontext = 3,
344 Opt_rootcontext = 4,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345};
346
Steven Whitehousea447c092008-10-13 10:46:57 +0100347static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400348 {Opt_context, CONTEXT_STR "%s"},
349 {Opt_fscontext, FSCONTEXT_STR "%s"},
350 {Opt_defcontext, DEFCONTEXT_STR "%s"},
351 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
Eric Paris31e87932007-09-19 17:19:12 -0400352 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353};
354
355#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
356
Eric Parisc312feb2006-07-10 04:43:53 -0700357static int may_context_mount_sb_relabel(u32 sid,
358 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100359 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700360{
David Howells275bb412008-11-14 10:39:19 +1100361 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700362 int rc;
363
364 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
365 FILESYSTEM__RELABELFROM, NULL);
366 if (rc)
367 return rc;
368
369 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
370 FILESYSTEM__RELABELTO, NULL);
371 return rc;
372}
373
Eric Paris08089252006-07-10 04:43:55 -0700374static int may_context_mount_inode_relabel(u32 sid,
375 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100376 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700377{
David Howells275bb412008-11-14 10:39:19 +1100378 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700379 int rc;
380 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
381 FILESYSTEM__RELABELFROM, NULL);
382 if (rc)
383 return rc;
384
385 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
386 FILESYSTEM__ASSOCIATE, NULL);
387 return rc;
388}
389
Eric Parisc9180a52007-11-30 13:00:35 -0500390static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
392 struct superblock_security_struct *sbsec = sb->s_security;
393 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500394 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 int rc = 0;
396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
398 /* Make sure that the xattr handler exists and that no
399 error other than -ENODATA is returned by getxattr on
400 the root directory. -ENODATA is ok, as this may be
401 the first boot of the SELinux kernel before we have
402 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500403 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
405 "xattr support\n", sb->s_id, sb->s_type->name);
406 rc = -EOPNOTSUPP;
407 goto out;
408 }
Eric Parisc9180a52007-11-30 13:00:35 -0500409 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (rc < 0 && rc != -ENODATA) {
411 if (rc == -EOPNOTSUPP)
412 printk(KERN_WARNING "SELinux: (dev %s, type "
413 "%s) has no security xattr handler\n",
414 sb->s_id, sb->s_type->name);
415 else
416 printk(KERN_WARNING "SELinux: (dev %s, type "
417 "%s) getxattr errno %d\n", sb->s_id,
418 sb->s_type->name, -rc);
419 goto out;
420 }
421 }
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 sbsec->initialized = 1;
424
Eric Parisc9180a52007-11-30 13:00:35 -0500425 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500426 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500428 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500429 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 sb->s_id, sb->s_type->name,
431 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500434 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 /* Initialize any other inodes associated with the superblock, e.g.
437 inodes created prior to initial policy load or inodes created
438 during get_sb by a pseudo filesystem that directly
439 populates itself. */
440 spin_lock(&sbsec->isec_lock);
441next_inode:
442 if (!list_empty(&sbsec->isec_head)) {
443 struct inode_security_struct *isec =
444 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500445 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 struct inode *inode = isec->inode;
447 spin_unlock(&sbsec->isec_lock);
448 inode = igrab(inode);
449 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500450 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 inode_doinit(inode);
452 iput(inode);
453 }
454 spin_lock(&sbsec->isec_lock);
455 list_del_init(&isec->list);
456 goto next_inode;
457 }
458 spin_unlock(&sbsec->isec_lock);
459out:
Eric Parisc9180a52007-11-30 13:00:35 -0500460 return rc;
461}
462
463/*
464 * This function should allow an FS to ask what it's mount security
465 * options were so it can use those later for submounts, displaying
466 * mount options, or whatever.
467 */
468static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500469 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500470{
471 int rc = 0, i;
472 struct superblock_security_struct *sbsec = sb->s_security;
473 char *context = NULL;
474 u32 len;
475 char tmp;
476
Eric Parise0007522008-03-05 10:31:54 -0500477 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500478
479 if (!sbsec->initialized)
480 return -EINVAL;
481
482 if (!ss_initialized)
483 return -EINVAL;
484
485 /*
486 * if we ever use sbsec flags for anything other than tracking mount
487 * settings this is going to need a mask
488 */
489 tmp = sbsec->flags;
490 /* count the number of mount options for this sb */
491 for (i = 0; i < 8; i++) {
492 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500493 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500494 tmp >>= 1;
495 }
496
Eric Parise0007522008-03-05 10:31:54 -0500497 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
498 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500499 rc = -ENOMEM;
500 goto out_free;
501 }
502
Eric Parise0007522008-03-05 10:31:54 -0500503 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
504 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500505 rc = -ENOMEM;
506 goto out_free;
507 }
508
509 i = 0;
510 if (sbsec->flags & FSCONTEXT_MNT) {
511 rc = security_sid_to_context(sbsec->sid, &context, &len);
512 if (rc)
513 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500514 opts->mnt_opts[i] = context;
515 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500516 }
517 if (sbsec->flags & CONTEXT_MNT) {
518 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
519 if (rc)
520 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500521 opts->mnt_opts[i] = context;
522 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500523 }
524 if (sbsec->flags & DEFCONTEXT_MNT) {
525 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
526 if (rc)
527 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500528 opts->mnt_opts[i] = context;
529 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500530 }
531 if (sbsec->flags & ROOTCONTEXT_MNT) {
532 struct inode *root = sbsec->sb->s_root->d_inode;
533 struct inode_security_struct *isec = root->i_security;
534
535 rc = security_sid_to_context(isec->sid, &context, &len);
536 if (rc)
537 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500538 opts->mnt_opts[i] = context;
539 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500540 }
541
Eric Parise0007522008-03-05 10:31:54 -0500542 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500543
544 return 0;
545
546out_free:
Eric Parise0007522008-03-05 10:31:54 -0500547 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500548 return rc;
549}
550
551static int bad_option(struct superblock_security_struct *sbsec, char flag,
552 u32 old_sid, u32 new_sid)
553{
554 /* check if the old mount command had the same options */
555 if (sbsec->initialized)
556 if (!(sbsec->flags & flag) ||
557 (old_sid != new_sid))
558 return 1;
559
560 /* check if we were passed the same options twice,
561 * aka someone passed context=a,context=b
562 */
563 if (!sbsec->initialized)
564 if (sbsec->flags & flag)
565 return 1;
566 return 0;
567}
Eric Parise0007522008-03-05 10:31:54 -0500568
Eric Parisc9180a52007-11-30 13:00:35 -0500569/*
570 * Allow filesystems with binary mount data to explicitly set mount point
571 * labeling information.
572 */
Eric Parise0007522008-03-05 10:31:54 -0500573static int selinux_set_mnt_opts(struct super_block *sb,
574 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500575{
David Howells275bb412008-11-14 10:39:19 +1100576 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500577 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500578 struct superblock_security_struct *sbsec = sb->s_security;
579 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000580 struct inode *inode = sbsec->sb->s_root->d_inode;
581 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500582 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
583 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500584 char **mount_options = opts->mnt_opts;
585 int *flags = opts->mnt_opts_flags;
586 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500587
588 mutex_lock(&sbsec->lock);
589
590 if (!ss_initialized) {
591 if (!num_opts) {
592 /* Defer initialization until selinux_complete_init,
593 after the initial policy is loaded and the security
594 server is ready to handle calls. */
595 spin_lock(&sb_security_lock);
596 if (list_empty(&sbsec->list))
597 list_add(&sbsec->list, &superblock_security_head);
598 spin_unlock(&sb_security_lock);
599 goto out;
600 }
601 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400602 printk(KERN_WARNING "SELinux: Unable to set superblock options "
603 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500604 goto out;
605 }
606
607 /*
Eric Parise0007522008-03-05 10:31:54 -0500608 * Binary mount data FS will come through this function twice. Once
609 * from an explicit call and once from the generic calls from the vfs.
610 * Since the generic VFS calls will not contain any security mount data
611 * we need to skip the double mount verification.
612 *
613 * This does open a hole in which we will not notice if the first
614 * mount using this sb set explict options and a second mount using
615 * this sb does not set any security options. (The first options
616 * will be used for both mounts)
617 */
618 if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
619 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400620 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500621
622 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500623 * parse the mount options, check if they are valid sids.
624 * also check if someone is trying to mount the same sb more
625 * than once with different security options.
626 */
627 for (i = 0; i < num_opts; i++) {
628 u32 sid;
629 rc = security_context_to_sid(mount_options[i],
630 strlen(mount_options[i]), &sid);
631 if (rc) {
632 printk(KERN_WARNING "SELinux: security_context_to_sid"
633 "(%s) failed for (dev %s, type %s) errno=%d\n",
634 mount_options[i], sb->s_id, name, rc);
635 goto out;
636 }
637 switch (flags[i]) {
638 case FSCONTEXT_MNT:
639 fscontext_sid = sid;
640
641 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
642 fscontext_sid))
643 goto out_double_mount;
644
645 sbsec->flags |= FSCONTEXT_MNT;
646 break;
647 case CONTEXT_MNT:
648 context_sid = sid;
649
650 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
651 context_sid))
652 goto out_double_mount;
653
654 sbsec->flags |= CONTEXT_MNT;
655 break;
656 case ROOTCONTEXT_MNT:
657 rootcontext_sid = sid;
658
659 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
660 rootcontext_sid))
661 goto out_double_mount;
662
663 sbsec->flags |= ROOTCONTEXT_MNT;
664
665 break;
666 case DEFCONTEXT_MNT:
667 defcontext_sid = sid;
668
669 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
670 defcontext_sid))
671 goto out_double_mount;
672
673 sbsec->flags |= DEFCONTEXT_MNT;
674
675 break;
676 default:
677 rc = -EINVAL;
678 goto out;
679 }
680 }
681
682 if (sbsec->initialized) {
683 /* previously mounted with options, but not on this attempt? */
684 if (sbsec->flags && !num_opts)
685 goto out_double_mount;
686 rc = 0;
687 goto out;
688 }
689
James Morris089be432008-07-15 18:32:49 +1000690 if (strcmp(sb->s_type->name, "proc") == 0)
Eric Parisc9180a52007-11-30 13:00:35 -0500691 sbsec->proc = 1;
692
693 /* Determine the labeling behavior to use for this filesystem type. */
James Morris089be432008-07-15 18:32:49 +1000694 rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500695 if (rc) {
696 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000697 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500698 goto out;
699 }
700
701 /* sets the context of the superblock for the fs being mounted. */
702 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100703 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500704 if (rc)
705 goto out;
706
707 sbsec->sid = fscontext_sid;
708 }
709
710 /*
711 * Switch to using mount point labeling behavior.
712 * sets the label used on all file below the mountpoint, and will set
713 * the superblock context if not already set.
714 */
715 if (context_sid) {
716 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100717 rc = may_context_mount_sb_relabel(context_sid, sbsec,
718 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500719 if (rc)
720 goto out;
721 sbsec->sid = context_sid;
722 } else {
David Howells275bb412008-11-14 10:39:19 +1100723 rc = may_context_mount_inode_relabel(context_sid, sbsec,
724 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500725 if (rc)
726 goto out;
727 }
728 if (!rootcontext_sid)
729 rootcontext_sid = context_sid;
730
731 sbsec->mntpoint_sid = context_sid;
732 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
733 }
734
735 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100736 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
737 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500738 if (rc)
739 goto out;
740
741 root_isec->sid = rootcontext_sid;
742 root_isec->initialized = 1;
743 }
744
745 if (defcontext_sid) {
746 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
747 rc = -EINVAL;
748 printk(KERN_WARNING "SELinux: defcontext option is "
749 "invalid for this filesystem type\n");
750 goto out;
751 }
752
753 if (defcontext_sid != sbsec->def_sid) {
754 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100755 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500756 if (rc)
757 goto out;
758 }
759
760 sbsec->def_sid = defcontext_sid;
761 }
762
763 rc = sb_finish_set_opts(sb);
764out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700765 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500767out_double_mount:
768 rc = -EINVAL;
769 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
770 "security settings for (dev %s, type %s)\n", sb->s_id, name);
771 goto out;
772}
773
774static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
775 struct super_block *newsb)
776{
777 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
778 struct superblock_security_struct *newsbsec = newsb->s_security;
779
780 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
781 int set_context = (oldsbsec->flags & CONTEXT_MNT);
782 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
783
Eric Paris0f5e6422008-04-21 16:24:11 -0400784 /*
785 * if the parent was able to be mounted it clearly had no special lsm
786 * mount options. thus we can safely put this sb on the list and deal
787 * with it later
788 */
789 if (!ss_initialized) {
790 spin_lock(&sb_security_lock);
791 if (list_empty(&newsbsec->list))
792 list_add(&newsbsec->list, &superblock_security_head);
793 spin_unlock(&sb_security_lock);
794 return;
795 }
Eric Parisc9180a52007-11-30 13:00:35 -0500796
Eric Parisc9180a52007-11-30 13:00:35 -0500797 /* how can we clone if the old one wasn't set up?? */
798 BUG_ON(!oldsbsec->initialized);
799
Eric Paris5a552612008-04-09 14:08:35 -0400800 /* if fs is reusing a sb, just let its options stand... */
801 if (newsbsec->initialized)
802 return;
803
Eric Parisc9180a52007-11-30 13:00:35 -0500804 mutex_lock(&newsbsec->lock);
805
806 newsbsec->flags = oldsbsec->flags;
807
808 newsbsec->sid = oldsbsec->sid;
809 newsbsec->def_sid = oldsbsec->def_sid;
810 newsbsec->behavior = oldsbsec->behavior;
811
812 if (set_context) {
813 u32 sid = oldsbsec->mntpoint_sid;
814
815 if (!set_fscontext)
816 newsbsec->sid = sid;
817 if (!set_rootcontext) {
818 struct inode *newinode = newsb->s_root->d_inode;
819 struct inode_security_struct *newisec = newinode->i_security;
820 newisec->sid = sid;
821 }
822 newsbsec->mntpoint_sid = sid;
823 }
824 if (set_rootcontext) {
825 const struct inode *oldinode = oldsb->s_root->d_inode;
826 const struct inode_security_struct *oldisec = oldinode->i_security;
827 struct inode *newinode = newsb->s_root->d_inode;
828 struct inode_security_struct *newisec = newinode->i_security;
829
830 newisec->sid = oldisec->sid;
831 }
832
833 sb_finish_set_opts(newsb);
834 mutex_unlock(&newsbsec->lock);
835}
836
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200837static int selinux_parse_opts_str(char *options,
838 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500839{
Eric Parise0007522008-03-05 10:31:54 -0500840 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500841 char *context = NULL, *defcontext = NULL;
842 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500843 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500844
Eric Parise0007522008-03-05 10:31:54 -0500845 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500846
847 /* Standard string-based options. */
848 while ((p = strsep(&options, "|")) != NULL) {
849 int token;
850 substring_t args[MAX_OPT_ARGS];
851
852 if (!*p)
853 continue;
854
855 token = match_token(p, tokens, args);
856
857 switch (token) {
858 case Opt_context:
859 if (context || defcontext) {
860 rc = -EINVAL;
861 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
862 goto out_err;
863 }
864 context = match_strdup(&args[0]);
865 if (!context) {
866 rc = -ENOMEM;
867 goto out_err;
868 }
869 break;
870
871 case Opt_fscontext:
872 if (fscontext) {
873 rc = -EINVAL;
874 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
875 goto out_err;
876 }
877 fscontext = match_strdup(&args[0]);
878 if (!fscontext) {
879 rc = -ENOMEM;
880 goto out_err;
881 }
882 break;
883
884 case Opt_rootcontext:
885 if (rootcontext) {
886 rc = -EINVAL;
887 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
888 goto out_err;
889 }
890 rootcontext = match_strdup(&args[0]);
891 if (!rootcontext) {
892 rc = -ENOMEM;
893 goto out_err;
894 }
895 break;
896
897 case Opt_defcontext:
898 if (context || defcontext) {
899 rc = -EINVAL;
900 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
901 goto out_err;
902 }
903 defcontext = match_strdup(&args[0]);
904 if (!defcontext) {
905 rc = -ENOMEM;
906 goto out_err;
907 }
908 break;
909
910 default:
911 rc = -EINVAL;
912 printk(KERN_WARNING "SELinux: unknown mount option\n");
913 goto out_err;
914
915 }
916 }
917
Eric Parise0007522008-03-05 10:31:54 -0500918 rc = -ENOMEM;
919 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
920 if (!opts->mnt_opts)
921 goto out_err;
922
923 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
924 if (!opts->mnt_opts_flags) {
925 kfree(opts->mnt_opts);
926 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500927 }
928
Eric Parise0007522008-03-05 10:31:54 -0500929 if (fscontext) {
930 opts->mnt_opts[num_mnt_opts] = fscontext;
931 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
932 }
933 if (context) {
934 opts->mnt_opts[num_mnt_opts] = context;
935 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
936 }
937 if (rootcontext) {
938 opts->mnt_opts[num_mnt_opts] = rootcontext;
939 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
940 }
941 if (defcontext) {
942 opts->mnt_opts[num_mnt_opts] = defcontext;
943 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
944 }
945
946 opts->num_mnt_opts = num_mnt_opts;
947 return 0;
948
Eric Parisc9180a52007-11-30 13:00:35 -0500949out_err:
950 kfree(context);
951 kfree(defcontext);
952 kfree(fscontext);
953 kfree(rootcontext);
954 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955}
Eric Parise0007522008-03-05 10:31:54 -0500956/*
957 * string mount options parsing and call set the sbsec
958 */
959static int superblock_doinit(struct super_block *sb, void *data)
960{
961 int rc = 0;
962 char *options = data;
963 struct security_mnt_opts opts;
964
965 security_init_mnt_opts(&opts);
966
967 if (!data)
968 goto out;
969
970 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
971
972 rc = selinux_parse_opts_str(options, &opts);
973 if (rc)
974 goto out_err;
975
976out:
977 rc = selinux_set_mnt_opts(sb, &opts);
978
979out_err:
980 security_free_mnt_opts(&opts);
981 return rc;
982}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Adrian Bunk3583a712008-07-22 20:21:23 +0300984static void selinux_write_opts(struct seq_file *m,
985 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000986{
987 int i;
988 char *prefix;
989
990 for (i = 0; i < opts->num_mnt_opts; i++) {
991 char *has_comma = strchr(opts->mnt_opts[i], ',');
992
993 switch (opts->mnt_opts_flags[i]) {
994 case CONTEXT_MNT:
995 prefix = CONTEXT_STR;
996 break;
997 case FSCONTEXT_MNT:
998 prefix = FSCONTEXT_STR;
999 break;
1000 case ROOTCONTEXT_MNT:
1001 prefix = ROOTCONTEXT_STR;
1002 break;
1003 case DEFCONTEXT_MNT:
1004 prefix = DEFCONTEXT_STR;
1005 break;
1006 default:
1007 BUG();
1008 };
1009 /* we need a comma before each option */
1010 seq_putc(m, ',');
1011 seq_puts(m, prefix);
1012 if (has_comma)
1013 seq_putc(m, '\"');
1014 seq_puts(m, opts->mnt_opts[i]);
1015 if (has_comma)
1016 seq_putc(m, '\"');
1017 }
1018}
1019
1020static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1021{
1022 struct security_mnt_opts opts;
1023 int rc;
1024
1025 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001026 if (rc) {
1027 /* before policy load we may get EINVAL, don't show anything */
1028 if (rc == -EINVAL)
1029 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001030 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001031 }
Eric Paris2069f452008-07-04 09:47:13 +10001032
1033 selinux_write_opts(m, &opts);
1034
1035 security_free_mnt_opts(&opts);
1036
1037 return rc;
1038}
1039
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040static inline u16 inode_mode_to_security_class(umode_t mode)
1041{
1042 switch (mode & S_IFMT) {
1043 case S_IFSOCK:
1044 return SECCLASS_SOCK_FILE;
1045 case S_IFLNK:
1046 return SECCLASS_LNK_FILE;
1047 case S_IFREG:
1048 return SECCLASS_FILE;
1049 case S_IFBLK:
1050 return SECCLASS_BLK_FILE;
1051 case S_IFDIR:
1052 return SECCLASS_DIR;
1053 case S_IFCHR:
1054 return SECCLASS_CHR_FILE;
1055 case S_IFIFO:
1056 return SECCLASS_FIFO_FILE;
1057
1058 }
1059
1060 return SECCLASS_FILE;
1061}
1062
James Morris13402582005-09-30 14:24:34 -04001063static inline int default_protocol_stream(int protocol)
1064{
1065 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1066}
1067
1068static inline int default_protocol_dgram(int protocol)
1069{
1070 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1071}
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1074{
1075 switch (family) {
1076 case PF_UNIX:
1077 switch (type) {
1078 case SOCK_STREAM:
1079 case SOCK_SEQPACKET:
1080 return SECCLASS_UNIX_STREAM_SOCKET;
1081 case SOCK_DGRAM:
1082 return SECCLASS_UNIX_DGRAM_SOCKET;
1083 }
1084 break;
1085 case PF_INET:
1086 case PF_INET6:
1087 switch (type) {
1088 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001089 if (default_protocol_stream(protocol))
1090 return SECCLASS_TCP_SOCKET;
1091 else
1092 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001094 if (default_protocol_dgram(protocol))
1095 return SECCLASS_UDP_SOCKET;
1096 else
1097 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001098 case SOCK_DCCP:
1099 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001100 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return SECCLASS_RAWIP_SOCKET;
1102 }
1103 break;
1104 case PF_NETLINK:
1105 switch (protocol) {
1106 case NETLINK_ROUTE:
1107 return SECCLASS_NETLINK_ROUTE_SOCKET;
1108 case NETLINK_FIREWALL:
1109 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001110 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1112 case NETLINK_NFLOG:
1113 return SECCLASS_NETLINK_NFLOG_SOCKET;
1114 case NETLINK_XFRM:
1115 return SECCLASS_NETLINK_XFRM_SOCKET;
1116 case NETLINK_SELINUX:
1117 return SECCLASS_NETLINK_SELINUX_SOCKET;
1118 case NETLINK_AUDIT:
1119 return SECCLASS_NETLINK_AUDIT_SOCKET;
1120 case NETLINK_IP6_FW:
1121 return SECCLASS_NETLINK_IP6FW_SOCKET;
1122 case NETLINK_DNRTMSG:
1123 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001124 case NETLINK_KOBJECT_UEVENT:
1125 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 default:
1127 return SECCLASS_NETLINK_SOCKET;
1128 }
1129 case PF_PACKET:
1130 return SECCLASS_PACKET_SOCKET;
1131 case PF_KEY:
1132 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001133 case PF_APPLETALK:
1134 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
1136
1137 return SECCLASS_SOCKET;
1138}
1139
1140#ifdef CONFIG_PROC_FS
1141static int selinux_proc_get_sid(struct proc_dir_entry *de,
1142 u16 tclass,
1143 u32 *sid)
1144{
1145 int buflen, rc;
1146 char *buffer, *path, *end;
1147
Eric Paris828dfe12008-04-17 13:17:49 -04001148 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 if (!buffer)
1150 return -ENOMEM;
1151
1152 buflen = PAGE_SIZE;
1153 end = buffer+buflen;
1154 *--end = '\0';
1155 buflen--;
1156 path = end-1;
1157 *path = '/';
1158 while (de && de != de->parent) {
1159 buflen -= de->namelen + 1;
1160 if (buflen < 0)
1161 break;
1162 end -= de->namelen;
1163 memcpy(end, de->name, de->namelen);
1164 *--end = '/';
1165 path = end;
1166 de = de->parent;
1167 }
1168 rc = security_genfs_sid("proc", path, tclass, sid);
1169 free_page((unsigned long)buffer);
1170 return rc;
1171}
1172#else
1173static int selinux_proc_get_sid(struct proc_dir_entry *de,
1174 u16 tclass,
1175 u32 *sid)
1176{
1177 return -EINVAL;
1178}
1179#endif
1180
1181/* The inode's security attributes must be initialized before first use. */
1182static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1183{
1184 struct superblock_security_struct *sbsec = NULL;
1185 struct inode_security_struct *isec = inode->i_security;
1186 u32 sid;
1187 struct dentry *dentry;
1188#define INITCONTEXTLEN 255
1189 char *context = NULL;
1190 unsigned len = 0;
1191 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 if (isec->initialized)
1194 goto out;
1195
Eric Paris23970742006-09-25 23:32:01 -07001196 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001198 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 sbsec = inode->i_sb->s_security;
1201 if (!sbsec->initialized) {
1202 /* Defer initialization until selinux_complete_init,
1203 after the initial policy is loaded and the security
1204 server is ready to handle calls. */
1205 spin_lock(&sbsec->isec_lock);
1206 if (list_empty(&isec->list))
1207 list_add(&isec->list, &sbsec->isec_head);
1208 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001209 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 }
1211
1212 switch (sbsec->behavior) {
1213 case SECURITY_FS_USE_XATTR:
1214 if (!inode->i_op->getxattr) {
1215 isec->sid = sbsec->def_sid;
1216 break;
1217 }
1218
1219 /* Need a dentry, since the xattr API requires one.
1220 Life would be simpler if we could just pass the inode. */
1221 if (opt_dentry) {
1222 /* Called from d_instantiate or d_splice_alias. */
1223 dentry = dget(opt_dentry);
1224 } else {
1225 /* Called from selinux_complete_init, try to find a dentry. */
1226 dentry = d_find_alias(inode);
1227 }
1228 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001229 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001230 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001232 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 }
1234
1235 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001236 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 if (!context) {
1238 rc = -ENOMEM;
1239 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001240 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 }
1242 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1243 context, len);
1244 if (rc == -ERANGE) {
1245 /* Need a larger buffer. Query for the right size. */
1246 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1247 NULL, 0);
1248 if (rc < 0) {
1249 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001250 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 }
1252 kfree(context);
1253 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001254 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if (!context) {
1256 rc = -ENOMEM;
1257 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001258 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260 rc = inode->i_op->getxattr(dentry,
1261 XATTR_NAME_SELINUX,
1262 context, len);
1263 }
1264 dput(dentry);
1265 if (rc < 0) {
1266 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001267 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001268 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 -rc, inode->i_sb->s_id, inode->i_ino);
1270 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001271 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 }
1273 /* Map ENODATA to the default file SID */
1274 sid = sbsec->def_sid;
1275 rc = 0;
1276 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001277 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001278 sbsec->def_sid,
1279 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001281 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001283 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 inode->i_sb->s_id, inode->i_ino);
1285 kfree(context);
1286 /* Leave with the unlabeled SID */
1287 rc = 0;
1288 break;
1289 }
1290 }
1291 kfree(context);
1292 isec->sid = sid;
1293 break;
1294 case SECURITY_FS_USE_TASK:
1295 isec->sid = isec->task_sid;
1296 break;
1297 case SECURITY_FS_USE_TRANS:
1298 /* Default to the fs SID. */
1299 isec->sid = sbsec->sid;
1300
1301 /* Try to obtain a transition SID. */
1302 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1303 rc = security_transition_sid(isec->task_sid,
1304 sbsec->sid,
1305 isec->sclass,
1306 &sid);
1307 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001308 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 isec->sid = sid;
1310 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001311 case SECURITY_FS_USE_MNTPOINT:
1312 isec->sid = sbsec->mntpoint_sid;
1313 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001315 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 isec->sid = sbsec->sid;
1317
Stephen Smalleyea6b1842008-09-22 15:41:19 -04001318 if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 struct proc_inode *proci = PROC_I(inode);
1320 if (proci->pde) {
1321 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1322 rc = selinux_proc_get_sid(proci->pde,
1323 isec->sclass,
1324 &sid);
1325 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001326 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 isec->sid = sid;
1328 }
1329 }
1330 break;
1331 }
1332
1333 isec->initialized = 1;
1334
Eric Paris23970742006-09-25 23:32:01 -07001335out_unlock:
1336 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337out:
1338 if (isec->sclass == SECCLASS_FILE)
1339 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 return rc;
1341}
1342
1343/* Convert a Linux signal to an access vector. */
1344static inline u32 signal_to_av(int sig)
1345{
1346 u32 perm = 0;
1347
1348 switch (sig) {
1349 case SIGCHLD:
1350 /* Commonly granted from child to parent. */
1351 perm = PROCESS__SIGCHLD;
1352 break;
1353 case SIGKILL:
1354 /* Cannot be caught or ignored */
1355 perm = PROCESS__SIGKILL;
1356 break;
1357 case SIGSTOP:
1358 /* Cannot be caught or ignored */
1359 perm = PROCESS__SIGSTOP;
1360 break;
1361 default:
1362 /* All other signals. */
1363 perm = PROCESS__SIGNAL;
1364 break;
1365 }
1366
1367 return perm;
1368}
1369
David Howells275bb412008-11-14 10:39:19 +11001370/*
1371 * Check permission betweeen a pair of tasks, e.g. signal checks,
1372 * fork check, ptrace check, etc.
1373 * tsk1 is the actor and tsk2 is the target
1374 */
1375static int task_has_perm(const struct task_struct *tsk1,
1376 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 u32 perms)
1378{
David Howells275bb412008-11-14 10:39:19 +11001379 const struct task_security_struct *__tsec1, *__tsec2;
1380 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
David Howells275bb412008-11-14 10:39:19 +11001382 rcu_read_lock();
1383 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1384 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1385 rcu_read_unlock();
1386 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387}
1388
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001389#if CAP_LAST_CAP > 63
1390#error Fix SELinux to handle capabilities > 63.
1391#endif
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393/* Check whether a task is allowed to use a capability. */
1394static int task_has_capability(struct task_struct *tsk,
Eric Paris06112162008-11-11 22:02:50 +11001395 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001398 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001399 u16 sclass;
David Howells275bb412008-11-14 10:39:19 +11001400 u32 sid = task_sid(tsk);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001401 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001402 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Eric Paris828dfe12008-04-17 13:17:49 -04001404 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 ad.tsk = tsk;
1406 ad.u.cap = cap;
1407
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001408 switch (CAP_TO_INDEX(cap)) {
1409 case 0:
1410 sclass = SECCLASS_CAPABILITY;
1411 break;
1412 case 1:
1413 sclass = SECCLASS_CAPABILITY2;
1414 break;
1415 default:
1416 printk(KERN_ERR
1417 "SELinux: out of range capability %d\n", cap);
1418 BUG();
1419 }
Eric Paris06112162008-11-11 22:02:50 +11001420
David Howells275bb412008-11-14 10:39:19 +11001421 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001422 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001423 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001424 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
1427/* Check whether a task is allowed to use a system operation. */
1428static int task_has_system(struct task_struct *tsk,
1429 u32 perms)
1430{
David Howells275bb412008-11-14 10:39:19 +11001431 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
David Howells275bb412008-11-14 10:39:19 +11001433 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 SECCLASS_SYSTEM, perms, NULL);
1435}
1436
1437/* Check whether a task has a particular permission to an inode.
1438 The 'adp' parameter is optional and allows other audit
1439 data to be passed (e.g. the dentry). */
1440static int inode_has_perm(struct task_struct *tsk,
1441 struct inode *inode,
1442 u32 perms,
1443 struct avc_audit_data *adp)
1444{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 struct inode_security_struct *isec;
1446 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001447 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Eric Paris828dfe12008-04-17 13:17:49 -04001449 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001450 return 0;
1451
David Howells275bb412008-11-14 10:39:19 +11001452 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 isec = inode->i_security;
1454
1455 if (!adp) {
1456 adp = &ad;
1457 AVC_AUDIT_DATA_INIT(&ad, FS);
1458 ad.u.fs.inode = inode;
1459 }
1460
David Howells275bb412008-11-14 10:39:19 +11001461 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462}
1463
1464/* Same as inode_has_perm, but pass explicit audit data containing
1465 the dentry to help the auditing code to more easily generate the
1466 pathname if needed. */
1467static inline int dentry_has_perm(struct task_struct *tsk,
1468 struct vfsmount *mnt,
1469 struct dentry *dentry,
1470 u32 av)
1471{
1472 struct inode *inode = dentry->d_inode;
1473 struct avc_audit_data ad;
Eric Paris828dfe12008-04-17 13:17:49 -04001474 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001475 ad.u.fs.path.mnt = mnt;
1476 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 return inode_has_perm(tsk, inode, av, &ad);
1478}
1479
1480/* Check whether a task can use an open file descriptor to
1481 access an inode in a given way. Check access to the
1482 descriptor itself, and then use dentry_has_perm to
1483 check a particular permission to the file.
1484 Access to the descriptor is implicitly granted if it
1485 has the same SID as the process. If av is zero, then
1486 access to the file is not checked, e.g. for cases
1487 where only the descriptor is affected like seek. */
Arjan van de Ven858119e2006-01-14 13:20:43 -08001488static int file_has_perm(struct task_struct *tsk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 struct file *file,
1490 u32 av)
1491{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001493 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001495 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 int rc;
1497
1498 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001499 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
David Howells275bb412008-11-14 10:39:19 +11001501 if (sid != fsec->sid) {
1502 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 SECCLASS_FD,
1504 FD__USE,
1505 &ad);
1506 if (rc)
1507 return rc;
1508 }
1509
1510 /* av is zero if only checking access to the descriptor. */
1511 if (av)
1512 return inode_has_perm(tsk, inode, av, &ad);
1513
1514 return 0;
1515}
1516
1517/* Check whether a task can create a file. */
1518static int may_create(struct inode *dir,
1519 struct dentry *dentry,
1520 u16 tclass)
1521{
David Howells275bb412008-11-14 10:39:19 +11001522 const struct cred *cred = current_cred();
1523 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 struct inode_security_struct *dsec;
1525 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001526 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 struct avc_audit_data ad;
1528 int rc;
1529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 dsec = dir->i_security;
1531 sbsec = dir->i_sb->s_security;
1532
David Howells275bb412008-11-14 10:39:19 +11001533 sid = tsec->sid;
1534 newsid = tsec->create_sid;
1535
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001537 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
David Howells275bb412008-11-14 10:39:19 +11001539 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 DIR__ADD_NAME | DIR__SEARCH,
1541 &ad);
1542 if (rc)
1543 return rc;
1544
David Howells275bb412008-11-14 10:39:19 +11001545 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
1546 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 if (rc)
1548 return rc;
1549 }
1550
David Howells275bb412008-11-14 10:39:19 +11001551 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 if (rc)
1553 return rc;
1554
1555 return avc_has_perm(newsid, sbsec->sid,
1556 SECCLASS_FILESYSTEM,
1557 FILESYSTEM__ASSOCIATE, &ad);
1558}
1559
Michael LeMay4eb582c2006-06-26 00:24:57 -07001560/* Check whether a task can create a key. */
1561static int may_create_key(u32 ksid,
1562 struct task_struct *ctx)
1563{
David Howells275bb412008-11-14 10:39:19 +11001564 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001565
David Howells275bb412008-11-14 10:39:19 +11001566 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001567}
1568
Eric Paris828dfe12008-04-17 13:17:49 -04001569#define MAY_LINK 0
1570#define MAY_UNLINK 1
1571#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
1573/* Check whether a task can link, unlink, or rmdir a file/directory. */
1574static int may_link(struct inode *dir,
1575 struct dentry *dentry,
1576 int kind)
1577
1578{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 struct inode_security_struct *dsec, *isec;
1580 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001581 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 u32 av;
1583 int rc;
1584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 dsec = dir->i_security;
1586 isec = dentry->d_inode->i_security;
1587
1588 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001589 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 av = DIR__SEARCH;
1592 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001593 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 if (rc)
1595 return rc;
1596
1597 switch (kind) {
1598 case MAY_LINK:
1599 av = FILE__LINK;
1600 break;
1601 case MAY_UNLINK:
1602 av = FILE__UNLINK;
1603 break;
1604 case MAY_RMDIR:
1605 av = DIR__RMDIR;
1606 break;
1607 default:
Eric Paris744ba352008-04-17 11:52:44 -04001608 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1609 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 return 0;
1611 }
1612
David Howells275bb412008-11-14 10:39:19 +11001613 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 return rc;
1615}
1616
1617static inline int may_rename(struct inode *old_dir,
1618 struct dentry *old_dentry,
1619 struct inode *new_dir,
1620 struct dentry *new_dentry)
1621{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1623 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001624 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 u32 av;
1626 int old_is_dir, new_is_dir;
1627 int rc;
1628
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 old_dsec = old_dir->i_security;
1630 old_isec = old_dentry->d_inode->i_security;
1631 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1632 new_dsec = new_dir->i_security;
1633
1634 AVC_AUDIT_DATA_INIT(&ad, FS);
1635
Jan Blunck44707fd2008-02-14 19:38:33 -08001636 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001637 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1639 if (rc)
1640 return rc;
David Howells275bb412008-11-14 10:39:19 +11001641 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 old_isec->sclass, FILE__RENAME, &ad);
1643 if (rc)
1644 return rc;
1645 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001646 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 old_isec->sclass, DIR__REPARENT, &ad);
1648 if (rc)
1649 return rc;
1650 }
1651
Jan Blunck44707fd2008-02-14 19:38:33 -08001652 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 av = DIR__ADD_NAME | DIR__SEARCH;
1654 if (new_dentry->d_inode)
1655 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001656 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (rc)
1658 return rc;
1659 if (new_dentry->d_inode) {
1660 new_isec = new_dentry->d_inode->i_security;
1661 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001662 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 new_isec->sclass,
1664 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1665 if (rc)
1666 return rc;
1667 }
1668
1669 return 0;
1670}
1671
1672/* Check whether a task can perform a filesystem operation. */
1673static int superblock_has_perm(struct task_struct *tsk,
1674 struct super_block *sb,
1675 u32 perms,
1676 struct avc_audit_data *ad)
1677{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001679 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001682 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683}
1684
1685/* Convert a Linux mode and permission mask to an access vector. */
1686static inline u32 file_mask_to_av(int mode, int mask)
1687{
1688 u32 av = 0;
1689
1690 if ((mode & S_IFMT) != S_IFDIR) {
1691 if (mask & MAY_EXEC)
1692 av |= FILE__EXECUTE;
1693 if (mask & MAY_READ)
1694 av |= FILE__READ;
1695
1696 if (mask & MAY_APPEND)
1697 av |= FILE__APPEND;
1698 else if (mask & MAY_WRITE)
1699 av |= FILE__WRITE;
1700
1701 } else {
1702 if (mask & MAY_EXEC)
1703 av |= DIR__SEARCH;
1704 if (mask & MAY_WRITE)
1705 av |= DIR__WRITE;
1706 if (mask & MAY_READ)
1707 av |= DIR__READ;
1708 }
1709
1710 return av;
1711}
1712
1713/* Convert a Linux file to an access vector. */
1714static inline u32 file_to_av(struct file *file)
1715{
1716 u32 av = 0;
1717
1718 if (file->f_mode & FMODE_READ)
1719 av |= FILE__READ;
1720 if (file->f_mode & FMODE_WRITE) {
1721 if (file->f_flags & O_APPEND)
1722 av |= FILE__APPEND;
1723 else
1724 av |= FILE__WRITE;
1725 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001726 if (!av) {
1727 /*
1728 * Special file opened with flags 3 for ioctl-only use.
1729 */
1730 av = FILE__IOCTL;
1731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733 return av;
1734}
1735
Eric Paris8b6a5a32008-10-29 17:06:46 -04001736/*
1737 * Convert a file to an access vector and include the correct open
1738 * open permission.
1739 */
1740static inline u32 open_file_to_av(struct file *file)
1741{
1742 u32 av = file_to_av(file);
1743
1744 if (selinux_policycap_openperm) {
1745 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1746 /*
1747 * lnk files and socks do not really have an 'open'
1748 */
1749 if (S_ISREG(mode))
1750 av |= FILE__OPEN;
1751 else if (S_ISCHR(mode))
1752 av |= CHR_FILE__OPEN;
1753 else if (S_ISBLK(mode))
1754 av |= BLK_FILE__OPEN;
1755 else if (S_ISFIFO(mode))
1756 av |= FIFO_FILE__OPEN;
1757 else if (S_ISDIR(mode))
1758 av |= DIR__OPEN;
1759 else
1760 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1761 "unknown mode:%o\n", __func__, mode);
1762 }
1763 return av;
1764}
1765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766/* Hook functions begin here. */
1767
David Howells5cd9c582008-08-14 11:37:28 +01001768static int selinux_ptrace_may_access(struct task_struct *child,
1769 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 int rc;
1772
David Howells5cd9c582008-08-14 11:37:28 +01001773 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (rc)
1775 return rc;
1776
Stephen Smalley006ebb42008-05-19 08:32:49 -04001777 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001778 u32 sid = current_sid();
1779 u32 csid = task_sid(child);
1780 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001781 }
1782
David Howells5cd9c582008-08-14 11:37:28 +01001783 return task_has_perm(current, child, PROCESS__PTRACE);
1784}
1785
1786static int selinux_ptrace_traceme(struct task_struct *parent)
1787{
1788 int rc;
1789
1790 rc = secondary_ops->ptrace_traceme(parent);
1791 if (rc)
1792 return rc;
1793
1794 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795}
1796
1797static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001798 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799{
1800 int error;
1801
1802 error = task_has_perm(current, target, PROCESS__GETCAP);
1803 if (error)
1804 return error;
1805
1806 return secondary_ops->capget(target, effective, inheritable, permitted);
1807}
1808
David Howells15a24602008-11-14 10:39:15 +11001809static int selinux_capset_check(const kernel_cap_t *effective,
1810 const kernel_cap_t *inheritable,
1811 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812{
1813 int error;
1814
David Howells1cdcbec2008-11-14 10:39:14 +11001815 error = secondary_ops->capset_check(effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (error)
1817 return error;
1818
David Howells1cdcbec2008-11-14 10:39:14 +11001819 return task_has_perm(current, current, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820}
1821
David Howells15a24602008-11-14 10:39:15 +11001822static void selinux_capset_set(const kernel_cap_t *effective,
1823 const kernel_cap_t *inheritable,
1824 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825{
David Howells1cdcbec2008-11-14 10:39:14 +11001826 secondary_ops->capset_set(effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827}
1828
Eric Paris06112162008-11-11 22:02:50 +11001829static int selinux_capable(struct task_struct *tsk, int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830{
1831 int rc;
1832
Eric Paris06112162008-11-11 22:02:50 +11001833 rc = secondary_ops->capable(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (rc)
1835 return rc;
1836
Eric Paris06112162008-11-11 22:02:50 +11001837 return task_has_capability(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838}
1839
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001840static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1841{
1842 int buflen, rc;
1843 char *buffer, *path, *end;
1844
1845 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001846 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001847 if (!buffer)
1848 goto out;
1849
1850 buflen = PAGE_SIZE;
1851 end = buffer+buflen;
1852 *--end = '\0';
1853 buflen--;
1854 path = end-1;
1855 *path = '/';
1856 while (table) {
1857 const char *name = table->procname;
1858 size_t namelen = strlen(name);
1859 buflen -= namelen + 1;
1860 if (buflen < 0)
1861 goto out_free;
1862 end -= namelen;
1863 memcpy(end, name, namelen);
1864 *--end = '/';
1865 path = end;
1866 table = table->parent;
1867 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001868 buflen -= 4;
1869 if (buflen < 0)
1870 goto out_free;
1871 end -= 4;
1872 memcpy(end, "/sys", 4);
1873 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001874 rc = security_genfs_sid("proc", path, tclass, sid);
1875out_free:
1876 free_page((unsigned long)buffer);
1877out:
1878 return rc;
1879}
1880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881static int selinux_sysctl(ctl_table *table, int op)
1882{
1883 int error = 0;
1884 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001885 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 int rc;
1887
1888 rc = secondary_ops->sysctl(table, op);
1889 if (rc)
1890 return rc;
1891
David Howells275bb412008-11-14 10:39:19 +11001892 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001894 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1895 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 if (rc) {
1897 /* Default to the well-defined sysctl SID. */
1898 tsid = SECINITSID_SYSCTL;
1899 }
1900
1901 /* The op values are "defined" in sysctl.c, thereby creating
1902 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001903 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11001904 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 SECCLASS_DIR, DIR__SEARCH, NULL);
1906 } else {
1907 av = 0;
1908 if (op & 004)
1909 av |= FILE__READ;
1910 if (op & 002)
1911 av |= FILE__WRITE;
1912 if (av)
David Howells275bb412008-11-14 10:39:19 +11001913 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
1917 return error;
1918}
1919
1920static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1921{
1922 int rc = 0;
1923
1924 if (!sb)
1925 return 0;
1926
1927 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001928 case Q_SYNC:
1929 case Q_QUOTAON:
1930 case Q_QUOTAOFF:
1931 case Q_SETINFO:
1932 case Q_SETQUOTA:
1933 rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
1934 NULL);
1935 break;
1936 case Q_GETFMT:
1937 case Q_GETINFO:
1938 case Q_GETQUOTA:
1939 rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
1940 NULL);
1941 break;
1942 default:
1943 rc = 0; /* let the kernel handle invalid cmds */
1944 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 }
1946 return rc;
1947}
1948
1949static int selinux_quota_on(struct dentry *dentry)
1950{
1951 return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
1952}
1953
1954static int selinux_syslog(int type)
1955{
1956 int rc;
1957
1958 rc = secondary_ops->syslog(type);
1959 if (rc)
1960 return rc;
1961
1962 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04001963 case 3: /* Read last kernel messages */
1964 case 10: /* Return size of the log buffer */
1965 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1966 break;
1967 case 6: /* Disable logging to console */
1968 case 7: /* Enable logging to console */
1969 case 8: /* Set level of messages printed to console */
1970 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1971 break;
1972 case 0: /* Close log */
1973 case 1: /* Open log */
1974 case 2: /* Read from log */
1975 case 4: /* Read/clear last kernel messages */
1976 case 5: /* Clear ring buffer */
1977 default:
1978 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1979 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981 return rc;
1982}
1983
1984/*
1985 * Check that a process has enough memory to allocate a new virtual
1986 * mapping. 0 means there is enough memory for the allocation to
1987 * succeed and -ENOMEM implies there is not.
1988 *
1989 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
1990 * if the capability is granted, but __vm_enough_memory requires 1 if
1991 * the capability is granted.
1992 *
1993 * Do not audit the selinux permission check, as this is applied to all
1994 * processes that allocate mappings.
1995 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001996static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
1998 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Eric Paris06674672008-11-11 22:02:57 +11002000 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 if (rc == 0)
2002 cap_sys_admin = 1;
2003
Alan Cox34b4e4a2007-08-22 14:01:28 -07002004 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005}
2006
2007/* binprm security operations */
2008
2009static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
2010{
2011 struct bprm_security_struct *bsec;
2012
James Morris89d155e2005-10-30 14:59:21 -08002013 bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 if (!bsec)
2015 return -ENOMEM;
2016
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 bsec->sid = SECINITSID_UNLABELED;
2018 bsec->set = 0;
2019
2020 bprm->security = bsec;
2021 return 0;
2022}
2023
2024static int selinux_bprm_set_security(struct linux_binprm *bprm)
2025{
2026 struct task_security_struct *tsec;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002027 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 struct inode_security_struct *isec;
2029 struct bprm_security_struct *bsec;
2030 u32 newsid;
2031 struct avc_audit_data ad;
2032 int rc;
2033
2034 rc = secondary_ops->bprm_set_security(bprm);
2035 if (rc)
2036 return rc;
2037
2038 bsec = bprm->security;
2039
2040 if (bsec->set)
2041 return 0;
2042
David Howells275bb412008-11-14 10:39:19 +11002043 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 isec = inode->i_security;
2045
2046 /* Default to the current task SID. */
2047 bsec->sid = tsec->sid;
2048
Michael LeMay28eba5b2006-06-27 02:53:42 -07002049 /* Reset fs, key, and sock SIDs on execve. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 tsec->create_sid = 0;
Michael LeMay28eba5b2006-06-27 02:53:42 -07002051 tsec->keycreate_sid = 0;
Eric Paris42c3e032006-06-26 00:26:03 -07002052 tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
2054 if (tsec->exec_sid) {
2055 newsid = tsec->exec_sid;
2056 /* Reset exec SID on execve. */
2057 tsec->exec_sid = 0;
2058 } else {
2059 /* Check for a default transition on this program. */
2060 rc = security_transition_sid(tsec->sid, isec->sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002061 SECCLASS_PROCESS, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc)
2063 return rc;
2064 }
2065
2066 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002067 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Josef Sipek3d5ff522006-12-08 02:37:38 -08002069 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 newsid = tsec->sid;
2071
Eric Paris828dfe12008-04-17 13:17:49 -04002072 if (tsec->sid == newsid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 rc = avc_has_perm(tsec->sid, isec->sid,
2074 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2075 if (rc)
2076 return rc;
2077 } else {
2078 /* Check permissions for the transition. */
2079 rc = avc_has_perm(tsec->sid, newsid,
2080 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2081 if (rc)
2082 return rc;
2083
2084 rc = avc_has_perm(newsid, isec->sid,
2085 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2086 if (rc)
2087 return rc;
2088
2089 /* Clear any possibly unsafe personality bits on exec: */
2090 current->personality &= ~PER_CLEAR_ON_SETID;
2091
2092 /* Set the security field to the new SID. */
2093 bsec->sid = newsid;
2094 }
2095
2096 bsec->set = 1;
2097 return 0;
2098}
2099
Eric Paris828dfe12008-04-17 13:17:49 -04002100static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101{
2102 return secondary_ops->bprm_check_security(bprm);
2103}
2104
2105
Eric Paris828dfe12008-04-17 13:17:49 -04002106static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
David Howells275bb412008-11-14 10:39:19 +11002108 const struct cred *cred = current_cred();
2109 const struct task_security_struct *tsec = cred->security;
2110 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 int atsecure = 0;
2112
David Howells275bb412008-11-14 10:39:19 +11002113 sid = tsec->sid;
2114 osid = tsec->osid;
2115
2116 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 /* Enable secure mode for SIDs transitions unless
2118 the noatsecure permission is granted between
2119 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002120 atsecure = avc_has_perm(osid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 SECCLASS_PROCESS,
2122 PROCESS__NOATSECURE, NULL);
2123 }
2124
2125 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2126}
2127
2128static void selinux_bprm_free_security(struct linux_binprm *bprm)
2129{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07002130 kfree(bprm->security);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 bprm->security = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132}
2133
2134extern struct vfsmount *selinuxfs_mount;
2135extern struct dentry *selinux_null;
2136
2137/* Derived from fs/exec.c:flush_old_files. */
Eric Paris828dfe12008-04-17 13:17:49 -04002138static inline void flush_unauthorized_files(struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139{
2140 struct avc_audit_data ad;
2141 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002142 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002143 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002145 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002147 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 if (tty) {
2149 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002150 if (!list_empty(&tty->tty_files)) {
2151 struct inode *inode;
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 /* Revalidate access to controlling tty.
2154 Use inode_has_perm on the tty inode directly rather
2155 than using file_has_perm, as this particular open
2156 file may belong to another process and we are only
2157 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002158 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2159 inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (inode_has_perm(current, inode,
2161 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002162 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 }
2164 }
2165 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002166 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002168 /* Reset controlling tty. */
2169 if (drop_tty)
2170 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171
2172 /* Revalidate access to inherited open files. */
2173
Eric Paris828dfe12008-04-17 13:17:49 -04002174 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176 spin_lock(&files->file_lock);
2177 for (;;) {
2178 unsigned long set, i;
2179 int fd;
2180
2181 j++;
2182 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002183 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002184 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002186 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 if (!set)
2188 continue;
2189 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002190 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 if (set & 1) {
2192 file = fget(i);
2193 if (!file)
2194 continue;
2195 if (file_has_perm(current,
2196 file,
2197 file_to_av(file))) {
2198 sys_close(i);
2199 fd = get_unused_fd();
2200 if (fd != i) {
2201 if (fd >= 0)
2202 put_unused_fd(fd);
2203 fput(file);
2204 continue;
2205 }
2206 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002207 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 } else {
2209 devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002210 if (IS_ERR(devnull)) {
2211 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 put_unused_fd(fd);
2213 fput(file);
2214 continue;
2215 }
2216 }
2217 fd_install(fd, devnull);
2218 }
2219 fput(file);
2220 }
2221 }
2222 spin_lock(&files->file_lock);
2223
2224 }
2225 spin_unlock(&files->file_lock);
2226}
2227
2228static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
2229{
2230 struct task_security_struct *tsec;
2231 struct bprm_security_struct *bsec;
2232 u32 sid;
2233 int rc;
2234
2235 secondary_ops->bprm_apply_creds(bprm, unsafe);
2236
David Howells275bb412008-11-14 10:39:19 +11002237 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 bsec = bprm->security;
2240 sid = bsec->sid;
2241
2242 tsec->osid = tsec->sid;
2243 bsec->unsafe = 0;
2244 if (tsec->sid != sid) {
2245 /* Check for shared state. If not ok, leave SID
2246 unchanged and kill. */
2247 if (unsafe & LSM_UNSAFE_SHARE) {
2248 rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
2249 PROCESS__SHARE, NULL);
2250 if (rc) {
2251 bsec->unsafe = 1;
2252 return;
2253 }
2254 }
2255
2256 /* Check for ptracing, and update the task SID if ok.
2257 Otherwise, leave SID unchanged and kill. */
2258 if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
Roland McGrath03563572008-03-26 15:46:39 -07002259 struct task_struct *tracer;
2260 struct task_security_struct *sec;
2261 u32 ptsid = 0;
2262
2263 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07002264 tracer = tracehook_tracer_task(current);
Roland McGrath03563572008-03-26 15:46:39 -07002265 if (likely(tracer != NULL)) {
David Howells275bb412008-11-14 10:39:19 +11002266 sec = __task_cred(tracer)->security;
Roland McGrath03563572008-03-26 15:46:39 -07002267 ptsid = sec->sid;
2268 }
2269 rcu_read_unlock();
2270
2271 if (ptsid != 0) {
2272 rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
2273 PROCESS__PTRACE, NULL);
2274 if (rc) {
2275 bsec->unsafe = 1;
2276 return;
2277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 }
2279 }
2280 tsec->sid = sid;
2281 }
2282}
2283
2284/*
2285 * called after apply_creds without the task lock held
2286 */
2287static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
2288{
2289 struct task_security_struct *tsec;
2290 struct rlimit *rlim, *initrlim;
2291 struct itimerval itimer;
2292 struct bprm_security_struct *bsec;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002293 struct sighand_struct *psig;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 int rc, i;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002295 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
David Howells275bb412008-11-14 10:39:19 +11002297 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 bsec = bprm->security;
2299
2300 if (bsec->unsafe) {
2301 force_sig_specific(SIGKILL, current);
2302 return;
2303 }
2304 if (tsec->osid == tsec->sid)
2305 return;
2306
2307 /* Close files for which the new task SID is not authorized. */
2308 flush_unauthorized_files(current->files);
2309
2310 /* Check whether the new SID can inherit signal state
2311 from the old SID. If not, clear itimers to avoid
2312 subsequent signal generation and flush and unblock
2313 signals. This must occur _after_ the task SID has
2314 been updated so that any kill done after the flush
2315 will be checked against the new SID. */
2316 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2317 PROCESS__SIGINH, NULL);
2318 if (rc) {
2319 memset(&itimer, 0, sizeof itimer);
2320 for (i = 0; i < 3; i++)
2321 do_setitimer(i, &itimer, NULL);
2322 flush_signals(current);
2323 spin_lock_irq(&current->sighand->siglock);
2324 flush_signal_handlers(current, 1);
2325 sigemptyset(&current->blocked);
2326 recalc_sigpending();
2327 spin_unlock_irq(&current->sighand->siglock);
2328 }
2329
Stephen Smalley4ac212a2007-08-29 08:51:50 -04002330 /* Always clear parent death signal on SID transitions. */
2331 current->pdeath_signal = 0;
2332
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 /* Check whether the new SID can inherit resource limits
2334 from the old SID. If not, reset all soft limits to
2335 the lower of the current task's hard limit and the init
2336 task's soft limit. Note that the setting of hard limits
2337 (even to lower them) can be controlled by the setrlimit
2338 check. The inclusion of the init task's soft limit into
2339 the computation is to avoid resetting soft limits higher
2340 than the default soft limit for cases where the default
2341 is lower than the hard limit, e.g. RLIMIT_CORE or
2342 RLIMIT_STACK.*/
2343 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2344 PROCESS__RLIMITINH, NULL);
2345 if (rc) {
2346 for (i = 0; i < RLIM_NLIMITS; i++) {
2347 rlim = current->signal->rlim + i;
2348 initrlim = init_task.signal->rlim+i;
Eric Paris828dfe12008-04-17 13:17:49 -04002349 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 }
Frank Mayharf06febc2008-09-12 09:54:39 -07002351 update_rlimit_cpu(rlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 }
2353
2354 /* Wake up the parent if it is waiting so that it can
2355 recheck wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002356 read_lock_irq(&tasklist_lock);
2357 psig = current->parent->sighand;
2358 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002360 spin_unlock_irqrestore(&psig->siglock, flags);
2361 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362}
2363
2364/* superblock security operations */
2365
2366static int selinux_sb_alloc_security(struct super_block *sb)
2367{
2368 return superblock_alloc_security(sb);
2369}
2370
2371static void selinux_sb_free_security(struct super_block *sb)
2372{
2373 superblock_free_security(sb);
2374}
2375
2376static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2377{
2378 if (plen > olen)
2379 return 0;
2380
2381 return !memcmp(prefix, option, plen);
2382}
2383
2384static inline int selinux_option(char *option, int len)
2385{
Eric Paris832cbd92008-04-01 13:24:09 -04002386 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2387 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2388 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2389 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390}
2391
2392static inline void take_option(char **to, char *from, int *first, int len)
2393{
2394 if (!*first) {
2395 **to = ',';
2396 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002397 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 *first = 0;
2399 memcpy(*to, from, len);
2400 *to += len;
2401}
2402
Eric Paris828dfe12008-04-17 13:17:49 -04002403static inline void take_selinux_option(char **to, char *from, int *first,
2404 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002405{
2406 int current_size = 0;
2407
2408 if (!*first) {
2409 **to = '|';
2410 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002411 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002412 *first = 0;
2413
2414 while (current_size < len) {
2415 if (*from != '"') {
2416 **to = *from;
2417 *to += 1;
2418 }
2419 from += 1;
2420 current_size += 1;
2421 }
2422}
2423
Eric Parise0007522008-03-05 10:31:54 -05002424static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425{
2426 int fnosec, fsec, rc = 0;
2427 char *in_save, *in_curr, *in_end;
2428 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002429 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431 in_curr = orig;
2432 sec_curr = copy;
2433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2435 if (!nosec) {
2436 rc = -ENOMEM;
2437 goto out;
2438 }
2439
2440 nosec_save = nosec;
2441 fnosec = fsec = 1;
2442 in_save = in_end = orig;
2443
2444 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002445 if (*in_end == '"')
2446 open_quote = !open_quote;
2447 if ((*in_end == ',' && open_quote == 0) ||
2448 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 int len = in_end - in_curr;
2450
2451 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002452 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 else
2454 take_option(&nosec, in_curr, &fnosec, len);
2455
2456 in_curr = in_end + 1;
2457 }
2458 } while (*in_end++);
2459
Eric Paris6931dfc2005-06-30 02:58:51 -07002460 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002461 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462out:
2463 return rc;
2464}
2465
2466static int selinux_sb_kern_mount(struct super_block *sb, void *data)
2467{
2468 struct avc_audit_data ad;
2469 int rc;
2470
2471 rc = superblock_doinit(sb, data);
2472 if (rc)
2473 return rc;
2474
Eric Paris828dfe12008-04-17 13:17:49 -04002475 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002476 ad.u.fs.path.dentry = sb->s_root;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
2478}
2479
David Howells726c3342006-06-23 02:02:58 -07002480static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481{
2482 struct avc_audit_data ad;
2483
Eric Paris828dfe12008-04-17 13:17:49 -04002484 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002485 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells726c3342006-06-23 02:02:58 -07002486 return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487}
2488
Eric Paris828dfe12008-04-17 13:17:49 -04002489static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002490 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002491 char *type,
2492 unsigned long flags,
2493 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494{
2495 int rc;
2496
Al Virob5266eb2008-03-22 17:48:24 -04002497 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 if (rc)
2499 return rc;
2500
2501 if (flags & MS_REMOUNT)
Al Virob5266eb2008-03-22 17:48:24 -04002502 return superblock_has_perm(current, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002503 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 else
Al Virob5266eb2008-03-22 17:48:24 -04002505 return dentry_has_perm(current, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002506 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507}
2508
2509static int selinux_umount(struct vfsmount *mnt, int flags)
2510{
2511 int rc;
2512
2513 rc = secondary_ops->sb_umount(mnt, flags);
2514 if (rc)
2515 return rc;
2516
Eric Paris828dfe12008-04-17 13:17:49 -04002517 return superblock_has_perm(current, mnt->mnt_sb,
2518 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519}
2520
2521/* inode security operations */
2522
2523static int selinux_inode_alloc_security(struct inode *inode)
2524{
2525 return inode_alloc_security(inode);
2526}
2527
2528static void selinux_inode_free_security(struct inode *inode)
2529{
2530 inode_free_security(inode);
2531}
2532
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002533static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2534 char **name, void **value,
2535 size_t *len)
2536{
David Howells275bb412008-11-14 10:39:19 +11002537 const struct cred *cred = current_cred();
2538 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002539 struct inode_security_struct *dsec;
2540 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002541 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002542 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002543 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002544
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002545 dsec = dir->i_security;
2546 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002547
David Howells275bb412008-11-14 10:39:19 +11002548 sid = tsec->sid;
2549 newsid = tsec->create_sid;
2550
2551 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
2552 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002553 inode_mode_to_security_class(inode->i_mode),
2554 &newsid);
2555 if (rc) {
2556 printk(KERN_WARNING "%s: "
2557 "security_transition_sid failed, rc=%d (dev=%s "
2558 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002559 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002560 -rc, inode->i_sb->s_id, inode->i_ino);
2561 return rc;
2562 }
2563 }
2564
Eric Paris296fddf2006-09-25 23:32:00 -07002565 /* Possibly defer initialization to selinux_complete_init. */
2566 if (sbsec->initialized) {
2567 struct inode_security_struct *isec = inode->i_security;
2568 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2569 isec->sid = newsid;
2570 isec->initialized = 1;
2571 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002572
Stephen Smalley8aad3872006-03-22 00:09:13 -08002573 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002574 return -EOPNOTSUPP;
2575
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002576 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002577 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002578 if (!namep)
2579 return -ENOMEM;
2580 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002581 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002582
2583 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002584 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002585 if (rc) {
2586 kfree(namep);
2587 return rc;
2588 }
2589 *value = context;
2590 *len = clen;
2591 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002592
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002593 return 0;
2594}
2595
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2597{
2598 return may_create(dir, dentry, SECCLASS_FILE);
2599}
2600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2602{
2603 int rc;
2604
Eric Paris828dfe12008-04-17 13:17:49 -04002605 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 if (rc)
2607 return rc;
2608 return may_link(dir, old_dentry, MAY_LINK);
2609}
2610
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2612{
2613 int rc;
2614
2615 rc = secondary_ops->inode_unlink(dir, dentry);
2616 if (rc)
2617 return rc;
2618 return may_link(dir, dentry, MAY_UNLINK);
2619}
2620
2621static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2622{
2623 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2624}
2625
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2627{
2628 return may_create(dir, dentry, SECCLASS_DIR);
2629}
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2632{
2633 return may_link(dir, dentry, MAY_RMDIR);
2634}
2635
2636static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2637{
2638 int rc;
2639
2640 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2641 if (rc)
2642 return rc;
2643
2644 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2645}
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002648 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649{
2650 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2651}
2652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653static int selinux_inode_readlink(struct dentry *dentry)
2654{
2655 return dentry_has_perm(current, NULL, dentry, FILE__READ);
2656}
2657
2658static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2659{
2660 int rc;
2661
Eric Paris828dfe12008-04-17 13:17:49 -04002662 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 if (rc)
2664 return rc;
2665 return dentry_has_perm(current, NULL, dentry, FILE__READ);
2666}
2667
Al Virob77b0642008-07-17 09:37:02 -04002668static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
2670 int rc;
2671
Al Virob77b0642008-07-17 09:37:02 -04002672 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 if (rc)
2674 return rc;
2675
2676 if (!mask) {
2677 /* No permission to check. Existence test. */
2678 return 0;
2679 }
2680
2681 return inode_has_perm(current, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002682 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683}
2684
2685static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2686{
2687 int rc;
2688
2689 rc = secondary_ops->inode_setattr(dentry, iattr);
2690 if (rc)
2691 return rc;
2692
2693 if (iattr->ia_valid & ATTR_FORCE)
2694 return 0;
2695
2696 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2697 ATTR_ATIME_SET | ATTR_MTIME_SET))
2698 return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
2699
2700 return dentry_has_perm(current, NULL, dentry, FILE__WRITE);
2701}
2702
2703static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2704{
2705 return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
2706}
2707
David Howells8f0cfa52008-04-29 00:59:41 -07002708static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002709{
2710 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2711 sizeof XATTR_SECURITY_PREFIX - 1)) {
2712 if (!strcmp(name, XATTR_NAME_CAPS)) {
2713 if (!capable(CAP_SETFCAP))
2714 return -EPERM;
2715 } else if (!capable(CAP_SYS_ADMIN)) {
2716 /* A different attribute in the security namespace.
2717 Restrict to administrator. */
2718 return -EPERM;
2719 }
2720 }
2721
2722 /* Not an attribute we recognize, so just check the
2723 ordinary setattr permission. */
2724 return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
2725}
2726
David Howells8f0cfa52008-04-29 00:59:41 -07002727static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2728 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 struct inode *inode = dentry->d_inode;
2731 struct inode_security_struct *isec = inode->i_security;
2732 struct superblock_security_struct *sbsec;
2733 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002734 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 int rc = 0;
2736
Serge E. Hallynb5376772007-10-16 23:31:36 -07002737 if (strcmp(name, XATTR_NAME_SELINUX))
2738 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740 sbsec = inode->i_sb->s_security;
2741 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2742 return -EOPNOTSUPP;
2743
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302744 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 return -EPERM;
2746
Eric Paris828dfe12008-04-17 13:17:49 -04002747 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002748 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
David Howells275bb412008-11-14 10:39:19 +11002750 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 FILE__RELABELFROM, &ad);
2752 if (rc)
2753 return rc;
2754
2755 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002756 if (rc == -EINVAL) {
2757 if (!capable(CAP_MAC_ADMIN))
2758 return rc;
2759 rc = security_context_to_sid_force(value, size, &newsid);
2760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 if (rc)
2762 return rc;
2763
David Howells275bb412008-11-14 10:39:19 +11002764 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 FILE__RELABELTO, &ad);
2766 if (rc)
2767 return rc;
2768
David Howells275bb412008-11-14 10:39:19 +11002769 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002770 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 if (rc)
2772 return rc;
2773
2774 return avc_has_perm(newsid,
2775 sbsec->sid,
2776 SECCLASS_FILESYSTEM,
2777 FILESYSTEM__ASSOCIATE,
2778 &ad);
2779}
2780
David Howells8f0cfa52008-04-29 00:59:41 -07002781static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002782 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002783 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784{
2785 struct inode *inode = dentry->d_inode;
2786 struct inode_security_struct *isec = inode->i_security;
2787 u32 newsid;
2788 int rc;
2789
2790 if (strcmp(name, XATTR_NAME_SELINUX)) {
2791 /* Not an attribute we recognize, so nothing to do. */
2792 return;
2793 }
2794
Stephen Smalley12b29f32008-05-07 13:03:20 -04002795 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002797 printk(KERN_ERR "SELinux: unable to map context to SID"
2798 "for (%s, %lu), rc=%d\n",
2799 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return;
2801 }
2802
2803 isec->sid = newsid;
2804 return;
2805}
2806
David Howells8f0cfa52008-04-29 00:59:41 -07002807static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
2810}
2811
Eric Paris828dfe12008-04-17 13:17:49 -04002812static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813{
2814 return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
2815}
2816
David Howells8f0cfa52008-04-29 00:59:41 -07002817static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002819 if (strcmp(name, XATTR_NAME_SELINUX))
2820 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
2822 /* No one is allowed to remove a SELinux security label.
2823 You can change the label, but all data must be labeled. */
2824 return -EACCES;
2825}
2826
James Morrisd381d8a2005-10-30 14:59:22 -08002827/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002828 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002829 *
2830 * Permission check is handled by selinux_inode_getxattr hook.
2831 */
David P. Quigley42492592008-02-04 22:29:39 -08002832static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833{
David P. Quigley42492592008-02-04 22:29:39 -08002834 u32 size;
2835 int error;
2836 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002839 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2840 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002842 /*
2843 * If the caller has CAP_MAC_ADMIN, then get the raw context
2844 * value even if it is not defined by current policy; otherwise,
2845 * use the in-core value under current policy.
2846 * Use the non-auditing forms of the permission checks since
2847 * getxattr may be called by unprivileged processes commonly
2848 * and lack of permission just means that we fall back to the
2849 * in-core context value, not a denial.
2850 */
Eric Paris06674672008-11-11 22:02:57 +11002851 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002852 if (!error)
2853 error = security_sid_to_context_force(isec->sid, &context,
2854 &size);
2855 else
2856 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002857 if (error)
2858 return error;
2859 error = size;
2860 if (alloc) {
2861 *buffer = context;
2862 goto out_nofree;
2863 }
2864 kfree(context);
2865out_nofree:
2866 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867}
2868
2869static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002870 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871{
2872 struct inode_security_struct *isec = inode->i_security;
2873 u32 newsid;
2874 int rc;
2875
2876 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2877 return -EOPNOTSUPP;
2878
2879 if (!value || !size)
2880 return -EACCES;
2881
Eric Paris828dfe12008-04-17 13:17:49 -04002882 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 if (rc)
2884 return rc;
2885
2886 isec->sid = newsid;
2887 return 0;
2888}
2889
2890static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2891{
2892 const int len = sizeof(XATTR_NAME_SELINUX);
2893 if (buffer && len <= buffer_size)
2894 memcpy(buffer, XATTR_NAME_SELINUX, len);
2895 return len;
2896}
2897
Serge E. Hallynb5376772007-10-16 23:31:36 -07002898static int selinux_inode_need_killpriv(struct dentry *dentry)
2899{
2900 return secondary_ops->inode_need_killpriv(dentry);
2901}
2902
2903static int selinux_inode_killpriv(struct dentry *dentry)
2904{
2905 return secondary_ops->inode_killpriv(dentry);
2906}
2907
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002908static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2909{
2910 struct inode_security_struct *isec = inode->i_security;
2911 *secid = isec->sid;
2912}
2913
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914/* file security operations */
2915
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002916static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002918 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002919 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921 if (!mask) {
2922 /* No permission to check. Existence test. */
2923 return 0;
2924 }
2925
2926 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2927 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2928 mask |= MAY_APPEND;
2929
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002930 rc = file_has_perm(current, file,
2931 file_mask_to_av(inode->i_mode, mask));
2932 if (rc)
2933 return rc;
2934
2935 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936}
2937
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002938static int selinux_file_permission(struct file *file, int mask)
2939{
2940 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002941 struct file_security_struct *fsec = file->f_security;
2942 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11002943 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002944
2945 if (!mask) {
2946 /* No permission to check. Existence test. */
2947 return 0;
2948 }
2949
David Howells275bb412008-11-14 10:39:19 +11002950 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002951 && fsec->pseqno == avc_policy_seqno())
2952 return selinux_netlbl_inode_permission(inode, mask);
2953
2954 return selinux_revalidate_file_permission(file, mask);
2955}
2956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957static int selinux_file_alloc_security(struct file *file)
2958{
2959 return file_alloc_security(file);
2960}
2961
2962static void selinux_file_free_security(struct file *file)
2963{
2964 file_free_security(file);
2965}
2966
2967static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2968 unsigned long arg)
2969{
Stephen Smalley242631c2008-06-05 09:21:28 -04002970 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
Stephen Smalley242631c2008-06-05 09:21:28 -04002972 if (_IOC_DIR(cmd) & _IOC_WRITE)
2973 av |= FILE__WRITE;
2974 if (_IOC_DIR(cmd) & _IOC_READ)
2975 av |= FILE__READ;
2976 if (!av)
2977 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
Stephen Smalley242631c2008-06-05 09:21:28 -04002979 return file_has_perm(current, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980}
2981
2982static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
2983{
2984#ifndef CONFIG_PPC32
2985 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
2986 /*
2987 * We are making executable an anonymous mapping or a
2988 * private file mapping that will also be writable.
2989 * This has an additional check.
2990 */
2991 int rc = task_has_perm(current, current, PROCESS__EXECMEM);
2992 if (rc)
2993 return rc;
2994 }
2995#endif
2996
2997 if (file) {
2998 /* read access is always possible with a mapping */
2999 u32 av = FILE__READ;
3000
3001 /* write access only matters if the mapping is shared */
3002 if (shared && (prot & PROT_WRITE))
3003 av |= FILE__WRITE;
3004
3005 if (prot & PROT_EXEC)
3006 av |= FILE__EXECUTE;
3007
3008 return file_has_perm(current, file, av);
3009 }
3010 return 0;
3011}
3012
3013static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003014 unsigned long prot, unsigned long flags,
3015 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016{
Eric Parised032182007-06-28 15:55:21 -04003017 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003018 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
Eric Parised032182007-06-28 15:55:21 -04003020 if (addr < mmap_min_addr)
3021 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3022 MEMPROTECT__MMAP_ZERO, NULL);
3023 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 return rc;
3025
3026 if (selinux_checkreqprot)
3027 prot = reqprot;
3028
3029 return file_map_prot_check(file, prot,
3030 (flags & MAP_TYPE) == MAP_SHARED);
3031}
3032
3033static int selinux_file_mprotect(struct vm_area_struct *vma,
3034 unsigned long reqprot,
3035 unsigned long prot)
3036{
3037 int rc;
3038
3039 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3040 if (rc)
3041 return rc;
3042
3043 if (selinux_checkreqprot)
3044 prot = reqprot;
3045
3046#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003047 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3048 rc = 0;
3049 if (vma->vm_start >= vma->vm_mm->start_brk &&
3050 vma->vm_end <= vma->vm_mm->brk) {
3051 rc = task_has_perm(current, current,
3052 PROCESS__EXECHEAP);
3053 } else if (!vma->vm_file &&
3054 vma->vm_start <= vma->vm_mm->start_stack &&
3055 vma->vm_end >= vma->vm_mm->start_stack) {
3056 rc = task_has_perm(current, current, PROCESS__EXECSTACK);
3057 } else if (vma->vm_file && vma->anon_vma) {
3058 /*
3059 * We are making executable a file mapping that has
3060 * had some COW done. Since pages might have been
3061 * written, check ability to execute the possibly
3062 * modified content. This typically should only
3063 * occur for text relocations.
3064 */
3065 rc = file_has_perm(current, vma->vm_file,
3066 FILE__EXECMOD);
3067 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003068 if (rc)
3069 return rc;
3070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071#endif
3072
3073 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3074}
3075
3076static int selinux_file_lock(struct file *file, unsigned int cmd)
3077{
3078 return file_has_perm(current, file, FILE__LOCK);
3079}
3080
3081static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3082 unsigned long arg)
3083{
3084 int err = 0;
3085
3086 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003087 case F_SETFL:
3088 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3089 err = -EINVAL;
3090 break;
3091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
Eric Paris828dfe12008-04-17 13:17:49 -04003093 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
3094 err = file_has_perm(current, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003096 }
3097 /* fall through */
3098 case F_SETOWN:
3099 case F_SETSIG:
3100 case F_GETFL:
3101 case F_GETOWN:
3102 case F_GETSIG:
3103 /* Just check FD__USE permission */
3104 err = file_has_perm(current, file, 0);
3105 break;
3106 case F_GETLK:
3107 case F_SETLK:
3108 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003110 case F_GETLK64:
3111 case F_SETLK64:
3112 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003114 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3115 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003117 }
3118 err = file_has_perm(current, file, FILE__LOCK);
3119 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 }
3121
3122 return err;
3123}
3124
3125static int selinux_file_set_fowner(struct file *file)
3126{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 struct file_security_struct *fsec;
3128
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003130 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
3132 return 0;
3133}
3134
3135static int selinux_file_send_sigiotask(struct task_struct *tsk,
3136 struct fown_struct *fown, int signum)
3137{
Eric Paris828dfe12008-04-17 13:17:49 -04003138 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003139 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 struct file_security_struct *fsec;
3142
3143 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003144 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 fsec = file->f_security;
3147
3148 if (!signum)
3149 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3150 else
3151 perm = signal_to_av(signum);
3152
David Howells275bb412008-11-14 10:39:19 +11003153 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 SECCLASS_PROCESS, perm, NULL);
3155}
3156
3157static int selinux_file_receive(struct file *file)
3158{
3159 return file_has_perm(current, file, file_to_av(file));
3160}
3161
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003162static int selinux_dentry_open(struct file *file)
3163{
3164 struct file_security_struct *fsec;
3165 struct inode *inode;
3166 struct inode_security_struct *isec;
3167 inode = file->f_path.dentry->d_inode;
3168 fsec = file->f_security;
3169 isec = inode->i_security;
3170 /*
3171 * Save inode label and policy sequence number
3172 * at open-time so that selinux_file_permission
3173 * can determine whether revalidation is necessary.
3174 * Task label is already saved in the file security
3175 * struct as its SID.
3176 */
3177 fsec->isid = isec->sid;
3178 fsec->pseqno = avc_policy_seqno();
3179 /*
3180 * Since the inode label or policy seqno may have changed
3181 * between the selinux_inode_permission check and the saving
3182 * of state above, recheck that access is still permitted.
3183 * Otherwise, access might never be revalidated against the
3184 * new inode label or new policy.
3185 * This check is not redundant - do not remove.
3186 */
Eric Paris8b6a5a32008-10-29 17:06:46 -04003187 return inode_has_perm(current, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003188}
3189
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190/* task security operations */
3191
3192static int selinux_task_create(unsigned long clone_flags)
3193{
3194 int rc;
3195
3196 rc = secondary_ops->task_create(clone_flags);
3197 if (rc)
3198 return rc;
3199
3200 return task_has_perm(current, current, PROCESS__FORK);
3201}
3202
David Howellsf1752ee2008-11-14 10:39:17 +11003203static int selinux_cred_alloc_security(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204{
3205 struct task_security_struct *tsec1, *tsec2;
3206 int rc;
3207
David Howells275bb412008-11-14 10:39:19 +11003208 tsec1 = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
David Howellsf1752ee2008-11-14 10:39:17 +11003210 rc = cred_alloc_security(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 if (rc)
3212 return rc;
David Howellsf1752ee2008-11-14 10:39:17 +11003213 tsec2 = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 tsec2->osid = tsec1->osid;
3216 tsec2->sid = tsec1->sid;
3217
Michael LeMay28eba5b2006-06-27 02:53:42 -07003218 /* Retain the exec, fs, key, and sock SIDs across fork */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 tsec2->exec_sid = tsec1->exec_sid;
3220 tsec2->create_sid = tsec1->create_sid;
Michael LeMay28eba5b2006-06-27 02:53:42 -07003221 tsec2->keycreate_sid = tsec1->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07003222 tsec2->sockcreate_sid = tsec1->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 return 0;
3225}
3226
David Howellsf1752ee2008-11-14 10:39:17 +11003227/*
3228 * detach and free the LSM part of a set of credentials
3229 */
3230static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231{
David Howellsf1752ee2008-11-14 10:39:17 +11003232 struct task_security_struct *tsec = cred->security;
3233 cred->security = NULL;
3234 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235}
3236
3237static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3238{
3239 /* Since setuid only affects the current process, and
3240 since the SELinux controls are not based on the Linux
3241 identity attributes, SELinux does not need to control
3242 this operation. However, SELinux does control the use
3243 of the CAP_SETUID and CAP_SETGID capabilities using the
3244 capable hook. */
3245 return 0;
3246}
3247
3248static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3249{
Eric Paris828dfe12008-04-17 13:17:49 -04003250 return secondary_ops->task_post_setuid(id0, id1, id2, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251}
3252
3253static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3254{
3255 /* See the comment for setuid above. */
3256 return 0;
3257}
3258
3259static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3260{
3261 return task_has_perm(current, p, PROCESS__SETPGID);
3262}
3263
3264static int selinux_task_getpgid(struct task_struct *p)
3265{
3266 return task_has_perm(current, p, PROCESS__GETPGID);
3267}
3268
3269static int selinux_task_getsid(struct task_struct *p)
3270{
3271 return task_has_perm(current, p, PROCESS__GETSESSION);
3272}
3273
David Quigleyf9008e42006-06-30 01:55:46 -07003274static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3275{
David Howells275bb412008-11-14 10:39:19 +11003276 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003277}
3278
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279static int selinux_task_setgroups(struct group_info *group_info)
3280{
3281 /* See the comment for setuid above. */
3282 return 0;
3283}
3284
3285static int selinux_task_setnice(struct task_struct *p, int nice)
3286{
3287 int rc;
3288
3289 rc = secondary_ops->task_setnice(p, nice);
3290 if (rc)
3291 return rc;
3292
Eric Paris828dfe12008-04-17 13:17:49 -04003293 return task_has_perm(current, p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294}
3295
James Morris03e68062006-06-23 02:03:58 -07003296static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3297{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003298 int rc;
3299
3300 rc = secondary_ops->task_setioprio(p, ioprio);
3301 if (rc)
3302 return rc;
3303
James Morris03e68062006-06-23 02:03:58 -07003304 return task_has_perm(current, p, PROCESS__SETSCHED);
3305}
3306
David Quigleya1836a42006-06-30 01:55:49 -07003307static int selinux_task_getioprio(struct task_struct *p)
3308{
3309 return task_has_perm(current, p, PROCESS__GETSCHED);
3310}
3311
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3313{
3314 struct rlimit *old_rlim = current->signal->rlim + resource;
3315 int rc;
3316
3317 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3318 if (rc)
3319 return rc;
3320
3321 /* Control the ability to change the hard limit (whether
3322 lowering or raising it), so that the hard limit can
3323 later be used as a safe reset point for the soft limit
3324 upon context transitions. See selinux_bprm_apply_creds. */
3325 if (old_rlim->rlim_max != new_rlim->rlim_max)
3326 return task_has_perm(current, current, PROCESS__SETRLIMIT);
3327
3328 return 0;
3329}
3330
3331static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3332{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003333 int rc;
3334
3335 rc = secondary_ops->task_setscheduler(p, policy, lp);
3336 if (rc)
3337 return rc;
3338
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 return task_has_perm(current, p, PROCESS__SETSCHED);
3340}
3341
3342static int selinux_task_getscheduler(struct task_struct *p)
3343{
3344 return task_has_perm(current, p, PROCESS__GETSCHED);
3345}
3346
David Quigley35601542006-06-23 02:04:01 -07003347static int selinux_task_movememory(struct task_struct *p)
3348{
3349 return task_has_perm(current, p, PROCESS__SETSCHED);
3350}
3351
David Quigleyf9008e42006-06-30 01:55:46 -07003352static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3353 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354{
3355 u32 perm;
3356 int rc;
3357
David Quigleyf9008e42006-06-30 01:55:46 -07003358 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 if (rc)
3360 return rc;
3361
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 if (!sig)
3363 perm = PROCESS__SIGNULL; /* null signal; existence test */
3364 else
3365 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003366 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003367 rc = avc_has_perm(secid, task_sid(p),
3368 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003369 else
3370 rc = task_has_perm(current, p, perm);
3371 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372}
3373
3374static int selinux_task_prctl(int option,
3375 unsigned long arg2,
3376 unsigned long arg3,
3377 unsigned long arg4,
Andrew G. Morgan3898b1b2008-04-28 02:13:40 -07003378 unsigned long arg5,
3379 long *rc_p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380{
3381 /* The current prctl operations do not appear to require
3382 any SELinux controls since they merely observe or modify
3383 the state of the current process. */
Andrew G. Morgan3898b1b2008-04-28 02:13:40 -07003384 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385}
3386
3387static int selinux_task_wait(struct task_struct *p)
3388{
Eric Paris8a535142007-10-22 16:10:31 -04003389 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390}
3391
3392static void selinux_task_reparent_to_init(struct task_struct *p)
3393{
Eric Paris828dfe12008-04-17 13:17:49 -04003394 struct task_security_struct *tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
3396 secondary_ops->task_reparent_to_init(p);
3397
David Howellsb6dff3e2008-11-14 10:39:16 +11003398 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 tsec->osid = tsec->sid;
3400 tsec->sid = SECINITSID_KERNEL;
3401 return;
3402}
3403
3404static void selinux_task_to_inode(struct task_struct *p,
3405 struct inode *inode)
3406{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003408 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
David Howells275bb412008-11-14 10:39:19 +11003410 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412}
3413
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003415static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3416 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417{
3418 int offset, ihlen, ret = -EINVAL;
3419 struct iphdr _iph, *ih;
3420
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003421 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3423 if (ih == NULL)
3424 goto out;
3425
3426 ihlen = ih->ihl * 4;
3427 if (ihlen < sizeof(_iph))
3428 goto out;
3429
3430 ad->u.net.v4info.saddr = ih->saddr;
3431 ad->u.net.v4info.daddr = ih->daddr;
3432 ret = 0;
3433
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003434 if (proto)
3435 *proto = ih->protocol;
3436
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003438 case IPPROTO_TCP: {
3439 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440
Eric Paris828dfe12008-04-17 13:17:49 -04003441 if (ntohs(ih->frag_off) & IP_OFFSET)
3442 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
3444 offset += ihlen;
3445 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3446 if (th == NULL)
3447 break;
3448
3449 ad->u.net.sport = th->source;
3450 ad->u.net.dport = th->dest;
3451 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003452 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
Eric Paris828dfe12008-04-17 13:17:49 -04003454 case IPPROTO_UDP: {
3455 struct udphdr _udph, *uh;
3456
3457 if (ntohs(ih->frag_off) & IP_OFFSET)
3458 break;
3459
3460 offset += ihlen;
3461 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3462 if (uh == NULL)
3463 break;
3464
3465 ad->u.net.sport = uh->source;
3466 ad->u.net.dport = uh->dest;
3467 break;
3468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
James Morris2ee92d42006-11-13 16:09:01 -08003470 case IPPROTO_DCCP: {
3471 struct dccp_hdr _dccph, *dh;
3472
3473 if (ntohs(ih->frag_off) & IP_OFFSET)
3474 break;
3475
3476 offset += ihlen;
3477 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3478 if (dh == NULL)
3479 break;
3480
3481 ad->u.net.sport = dh->dccph_sport;
3482 ad->u.net.dport = dh->dccph_dport;
3483 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003484 }
James Morris2ee92d42006-11-13 16:09:01 -08003485
Eric Paris828dfe12008-04-17 13:17:49 -04003486 default:
3487 break;
3488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489out:
3490 return ret;
3491}
3492
3493#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3494
3495/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003496static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3497 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498{
3499 u8 nexthdr;
3500 int ret = -EINVAL, offset;
3501 struct ipv6hdr _ipv6h, *ip6;
3502
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003503 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3505 if (ip6 == NULL)
3506 goto out;
3507
3508 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3509 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3510 ret = 0;
3511
3512 nexthdr = ip6->nexthdr;
3513 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003514 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 if (offset < 0)
3516 goto out;
3517
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003518 if (proto)
3519 *proto = nexthdr;
3520
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 switch (nexthdr) {
3522 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003523 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
3525 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3526 if (th == NULL)
3527 break;
3528
3529 ad->u.net.sport = th->source;
3530 ad->u.net.dport = th->dest;
3531 break;
3532 }
3533
3534 case IPPROTO_UDP: {
3535 struct udphdr _udph, *uh;
3536
3537 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3538 if (uh == NULL)
3539 break;
3540
3541 ad->u.net.sport = uh->source;
3542 ad->u.net.dport = uh->dest;
3543 break;
3544 }
3545
James Morris2ee92d42006-11-13 16:09:01 -08003546 case IPPROTO_DCCP: {
3547 struct dccp_hdr _dccph, *dh;
3548
3549 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3550 if (dh == NULL)
3551 break;
3552
3553 ad->u.net.sport = dh->dccph_sport;
3554 ad->u.net.dport = dh->dccph_dport;
3555 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003556 }
James Morris2ee92d42006-11-13 16:09:01 -08003557
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 /* includes fragments */
3559 default:
3560 break;
3561 }
3562out:
3563 return ret;
3564}
3565
3566#endif /* IPV6 */
3567
3568static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003569 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570{
David Howellscf9481e2008-07-27 21:31:07 +10003571 char *addrp;
3572 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
3574 switch (ad->u.net.family) {
3575 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003576 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003577 if (ret)
3578 goto parse_error;
3579 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3580 &ad->u.net.v4info.daddr);
3581 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
3583#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3584 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003585 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003586 if (ret)
3587 goto parse_error;
3588 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3589 &ad->u.net.v6info.daddr);
3590 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591#endif /* IPV6 */
3592 default:
David Howellscf9481e2008-07-27 21:31:07 +10003593 addrp = NULL;
3594 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 }
3596
David Howellscf9481e2008-07-27 21:31:07 +10003597parse_error:
3598 printk(KERN_WARNING
3599 "SELinux: failure in selinux_parse_skb(),"
3600 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003602
3603okay:
3604 if (_addrp)
3605 *_addrp = addrp;
3606 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607}
3608
Paul Moore4f6a9932007-03-01 14:35:22 -05003609/**
Paul Moore220deb92008-01-29 08:38:23 -05003610 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003611 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003612 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003613 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003614 *
3615 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003616 * Check the various different forms of network peer labeling and determine
3617 * the peer label/SID for the packet; most of the magic actually occurs in
3618 * the security server function security_net_peersid_cmp(). The function
3619 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3620 * or -EACCES if @sid is invalid due to inconsistencies with the different
3621 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003622 *
3623 */
Paul Moore220deb92008-01-29 08:38:23 -05003624static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003625{
Paul Moore71f1cb02008-01-29 08:51:16 -05003626 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003627 u32 xfrm_sid;
3628 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003629 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003630
3631 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003632 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003633
Paul Moore71f1cb02008-01-29 08:51:16 -05003634 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3635 if (unlikely(err)) {
3636 printk(KERN_WARNING
3637 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3638 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003639 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003640 }
Paul Moore220deb92008-01-29 08:38:23 -05003641
3642 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003643}
3644
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645/* socket security operations */
3646static int socket_has_perm(struct task_struct *task, struct socket *sock,
3647 u32 perms)
3648{
3649 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003651 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 int err = 0;
3653
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 isec = SOCK_INODE(sock)->i_security;
3655
3656 if (isec->sid == SECINITSID_KERNEL)
3657 goto out;
David Howells275bb412008-11-14 10:39:19 +11003658 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
Eric Paris828dfe12008-04-17 13:17:49 -04003660 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003662 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663
3664out:
3665 return err;
3666}
3667
3668static int selinux_socket_create(int family, int type,
3669 int protocol, int kern)
3670{
David Howells275bb412008-11-14 10:39:19 +11003671 const struct cred *cred = current_cred();
3672 const struct task_security_struct *tsec = cred->security;
3673 u32 sid, newsid;
3674 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
3677 if (kern)
3678 goto out;
3679
David Howells275bb412008-11-14 10:39:19 +11003680 sid = tsec->sid;
3681 newsid = tsec->sockcreate_sid ?: sid;
3682
3683 secclass = socket_type_to_security_class(family, type, protocol);
3684 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
3686out:
3687 return err;
3688}
3689
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003690static int selinux_socket_post_create(struct socket *sock, int family,
3691 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692{
David Howells275bb412008-11-14 10:39:19 +11003693 const struct cred *cred = current_cred();
3694 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003696 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003697 u32 sid, newsid;
3698 int err = 0;
3699
3700 sid = tsec->sid;
3701 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
3703 isec = SOCK_INODE(sock)->i_security;
3704
David Howells275bb412008-11-14 10:39:19 +11003705 if (kern)
3706 isec->sid = SECINITSID_KERNEL;
3707 else if (newsid)
3708 isec->sid = newsid;
3709 else
3710 isec->sid = sid;
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 isec->initialized = 1;
3714
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003715 if (sock->sk) {
3716 sksec = sock->sk->sk_security;
3717 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003718 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003719 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003720 }
3721
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003722 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723}
3724
3725/* Range of port numbers used to automatically bind.
3726 Need to determine whether we should perform a name_bind
3727 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
3729static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3730{
3731 u16 family;
3732 int err;
3733
3734 err = socket_has_perm(current, sock, SOCKET__BIND);
3735 if (err)
3736 goto out;
3737
3738 /*
3739 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003740 * Multiple address binding for SCTP is not supported yet: we just
3741 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 */
3743 family = sock->sk->sk_family;
3744 if (family == PF_INET || family == PF_INET6) {
3745 char *addrp;
3746 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 struct avc_audit_data ad;
3748 struct sockaddr_in *addr4 = NULL;
3749 struct sockaddr_in6 *addr6 = NULL;
3750 unsigned short snum;
3751 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003752 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 isec = SOCK_INODE(sock)->i_security;
3755
3756 if (family == PF_INET) {
3757 addr4 = (struct sockaddr_in *)address;
3758 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 addrp = (char *)&addr4->sin_addr.s_addr;
3760 } else {
3761 addr6 = (struct sockaddr_in6 *)address;
3762 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 addrp = (char *)&addr6->sin6_addr.s6_addr;
3764 }
3765
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003766 if (snum) {
3767 int low, high;
3768
3769 inet_get_local_port_range(&low, &high);
3770
3771 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003772 err = sel_netport_sid(sk->sk_protocol,
3773 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003774 if (err)
3775 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003776 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003777 ad.u.net.sport = htons(snum);
3778 ad.u.net.family = family;
3779 err = avc_has_perm(isec->sid, sid,
3780 isec->sclass,
3781 SOCKET__NAME_BIND, &ad);
3782 if (err)
3783 goto out;
3784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 }
Eric Paris828dfe12008-04-17 13:17:49 -04003786
3787 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003788 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 node_perm = TCP_SOCKET__NODE_BIND;
3790 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003791
James Morris13402582005-09-30 14:24:34 -04003792 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 node_perm = UDP_SOCKET__NODE_BIND;
3794 break;
James Morris2ee92d42006-11-13 16:09:01 -08003795
3796 case SECCLASS_DCCP_SOCKET:
3797 node_perm = DCCP_SOCKET__NODE_BIND;
3798 break;
3799
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 default:
3801 node_perm = RAWIP_SOCKET__NODE_BIND;
3802 break;
3803 }
Eric Paris828dfe12008-04-17 13:17:49 -04003804
Paul Moore224dfbd2008-01-29 08:38:13 -05003805 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 if (err)
3807 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003808
3809 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 ad.u.net.sport = htons(snum);
3811 ad.u.net.family = family;
3812
3813 if (family == PF_INET)
3814 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3815 else
3816 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3817
3818 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003819 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 if (err)
3821 goto out;
3822 }
3823out:
3824 return err;
3825}
3826
3827static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3828{
Paul Moore014ab192008-10-10 10:16:33 -04003829 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 struct inode_security_struct *isec;
3831 int err;
3832
3833 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3834 if (err)
3835 return err;
3836
3837 /*
James Morris2ee92d42006-11-13 16:09:01 -08003838 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 */
3840 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003841 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3842 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 struct avc_audit_data ad;
3844 struct sockaddr_in *addr4 = NULL;
3845 struct sockaddr_in6 *addr6 = NULL;
3846 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003847 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848
3849 if (sk->sk_family == PF_INET) {
3850 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003851 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 return -EINVAL;
3853 snum = ntohs(addr4->sin_port);
3854 } else {
3855 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003856 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 return -EINVAL;
3858 snum = ntohs(addr6->sin6_port);
3859 }
3860
Paul Moore3e112172008-04-10 10:48:14 -04003861 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 if (err)
3863 goto out;
3864
James Morris2ee92d42006-11-13 16:09:01 -08003865 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3866 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3867
Eric Paris828dfe12008-04-17 13:17:49 -04003868 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 ad.u.net.dport = htons(snum);
3870 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003871 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 if (err)
3873 goto out;
3874 }
3875
Paul Moore014ab192008-10-10 10:16:33 -04003876 err = selinux_netlbl_socket_connect(sk, address);
3877
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878out:
3879 return err;
3880}
3881
3882static int selinux_socket_listen(struct socket *sock, int backlog)
3883{
3884 return socket_has_perm(current, sock, SOCKET__LISTEN);
3885}
3886
3887static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3888{
3889 int err;
3890 struct inode_security_struct *isec;
3891 struct inode_security_struct *newisec;
3892
3893 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3894 if (err)
3895 return err;
3896
3897 newisec = SOCK_INODE(newsock)->i_security;
3898
3899 isec = SOCK_INODE(sock)->i_security;
3900 newisec->sclass = isec->sclass;
3901 newisec->sid = isec->sid;
3902 newisec->initialized = 1;
3903
3904 return 0;
3905}
3906
3907static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003908 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003910 int rc;
3911
3912 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3913 if (rc)
3914 return rc;
3915
3916 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917}
3918
3919static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3920 int size, int flags)
3921{
3922 return socket_has_perm(current, sock, SOCKET__READ);
3923}
3924
3925static int selinux_socket_getsockname(struct socket *sock)
3926{
3927 return socket_has_perm(current, sock, SOCKET__GETATTR);
3928}
3929
3930static int selinux_socket_getpeername(struct socket *sock)
3931{
3932 return socket_has_perm(current, sock, SOCKET__GETATTR);
3933}
3934
Eric Paris828dfe12008-04-17 13:17:49 -04003935static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936{
Paul Mooref8687af2006-10-30 15:22:15 -08003937 int err;
3938
3939 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3940 if (err)
3941 return err;
3942
3943 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944}
3945
3946static int selinux_socket_getsockopt(struct socket *sock, int level,
3947 int optname)
3948{
3949 return socket_has_perm(current, sock, SOCKET__GETOPT);
3950}
3951
3952static int selinux_socket_shutdown(struct socket *sock, int how)
3953{
3954 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
3955}
3956
3957static int selinux_socket_unix_stream_connect(struct socket *sock,
3958 struct socket *other,
3959 struct sock *newsk)
3960{
3961 struct sk_security_struct *ssec;
3962 struct inode_security_struct *isec;
3963 struct inode_security_struct *other_isec;
3964 struct avc_audit_data ad;
3965 int err;
3966
3967 err = secondary_ops->unix_stream_connect(sock, other, newsk);
3968 if (err)
3969 return err;
3970
3971 isec = SOCK_INODE(sock)->i_security;
3972 other_isec = SOCK_INODE(other)->i_security;
3973
Eric Paris828dfe12008-04-17 13:17:49 -04003974 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 ad.u.net.sk = other->sk;
3976
3977 err = avc_has_perm(isec->sid, other_isec->sid,
3978 isec->sclass,
3979 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
3980 if (err)
3981 return err;
3982
3983 /* connecting socket */
3984 ssec = sock->sk->sk_security;
3985 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04003986
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 /* server child socket */
3988 ssec = newsk->sk_security;
3989 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07003990 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
3991
3992 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993}
3994
3995static int selinux_socket_unix_may_send(struct socket *sock,
3996 struct socket *other)
3997{
3998 struct inode_security_struct *isec;
3999 struct inode_security_struct *other_isec;
4000 struct avc_audit_data ad;
4001 int err;
4002
4003 isec = SOCK_INODE(sock)->i_security;
4004 other_isec = SOCK_INODE(other)->i_security;
4005
Eric Paris828dfe12008-04-17 13:17:49 -04004006 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 ad.u.net.sk = other->sk;
4008
4009 err = avc_has_perm(isec->sid, other_isec->sid,
4010 isec->sclass, SOCKET__SENDTO, &ad);
4011 if (err)
4012 return err;
4013
4014 return 0;
4015}
4016
Paul Mooreeffad8d2008-01-29 08:49:27 -05004017static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4018 u32 peer_sid,
4019 struct avc_audit_data *ad)
4020{
4021 int err;
4022 u32 if_sid;
4023 u32 node_sid;
4024
4025 err = sel_netif_sid(ifindex, &if_sid);
4026 if (err)
4027 return err;
4028 err = avc_has_perm(peer_sid, if_sid,
4029 SECCLASS_NETIF, NETIF__INGRESS, ad);
4030 if (err)
4031 return err;
4032
4033 err = sel_netnode_sid(addrp, family, &node_sid);
4034 if (err)
4035 return err;
4036 return avc_has_perm(peer_sid, node_sid,
4037 SECCLASS_NODE, NODE__RECVFROM, ad);
4038}
4039
Paul Moore220deb92008-01-29 08:38:23 -05004040static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4041 struct sk_buff *skb,
4042 struct avc_audit_data *ad,
4043 u16 family,
4044 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045{
Paul Moore220deb92008-01-29 08:38:23 -05004046 int err;
4047 struct sk_security_struct *sksec = sk->sk_security;
4048 u16 sk_class;
4049 u32 netif_perm, node_perm, recv_perm;
4050 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004051
Paul Moore220deb92008-01-29 08:38:23 -05004052 sk_sid = sksec->sid;
4053 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
Paul Moore220deb92008-01-29 08:38:23 -05004055 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 case SECCLASS_UDP_SOCKET:
4057 netif_perm = NETIF__UDP_RECV;
4058 node_perm = NODE__UDP_RECV;
4059 recv_perm = UDP_SOCKET__RECV_MSG;
4060 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 case SECCLASS_TCP_SOCKET:
4062 netif_perm = NETIF__TCP_RECV;
4063 node_perm = NODE__TCP_RECV;
4064 recv_perm = TCP_SOCKET__RECV_MSG;
4065 break;
James Morris2ee92d42006-11-13 16:09:01 -08004066 case SECCLASS_DCCP_SOCKET:
4067 netif_perm = NETIF__DCCP_RECV;
4068 node_perm = NODE__DCCP_RECV;
4069 recv_perm = DCCP_SOCKET__RECV_MSG;
4070 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 default:
4072 netif_perm = NETIF__RAWIP_RECV;
4073 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004074 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 break;
4076 }
4077
Paul Moore220deb92008-01-29 08:38:23 -05004078 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004080 return err;
4081 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4082 if (err)
4083 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004084
Paul Moore224dfbd2008-01-29 08:38:13 -05004085 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004087 return err;
4088 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004090 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
Paul Moore220deb92008-01-29 08:38:23 -05004092 if (!recv_perm)
4093 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004094 err = sel_netport_sid(sk->sk_protocol,
4095 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004096 if (unlikely(err)) {
4097 printk(KERN_WARNING
4098 "SELinux: failure in"
4099 " selinux_sock_rcv_skb_iptables_compat(),"
4100 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004101 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004102 }
Paul Moore220deb92008-01-29 08:38:23 -05004103 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4104}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105
Paul Moore220deb92008-01-29 08:38:23 -05004106static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004107 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004108{
4109 int err;
4110 struct sk_security_struct *sksec = sk->sk_security;
4111 u32 peer_sid;
4112 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004113 struct avc_audit_data ad;
4114 char *addrp;
4115
4116 AVC_AUDIT_DATA_INIT(&ad, NET);
4117 ad.u.net.netif = skb->iif;
4118 ad.u.net.family = family;
4119 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4120 if (err)
4121 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004122
4123 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004124 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004125 family, addrp);
4126 else
4127 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004128 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004129 if (err)
4130 return err;
4131
4132 if (selinux_policycap_netpeer) {
4133 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004135 return err;
4136 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004137 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004138 if (err)
4139 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004140 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004141 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004142 if (err)
4143 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004144 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004146
James Morris4e5ab4c2006-06-09 00:33:33 -07004147 return err;
4148}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004149
James Morris4e5ab4c2006-06-09 00:33:33 -07004150static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4151{
Paul Moore220deb92008-01-29 08:38:23 -05004152 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004153 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004154 u16 family = sk->sk_family;
4155 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004156 struct avc_audit_data ad;
4157 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004158 u8 secmark_active;
4159 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004160
James Morris4e5ab4c2006-06-09 00:33:33 -07004161 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004162 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004163
4164 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004165 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004166 family = PF_INET;
4167
Paul Moored8395c82008-10-10 10:16:30 -04004168 /* If any sort of compatibility mode is enabled then handoff processing
4169 * to the selinux_sock_rcv_skb_compat() function to deal with the
4170 * special handling. We do this in an attempt to keep this function
4171 * as fast and as clean as possible. */
4172 if (selinux_compat_net || !selinux_policycap_netpeer)
4173 return selinux_sock_rcv_skb_compat(sk, skb, family);
4174
4175 secmark_active = selinux_secmark_enabled();
4176 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4177 if (!secmark_active && !peerlbl_active)
4178 return 0;
4179
James Morris4e5ab4c2006-06-09 00:33:33 -07004180 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004181 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004182 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004183 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004184 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004185 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004186
Paul Moored8395c82008-10-10 10:16:30 -04004187 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004188 u32 peer_sid;
4189
4190 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4191 if (err)
4192 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004193 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4194 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004195 if (err) {
4196 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004197 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004198 }
Paul Moored621d352008-01-29 08:43:36 -05004199 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4200 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004201 if (err)
4202 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004203 }
4204
Paul Moored8395c82008-10-10 10:16:30 -04004205 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004206 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4207 PACKET__RECV, &ad);
4208 if (err)
4209 return err;
4210 }
4211
Paul Moored621d352008-01-29 08:43:36 -05004212 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213}
4214
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004215static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4216 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218 int err = 0;
4219 char *scontext;
4220 u32 scontext_len;
4221 struct sk_security_struct *ssec;
4222 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004223 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224
4225 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004226
Paul Moore3de4bab2006-11-17 17:38:54 -05004227 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4228 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004229 ssec = sock->sk->sk_security;
4230 peer_sid = ssec->peer_sid;
4231 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004232 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 err = -ENOPROTOOPT;
4234 goto out;
4235 }
4236
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004237 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4238
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 if (err)
4240 goto out;
4241
4242 if (scontext_len > len) {
4243 err = -ERANGE;
4244 goto out_len;
4245 }
4246
4247 if (copy_to_user(optval, scontext, scontext_len))
4248 err = -EFAULT;
4249
4250out_len:
4251 if (put_user(scontext_len, optlen))
4252 err = -EFAULT;
4253
4254 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004255out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 return err;
4257}
4258
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004259static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004260{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004261 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004262 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004263
Paul Mooreaa862902008-10-10 10:16:29 -04004264 if (skb && skb->protocol == htons(ETH_P_IP))
4265 family = PF_INET;
4266 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4267 family = PF_INET6;
4268 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004269 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004270 else
4271 goto out;
4272
4273 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004274 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004275 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004276 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004277
Paul Moore75e22912008-01-29 08:38:04 -05004278out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004279 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004280 if (peer_secid == SECSID_NULL)
4281 return -EINVAL;
4282 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004283}
4284
Al Viro7d877f32005-10-21 03:20:43 -04004285static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286{
4287 return sk_alloc_security(sk, family, priority);
4288}
4289
4290static void selinux_sk_free_security(struct sock *sk)
4291{
4292 sk_free_security(sk);
4293}
4294
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004295static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4296{
4297 struct sk_security_struct *ssec = sk->sk_security;
4298 struct sk_security_struct *newssec = newsk->sk_security;
4299
4300 newssec->sid = ssec->sid;
4301 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004302 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004303
Paul Mooref74af6e2008-02-25 11:40:33 -05004304 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004305}
4306
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004307static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004308{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004309 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004310 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004311 else {
4312 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004313
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004314 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004315 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004316}
4317
Eric Paris828dfe12008-04-17 13:17:49 -04004318static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004319{
4320 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4321 struct sk_security_struct *sksec = sk->sk_security;
4322
David Woodhouse2148ccc2006-09-29 15:50:25 -07004323 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4324 sk->sk_family == PF_UNIX)
4325 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004326 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004327}
4328
Adrian Bunk9a673e52006-08-15 00:03:53 -07004329static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4330 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004331{
4332 struct sk_security_struct *sksec = sk->sk_security;
4333 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004334 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004335 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004336 u32 peersid;
4337
Paul Mooreaa862902008-10-10 10:16:29 -04004338 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4339 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4340 family = PF_INET;
4341
4342 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004343 if (err)
4344 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004345 if (peersid == SECSID_NULL) {
4346 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004347 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004348 return 0;
4349 }
4350
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004351 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4352 if (err)
4353 return err;
4354
4355 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004356 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004357 return 0;
4358}
4359
Adrian Bunk9a673e52006-08-15 00:03:53 -07004360static void selinux_inet_csk_clone(struct sock *newsk,
4361 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004362{
4363 struct sk_security_struct *newsksec = newsk->sk_security;
4364
4365 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004366 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004367 /* NOTE: Ideally, we should also get the isec->sid for the
4368 new socket in sync, but we don't have the isec available yet.
4369 So we will wait until sock_graft to do it, by which
4370 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004371
Paul Moore9f2ad662006-11-17 17:38:53 -05004372 /* We don't need to take any sort of lock here as we are the only
4373 * thread with access to newsksec */
4374 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004375}
4376
Paul Moore014ab192008-10-10 10:16:33 -04004377static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004378{
Paul Mooreaa862902008-10-10 10:16:29 -04004379 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004380 struct sk_security_struct *sksec = sk->sk_security;
4381
Paul Mooreaa862902008-10-10 10:16:29 -04004382 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4383 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4384 family = PF_INET;
4385
4386 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004387
4388 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004389}
4390
Adrian Bunk9a673e52006-08-15 00:03:53 -07004391static void selinux_req_classify_flow(const struct request_sock *req,
4392 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004393{
4394 fl->secid = req->secid;
4395}
4396
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4398{
4399 int err = 0;
4400 u32 perm;
4401 struct nlmsghdr *nlh;
4402 struct socket *sock = sk->sk_socket;
4403 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004404
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 if (skb->len < NLMSG_SPACE(0)) {
4406 err = -EINVAL;
4407 goto out;
4408 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004409 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004410
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4412 if (err) {
4413 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004414 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 "SELinux: unrecognized netlink message"
4416 " type=%hu for sclass=%hu\n",
4417 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004418 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 err = 0;
4420 }
4421
4422 /* Ignore */
4423 if (err == -ENOENT)
4424 err = 0;
4425 goto out;
4426 }
4427
4428 err = socket_has_perm(current, sock, perm);
4429out:
4430 return err;
4431}
4432
4433#ifdef CONFIG_NETFILTER
4434
Paul Mooreeffad8d2008-01-29 08:49:27 -05004435static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4436 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437{
Paul Mooredfaebe92008-10-10 10:16:31 -04004438 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004439 char *addrp;
4440 u32 peer_sid;
4441 struct avc_audit_data ad;
4442 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004443 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004444 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004445
Paul Mooreeffad8d2008-01-29 08:49:27 -05004446 if (!selinux_policycap_netpeer)
4447 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004448
Paul Mooreeffad8d2008-01-29 08:49:27 -05004449 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004450 netlbl_active = netlbl_enabled();
4451 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004452 if (!secmark_active && !peerlbl_active)
4453 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004454
Paul Moored8395c82008-10-10 10:16:30 -04004455 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4456 return NF_DROP;
4457
Paul Mooreeffad8d2008-01-29 08:49:27 -05004458 AVC_AUDIT_DATA_INIT(&ad, NET);
4459 ad.u.net.netif = ifindex;
4460 ad.u.net.family = family;
4461 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4462 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463
Paul Mooredfaebe92008-10-10 10:16:31 -04004464 if (peerlbl_active) {
4465 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4466 peer_sid, &ad);
4467 if (err) {
4468 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004469 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004470 }
4471 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004472
4473 if (secmark_active)
4474 if (avc_has_perm(peer_sid, skb->secmark,
4475 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4476 return NF_DROP;
4477
Paul Moore948bf852008-10-10 10:16:32 -04004478 if (netlbl_active)
4479 /* we do this in the FORWARD path and not the POST_ROUTING
4480 * path because we want to make sure we apply the necessary
4481 * labeling before IPsec is applied so we can leverage AH
4482 * protection */
4483 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4484 return NF_DROP;
4485
Paul Mooreeffad8d2008-01-29 08:49:27 -05004486 return NF_ACCEPT;
4487}
4488
4489static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4490 struct sk_buff *skb,
4491 const struct net_device *in,
4492 const struct net_device *out,
4493 int (*okfn)(struct sk_buff *))
4494{
4495 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4496}
4497
4498#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4499static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4500 struct sk_buff *skb,
4501 const struct net_device *in,
4502 const struct net_device *out,
4503 int (*okfn)(struct sk_buff *))
4504{
4505 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4506}
4507#endif /* IPV6 */
4508
Paul Moore948bf852008-10-10 10:16:32 -04004509static unsigned int selinux_ip_output(struct sk_buff *skb,
4510 u16 family)
4511{
4512 u32 sid;
4513
4514 if (!netlbl_enabled())
4515 return NF_ACCEPT;
4516
4517 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4518 * because we want to make sure we apply the necessary labeling
4519 * before IPsec is applied so we can leverage AH protection */
4520 if (skb->sk) {
4521 struct sk_security_struct *sksec = skb->sk->sk_security;
4522 sid = sksec->sid;
4523 } else
4524 sid = SECINITSID_KERNEL;
4525 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4526 return NF_DROP;
4527
4528 return NF_ACCEPT;
4529}
4530
4531static unsigned int selinux_ipv4_output(unsigned int hooknum,
4532 struct sk_buff *skb,
4533 const struct net_device *in,
4534 const struct net_device *out,
4535 int (*okfn)(struct sk_buff *))
4536{
4537 return selinux_ip_output(skb, PF_INET);
4538}
4539
Paul Mooreeffad8d2008-01-29 08:49:27 -05004540static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4541 int ifindex,
4542 struct avc_audit_data *ad,
4543 u16 family, char *addrp)
4544{
4545 int err;
4546 struct sk_security_struct *sksec = sk->sk_security;
4547 u16 sk_class;
4548 u32 netif_perm, node_perm, send_perm;
4549 u32 port_sid, node_sid, if_sid, sk_sid;
4550
4551 sk_sid = sksec->sid;
4552 sk_class = sksec->sclass;
4553
4554 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 case SECCLASS_UDP_SOCKET:
4556 netif_perm = NETIF__UDP_SEND;
4557 node_perm = NODE__UDP_SEND;
4558 send_perm = UDP_SOCKET__SEND_MSG;
4559 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 case SECCLASS_TCP_SOCKET:
4561 netif_perm = NETIF__TCP_SEND;
4562 node_perm = NODE__TCP_SEND;
4563 send_perm = TCP_SOCKET__SEND_MSG;
4564 break;
James Morris2ee92d42006-11-13 16:09:01 -08004565 case SECCLASS_DCCP_SOCKET:
4566 netif_perm = NETIF__DCCP_SEND;
4567 node_perm = NODE__DCCP_SEND;
4568 send_perm = DCCP_SOCKET__SEND_MSG;
4569 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 default:
4571 netif_perm = NETIF__RAWIP_SEND;
4572 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004573 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 break;
4575 }
4576
Paul Mooreeffad8d2008-01-29 08:49:27 -05004577 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004578 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004579 return err;
4580 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4581 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004582
Paul Moore224dfbd2008-01-29 08:38:13 -05004583 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004584 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004585 return err;
4586 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004587 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004588 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589
Paul Mooreeffad8d2008-01-29 08:49:27 -05004590 if (send_perm != 0)
4591 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592
Paul Moore3e112172008-04-10 10:48:14 -04004593 err = sel_netport_sid(sk->sk_protocol,
4594 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004595 if (unlikely(err)) {
4596 printk(KERN_WARNING
4597 "SELinux: failure in"
4598 " selinux_ip_postroute_iptables_compat(),"
4599 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004600 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004601 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004602 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004603}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
Paul Mooreeffad8d2008-01-29 08:49:27 -05004605static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4606 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004607 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004608{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004609 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004610 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004611 struct avc_audit_data ad;
4612 char *addrp;
4613 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004614
Paul Mooreeffad8d2008-01-29 08:49:27 -05004615 if (sk == NULL)
4616 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004617 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004618
Paul Moored8395c82008-10-10 10:16:30 -04004619 AVC_AUDIT_DATA_INIT(&ad, NET);
4620 ad.u.net.netif = ifindex;
4621 ad.u.net.family = family;
4622 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4623 return NF_DROP;
4624
Paul Mooreeffad8d2008-01-29 08:49:27 -05004625 if (selinux_compat_net) {
4626 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004627 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004628 return NF_DROP;
4629 } else {
4630 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004631 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004632 return NF_DROP;
4633 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004634
Paul Mooreeffad8d2008-01-29 08:49:27 -05004635 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004636 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004637 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004638
Paul Mooreeffad8d2008-01-29 08:49:27 -05004639 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640}
4641
Paul Mooreeffad8d2008-01-29 08:49:27 -05004642static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4643 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004645 u32 secmark_perm;
4646 u32 peer_sid;
4647 struct sock *sk;
4648 struct avc_audit_data ad;
4649 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004650 u8 secmark_active;
4651 u8 peerlbl_active;
4652
Paul Mooreeffad8d2008-01-29 08:49:27 -05004653 /* If any sort of compatibility mode is enabled then handoff processing
4654 * to the selinux_ip_postroute_compat() function to deal with the
4655 * special handling. We do this in an attempt to keep this function
4656 * as fast and as clean as possible. */
4657 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004658 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004659
4660 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4661 * packet transformation so allow the packet to pass without any checks
4662 * since we'll have another chance to perform access control checks
4663 * when the packet is on it's final way out.
4664 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4665 * is NULL, in this case go ahead and apply access control. */
4666 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4667 return NF_ACCEPT;
4668
4669 secmark_active = selinux_secmark_enabled();
4670 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4671 if (!secmark_active && !peerlbl_active)
4672 return NF_ACCEPT;
4673
Paul Moored8395c82008-10-10 10:16:30 -04004674 /* if the packet is being forwarded then get the peer label from the
4675 * packet itself; otherwise check to see if it is from a local
4676 * application or the kernel, if from an application get the peer label
4677 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004678 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004679 if (sk == NULL) {
4680 switch (family) {
4681 case PF_INET:
4682 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4683 secmark_perm = PACKET__FORWARD_OUT;
4684 else
4685 secmark_perm = PACKET__SEND;
4686 break;
4687 case PF_INET6:
4688 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4689 secmark_perm = PACKET__FORWARD_OUT;
4690 else
4691 secmark_perm = PACKET__SEND;
4692 break;
4693 default:
4694 return NF_DROP;
4695 }
4696 if (secmark_perm == PACKET__FORWARD_OUT) {
4697 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4698 return NF_DROP;
4699 } else
4700 peer_sid = SECINITSID_KERNEL;
4701 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004702 struct sk_security_struct *sksec = sk->sk_security;
4703 peer_sid = sksec->sid;
4704 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004705 }
4706
Paul Moored8395c82008-10-10 10:16:30 -04004707 AVC_AUDIT_DATA_INIT(&ad, NET);
4708 ad.u.net.netif = ifindex;
4709 ad.u.net.family = family;
4710 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4711 return NF_DROP;
4712
Paul Mooreeffad8d2008-01-29 08:49:27 -05004713 if (secmark_active)
4714 if (avc_has_perm(peer_sid, skb->secmark,
4715 SECCLASS_PACKET, secmark_perm, &ad))
4716 return NF_DROP;
4717
4718 if (peerlbl_active) {
4719 u32 if_sid;
4720 u32 node_sid;
4721
4722 if (sel_netif_sid(ifindex, &if_sid))
4723 return NF_DROP;
4724 if (avc_has_perm(peer_sid, if_sid,
4725 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4726 return NF_DROP;
4727
4728 if (sel_netnode_sid(addrp, family, &node_sid))
4729 return NF_DROP;
4730 if (avc_has_perm(peer_sid, node_sid,
4731 SECCLASS_NODE, NODE__SENDTO, &ad))
4732 return NF_DROP;
4733 }
4734
4735 return NF_ACCEPT;
4736}
4737
4738static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4739 struct sk_buff *skb,
4740 const struct net_device *in,
4741 const struct net_device *out,
4742 int (*okfn)(struct sk_buff *))
4743{
4744 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745}
4746
4747#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004748static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4749 struct sk_buff *skb,
4750 const struct net_device *in,
4751 const struct net_device *out,
4752 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004754 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756#endif /* IPV6 */
4757
4758#endif /* CONFIG_NETFILTER */
4759
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4761{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 int err;
4763
4764 err = secondary_ops->netlink_send(sk, skb);
4765 if (err)
4766 return err;
4767
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4769 err = selinux_nlmsg_perm(sk, skb);
4770
4771 return err;
4772}
4773
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004774static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004776 int err;
4777 struct avc_audit_data ad;
4778
4779 err = secondary_ops->netlink_recv(skb, capability);
4780 if (err)
4781 return err;
4782
4783 AVC_AUDIT_DATA_INIT(&ad, CAP);
4784 ad.u.cap = capability;
4785
4786 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004787 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788}
4789
4790static int ipc_alloc_security(struct task_struct *task,
4791 struct kern_ipc_perm *perm,
4792 u16 sclass)
4793{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004795 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
James Morris89d155e2005-10-30 14:59:21 -08004797 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 if (!isec)
4799 return -ENOMEM;
4800
David Howells275bb412008-11-14 10:39:19 +11004801 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004803 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 perm->security = isec;
4805
4806 return 0;
4807}
4808
4809static void ipc_free_security(struct kern_ipc_perm *perm)
4810{
4811 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 perm->security = NULL;
4813 kfree(isec);
4814}
4815
4816static int msg_msg_alloc_security(struct msg_msg *msg)
4817{
4818 struct msg_security_struct *msec;
4819
James Morris89d155e2005-10-30 14:59:21 -08004820 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 if (!msec)
4822 return -ENOMEM;
4823
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 msec->sid = SECINITSID_UNLABELED;
4825 msg->security = msec;
4826
4827 return 0;
4828}
4829
4830static void msg_msg_free_security(struct msg_msg *msg)
4831{
4832 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
4834 msg->security = NULL;
4835 kfree(msec);
4836}
4837
4838static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004839 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 struct ipc_security_struct *isec;
4842 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004843 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 isec = ipc_perms->security;
4846
4847 AVC_AUDIT_DATA_INIT(&ad, IPC);
4848 ad.u.ipc_id = ipc_perms->key;
4849
David Howells275bb412008-11-14 10:39:19 +11004850 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851}
4852
4853static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4854{
4855 return msg_msg_alloc_security(msg);
4856}
4857
4858static void selinux_msg_msg_free_security(struct msg_msg *msg)
4859{
4860 msg_msg_free_security(msg);
4861}
4862
4863/* message queue security operations */
4864static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4865{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 struct ipc_security_struct *isec;
4867 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004868 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 int rc;
4870
4871 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4872 if (rc)
4873 return rc;
4874
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 isec = msq->q_perm.security;
4876
4877 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004878 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879
David Howells275bb412008-11-14 10:39:19 +11004880 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 MSGQ__CREATE, &ad);
4882 if (rc) {
4883 ipc_free_security(&msq->q_perm);
4884 return rc;
4885 }
4886 return 0;
4887}
4888
4889static void selinux_msg_queue_free_security(struct msg_queue *msq)
4890{
4891 ipc_free_security(&msq->q_perm);
4892}
4893
4894static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4895{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 struct ipc_security_struct *isec;
4897 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004898 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 isec = msq->q_perm.security;
4901
4902 AVC_AUDIT_DATA_INIT(&ad, IPC);
4903 ad.u.ipc_id = msq->q_perm.key;
4904
David Howells275bb412008-11-14 10:39:19 +11004905 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 MSGQ__ASSOCIATE, &ad);
4907}
4908
4909static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4910{
4911 int err;
4912 int perms;
4913
Eric Paris828dfe12008-04-17 13:17:49 -04004914 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 case IPC_INFO:
4916 case MSG_INFO:
4917 /* No specific object, just general system-wide information. */
4918 return task_has_system(current, SYSTEM__IPC_INFO);
4919 case IPC_STAT:
4920 case MSG_STAT:
4921 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4922 break;
4923 case IPC_SET:
4924 perms = MSGQ__SETATTR;
4925 break;
4926 case IPC_RMID:
4927 perms = MSGQ__DESTROY;
4928 break;
4929 default:
4930 return 0;
4931 }
4932
Stephen Smalley6af963f2005-05-01 08:58:39 -07004933 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 return err;
4935}
4936
4937static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4938{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 struct ipc_security_struct *isec;
4940 struct msg_security_struct *msec;
4941 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004942 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 int rc;
4944
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 isec = msq->q_perm.security;
4946 msec = msg->security;
4947
4948 /*
4949 * First time through, need to assign label to the message
4950 */
4951 if (msec->sid == SECINITSID_UNLABELED) {
4952 /*
4953 * Compute new sid based on current process and
4954 * message queue this message will be stored in
4955 */
David Howells275bb412008-11-14 10:39:19 +11004956 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 &msec->sid);
4958 if (rc)
4959 return rc;
4960 }
4961
4962 AVC_AUDIT_DATA_INIT(&ad, IPC);
4963 ad.u.ipc_id = msq->q_perm.key;
4964
4965 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004966 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 MSGQ__WRITE, &ad);
4968 if (!rc)
4969 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11004970 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
4971 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 if (!rc)
4973 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11004974 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
4975 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976
4977 return rc;
4978}
4979
4980static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
4981 struct task_struct *target,
4982 long type, int mode)
4983{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 struct ipc_security_struct *isec;
4985 struct msg_security_struct *msec;
4986 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004987 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 int rc;
4989
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 isec = msq->q_perm.security;
4991 msec = msg->security;
4992
4993 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004994 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995
David Howells275bb412008-11-14 10:39:19 +11004996 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 SECCLASS_MSGQ, MSGQ__READ, &ad);
4998 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11004999 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 SECCLASS_MSG, MSG__RECEIVE, &ad);
5001 return rc;
5002}
5003
5004/* Shared Memory security operations */
5005static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5006{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 struct ipc_security_struct *isec;
5008 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005009 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010 int rc;
5011
5012 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5013 if (rc)
5014 return rc;
5015
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 isec = shp->shm_perm.security;
5017
5018 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005019 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020
David Howells275bb412008-11-14 10:39:19 +11005021 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022 SHM__CREATE, &ad);
5023 if (rc) {
5024 ipc_free_security(&shp->shm_perm);
5025 return rc;
5026 }
5027 return 0;
5028}
5029
5030static void selinux_shm_free_security(struct shmid_kernel *shp)
5031{
5032 ipc_free_security(&shp->shm_perm);
5033}
5034
5035static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5036{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 struct ipc_security_struct *isec;
5038 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005039 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 isec = shp->shm_perm.security;
5042
5043 AVC_AUDIT_DATA_INIT(&ad, IPC);
5044 ad.u.ipc_id = shp->shm_perm.key;
5045
David Howells275bb412008-11-14 10:39:19 +11005046 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 SHM__ASSOCIATE, &ad);
5048}
5049
5050/* Note, at this point, shp is locked down */
5051static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5052{
5053 int perms;
5054 int err;
5055
Eric Paris828dfe12008-04-17 13:17:49 -04005056 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 case IPC_INFO:
5058 case SHM_INFO:
5059 /* No specific object, just general system-wide information. */
5060 return task_has_system(current, SYSTEM__IPC_INFO);
5061 case IPC_STAT:
5062 case SHM_STAT:
5063 perms = SHM__GETATTR | SHM__ASSOCIATE;
5064 break;
5065 case IPC_SET:
5066 perms = SHM__SETATTR;
5067 break;
5068 case SHM_LOCK:
5069 case SHM_UNLOCK:
5070 perms = SHM__LOCK;
5071 break;
5072 case IPC_RMID:
5073 perms = SHM__DESTROY;
5074 break;
5075 default:
5076 return 0;
5077 }
5078
Stephen Smalley6af963f2005-05-01 08:58:39 -07005079 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 return err;
5081}
5082
5083static int selinux_shm_shmat(struct shmid_kernel *shp,
5084 char __user *shmaddr, int shmflg)
5085{
5086 u32 perms;
5087 int rc;
5088
5089 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5090 if (rc)
5091 return rc;
5092
5093 if (shmflg & SHM_RDONLY)
5094 perms = SHM__READ;
5095 else
5096 perms = SHM__READ | SHM__WRITE;
5097
Stephen Smalley6af963f2005-05-01 08:58:39 -07005098 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099}
5100
5101/* Semaphore security operations */
5102static int selinux_sem_alloc_security(struct sem_array *sma)
5103{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 struct ipc_security_struct *isec;
5105 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005106 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 int rc;
5108
5109 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5110 if (rc)
5111 return rc;
5112
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 isec = sma->sem_perm.security;
5114
5115 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005116 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117
David Howells275bb412008-11-14 10:39:19 +11005118 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 SEM__CREATE, &ad);
5120 if (rc) {
5121 ipc_free_security(&sma->sem_perm);
5122 return rc;
5123 }
5124 return 0;
5125}
5126
5127static void selinux_sem_free_security(struct sem_array *sma)
5128{
5129 ipc_free_security(&sma->sem_perm);
5130}
5131
5132static int selinux_sem_associate(struct sem_array *sma, int semflg)
5133{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 struct ipc_security_struct *isec;
5135 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005136 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 isec = sma->sem_perm.security;
5139
5140 AVC_AUDIT_DATA_INIT(&ad, IPC);
5141 ad.u.ipc_id = sma->sem_perm.key;
5142
David Howells275bb412008-11-14 10:39:19 +11005143 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 SEM__ASSOCIATE, &ad);
5145}
5146
5147/* Note, at this point, sma is locked down */
5148static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5149{
5150 int err;
5151 u32 perms;
5152
Eric Paris828dfe12008-04-17 13:17:49 -04005153 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 case IPC_INFO:
5155 case SEM_INFO:
5156 /* No specific object, just general system-wide information. */
5157 return task_has_system(current, SYSTEM__IPC_INFO);
5158 case GETPID:
5159 case GETNCNT:
5160 case GETZCNT:
5161 perms = SEM__GETATTR;
5162 break;
5163 case GETVAL:
5164 case GETALL:
5165 perms = SEM__READ;
5166 break;
5167 case SETVAL:
5168 case SETALL:
5169 perms = SEM__WRITE;
5170 break;
5171 case IPC_RMID:
5172 perms = SEM__DESTROY;
5173 break;
5174 case IPC_SET:
5175 perms = SEM__SETATTR;
5176 break;
5177 case IPC_STAT:
5178 case SEM_STAT:
5179 perms = SEM__GETATTR | SEM__ASSOCIATE;
5180 break;
5181 default:
5182 return 0;
5183 }
5184
Stephen Smalley6af963f2005-05-01 08:58:39 -07005185 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 return err;
5187}
5188
5189static int selinux_sem_semop(struct sem_array *sma,
5190 struct sembuf *sops, unsigned nsops, int alter)
5191{
5192 u32 perms;
5193
5194 if (alter)
5195 perms = SEM__READ | SEM__WRITE;
5196 else
5197 perms = SEM__READ;
5198
Stephen Smalley6af963f2005-05-01 08:58:39 -07005199 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200}
5201
5202static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5203{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 u32 av = 0;
5205
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 av = 0;
5207 if (flag & S_IRUGO)
5208 av |= IPC__UNIX_READ;
5209 if (flag & S_IWUGO)
5210 av |= IPC__UNIX_WRITE;
5211
5212 if (av == 0)
5213 return 0;
5214
Stephen Smalley6af963f2005-05-01 08:58:39 -07005215 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216}
5217
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005218static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5219{
5220 struct ipc_security_struct *isec = ipcp->security;
5221 *secid = isec->sid;
5222}
5223
Eric Paris828dfe12008-04-17 13:17:49 -04005224static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225{
5226 if (inode)
5227 inode_doinit_with_dentry(inode, dentry);
5228}
5229
5230static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005231 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232{
David Howells275bb412008-11-14 10:39:19 +11005233 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005234 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005236 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237
5238 if (current != p) {
5239 error = task_has_perm(current, p, PROCESS__GETATTR);
5240 if (error)
5241 return error;
5242 }
5243
David Howells275bb412008-11-14 10:39:19 +11005244 rcu_read_lock();
5245 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
5247 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005248 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005250 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005252 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005254 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005255 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005256 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005257 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005258 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 else
David Howells275bb412008-11-14 10:39:19 +11005260 goto invalid;
5261 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262
5263 if (!sid)
5264 return 0;
5265
Al Viro04ff9702007-03-12 16:17:58 +00005266 error = security_sid_to_context(sid, value, &len);
5267 if (error)
5268 return error;
5269 return len;
David Howells275bb412008-11-14 10:39:19 +11005270
5271invalid:
5272 rcu_read_unlock();
5273 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274}
5275
5276static int selinux_setprocattr(struct task_struct *p,
5277 char *name, void *value, size_t size)
5278{
5279 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005280 struct task_struct *tracer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 u32 sid = 0;
5282 int error;
5283 char *str = value;
5284
5285 if (current != p) {
5286 /* SELinux only allows a process to change its own
5287 security attributes. */
5288 return -EACCES;
5289 }
5290
5291 /*
5292 * Basic control over ability to set these attributes at all.
5293 * current == p, but we'll pass them separately in case the
5294 * above restriction is ever removed.
5295 */
5296 if (!strcmp(name, "exec"))
5297 error = task_has_perm(current, p, PROCESS__SETEXEC);
5298 else if (!strcmp(name, "fscreate"))
5299 error = task_has_perm(current, p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005300 else if (!strcmp(name, "keycreate"))
5301 error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005302 else if (!strcmp(name, "sockcreate"))
5303 error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 else if (!strcmp(name, "current"))
5305 error = task_has_perm(current, p, PROCESS__SETCURRENT);
5306 else
5307 error = -EINVAL;
5308 if (error)
5309 return error;
5310
5311 /* Obtain a SID for the context, if one was specified. */
5312 if (size && str[1] && str[1] != '\n') {
5313 if (str[size-1] == '\n') {
5314 str[size-1] = 0;
5315 size--;
5316 }
5317 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005318 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5319 if (!capable(CAP_MAC_ADMIN))
5320 return error;
5321 error = security_context_to_sid_force(value, size,
5322 &sid);
5323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 if (error)
5325 return error;
5326 }
5327
5328 /* Permission checking based on the specified context is
5329 performed during the actual operation (execve,
5330 open/mkdir/...), when we know the full context of the
5331 operation. See selinux_bprm_set_security for the execve
5332 checks and may_create for the file creation checks. The
5333 operation will then fail if the context is not permitted. */
David Howellsb6dff3e2008-11-14 10:39:16 +11005334 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 if (!strcmp(name, "exec"))
5336 tsec->exec_sid = sid;
5337 else if (!strcmp(name, "fscreate"))
5338 tsec->create_sid = sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005339 else if (!strcmp(name, "keycreate")) {
5340 error = may_create_key(sid, p);
5341 if (error)
5342 return error;
5343 tsec->keycreate_sid = sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005344 } else if (!strcmp(name, "sockcreate"))
5345 tsec->sockcreate_sid = sid;
5346 else if (!strcmp(name, "current")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 struct av_decision avd;
5348
5349 if (sid == 0)
5350 return -EINVAL;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005351 /*
5352 * SELinux allows to change context in the following case only.
5353 * - Single threaded processes.
5354 * - Multi threaded processes intend to change its context into
5355 * more restricted domain (defined by TYPEBOUNDS statement).
5356 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 if (atomic_read(&p->mm->mm_users) != 1) {
5358 struct task_struct *g, *t;
5359 struct mm_struct *mm = p->mm;
5360 read_lock(&tasklist_lock);
James Morris2baf06d2008-06-12 01:42:35 +10005361 do_each_thread(g, t) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 if (t->mm == mm && t != p) {
5363 read_unlock(&tasklist_lock);
KaiGai Koheid9250de2008-08-28 16:35:57 +09005364 error = security_bounded_transition(tsec->sid, sid);
5365 if (!error)
5366 goto boundary_ok;
5367
5368 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 }
James Morris2baf06d2008-06-12 01:42:35 +10005370 } while_each_thread(g, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 read_unlock(&tasklist_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04005372 }
KaiGai Koheid9250de2008-08-28 16:35:57 +09005373boundary_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374
5375 /* Check permissions for the transition. */
5376 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005377 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 if (error)
5379 return error;
5380
5381 /* Check for ptracing, and update the task SID if ok.
5382 Otherwise, leave SID unchanged and fail. */
5383 task_lock(p);
Roland McGrath03563572008-03-26 15:46:39 -07005384 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07005385 tracer = tracehook_tracer_task(p);
Roland McGrath03563572008-03-26 15:46:39 -07005386 if (tracer != NULL) {
David Howells275bb412008-11-14 10:39:19 +11005387 u32 ptsid = task_sid(tracer);
Roland McGrath03563572008-03-26 15:46:39 -07005388 rcu_read_unlock();
5389 error = avc_has_perm_noaudit(ptsid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 SECCLASS_PROCESS,
Stephen Smalley2c3c05d2007-06-07 15:34:10 -04005391 PROCESS__PTRACE, 0, &avd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 if (!error)
5393 tsec->sid = sid;
5394 task_unlock(p);
Roland McGrath03563572008-03-26 15:46:39 -07005395 avc_audit(ptsid, sid, SECCLASS_PROCESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 PROCESS__PTRACE, &avd, error, NULL);
5397 if (error)
5398 return error;
5399 } else {
Roland McGrath03563572008-03-26 15:46:39 -07005400 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 tsec->sid = sid;
5402 task_unlock(p);
5403 }
Eric Paris828dfe12008-04-17 13:17:49 -04005404 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 return -EINVAL;
5406
5407 return size;
5408}
5409
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005410static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5411{
5412 return security_sid_to_context(secid, secdata, seclen);
5413}
5414
David Howells7bf570d2008-04-29 20:52:51 +01005415static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005416{
5417 return security_context_to_sid(secdata, seclen, secid);
5418}
5419
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005420static void selinux_release_secctx(char *secdata, u32 seclen)
5421{
Paul Moore088999e2007-08-01 11:12:58 -04005422 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005423}
5424
Michael LeMayd7200242006-06-22 14:47:17 -07005425#ifdef CONFIG_KEYS
5426
David Howells7e047ef2006-06-26 00:24:50 -07005427static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
5428 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005429{
David Howells275bb412008-11-14 10:39:19 +11005430 const struct task_security_struct *__tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005431 struct key_security_struct *ksec;
5432
5433 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5434 if (!ksec)
5435 return -ENOMEM;
5436
David Howells275bb412008-11-14 10:39:19 +11005437 rcu_read_lock();
5438 __tsec = __task_cred(tsk)->security;
5439 if (__tsec->keycreate_sid)
5440 ksec->sid = __tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005441 else
David Howells275bb412008-11-14 10:39:19 +11005442 ksec->sid = __tsec->sid;
5443 rcu_read_unlock();
Michael LeMayd7200242006-06-22 14:47:17 -07005444
David Howells275bb412008-11-14 10:39:19 +11005445 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005446 return 0;
5447}
5448
5449static void selinux_key_free(struct key *k)
5450{
5451 struct key_security_struct *ksec = k->security;
5452
5453 k->security = NULL;
5454 kfree(ksec);
5455}
5456
5457static int selinux_key_permission(key_ref_t key_ref,
5458 struct task_struct *ctx,
5459 key_perm_t perm)
5460{
5461 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005462 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005463 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005464
5465 /* if no specific permissions are requested, we skip the
5466 permission check. No serious, additional covert channels
5467 appear to be created. */
5468 if (perm == 0)
5469 return 0;
5470
David Howells275bb412008-11-14 10:39:19 +11005471 sid = task_sid(ctx);
5472
5473 key = key_ref_to_ptr(key_ref);
5474 ksec = key->security;
5475
5476 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005477}
5478
David Howells70a5bb72008-04-29 01:01:26 -07005479static int selinux_key_getsecurity(struct key *key, char **_buffer)
5480{
5481 struct key_security_struct *ksec = key->security;
5482 char *context = NULL;
5483 unsigned len;
5484 int rc;
5485
5486 rc = security_sid_to_context(ksec->sid, &context, &len);
5487 if (!rc)
5488 rc = len;
5489 *_buffer = context;
5490 return rc;
5491}
5492
Michael LeMayd7200242006-06-22 14:47:17 -07005493#endif
5494
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005496 .name = "selinux",
5497
David Howells5cd9c582008-08-14 11:37:28 +01005498 .ptrace_may_access = selinux_ptrace_may_access,
5499 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 .capget = selinux_capget,
5501 .capset_check = selinux_capset_check,
5502 .capset_set = selinux_capset_set,
5503 .sysctl = selinux_sysctl,
5504 .capable = selinux_capable,
5505 .quotactl = selinux_quotactl,
5506 .quota_on = selinux_quota_on,
5507 .syslog = selinux_syslog,
5508 .vm_enough_memory = selinux_vm_enough_memory,
5509
5510 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005511 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512
5513 .bprm_alloc_security = selinux_bprm_alloc_security,
5514 .bprm_free_security = selinux_bprm_free_security,
5515 .bprm_apply_creds = selinux_bprm_apply_creds,
5516 .bprm_post_apply_creds = selinux_bprm_post_apply_creds,
5517 .bprm_set_security = selinux_bprm_set_security,
5518 .bprm_check_security = selinux_bprm_check_security,
5519 .bprm_secureexec = selinux_bprm_secureexec,
5520
5521 .sb_alloc_security = selinux_sb_alloc_security,
5522 .sb_free_security = selinux_sb_free_security,
5523 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005524 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005525 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 .sb_statfs = selinux_sb_statfs,
5527 .sb_mount = selinux_mount,
5528 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005529 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005530 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005531 .sb_parse_opts_str = selinux_parse_opts_str,
5532
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533
5534 .inode_alloc_security = selinux_inode_alloc_security,
5535 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005536 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 .inode_unlink = selinux_inode_unlink,
5540 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 .inode_rmdir = selinux_inode_rmdir,
5543 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 .inode_readlink = selinux_inode_readlink,
5546 .inode_follow_link = selinux_inode_follow_link,
5547 .inode_permission = selinux_inode_permission,
5548 .inode_setattr = selinux_inode_setattr,
5549 .inode_getattr = selinux_inode_getattr,
5550 .inode_setxattr = selinux_inode_setxattr,
5551 .inode_post_setxattr = selinux_inode_post_setxattr,
5552 .inode_getxattr = selinux_inode_getxattr,
5553 .inode_listxattr = selinux_inode_listxattr,
5554 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005555 .inode_getsecurity = selinux_inode_getsecurity,
5556 .inode_setsecurity = selinux_inode_setsecurity,
5557 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005558 .inode_need_killpriv = selinux_inode_need_killpriv,
5559 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005560 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
5562 .file_permission = selinux_file_permission,
5563 .file_alloc_security = selinux_file_alloc_security,
5564 .file_free_security = selinux_file_free_security,
5565 .file_ioctl = selinux_file_ioctl,
5566 .file_mmap = selinux_file_mmap,
5567 .file_mprotect = selinux_file_mprotect,
5568 .file_lock = selinux_file_lock,
5569 .file_fcntl = selinux_file_fcntl,
5570 .file_set_fowner = selinux_file_set_fowner,
5571 .file_send_sigiotask = selinux_file_send_sigiotask,
5572 .file_receive = selinux_file_receive,
5573
Eric Paris828dfe12008-04-17 13:17:49 -04005574 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005575
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005577 .cred_alloc_security = selinux_cred_alloc_security,
5578 .cred_free = selinux_cred_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 .task_setuid = selinux_task_setuid,
5580 .task_post_setuid = selinux_task_post_setuid,
5581 .task_setgid = selinux_task_setgid,
5582 .task_setpgid = selinux_task_setpgid,
5583 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005584 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005585 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 .task_setgroups = selinux_task_setgroups,
5587 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005588 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005589 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 .task_setrlimit = selinux_task_setrlimit,
5591 .task_setscheduler = selinux_task_setscheduler,
5592 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005593 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 .task_kill = selinux_task_kill,
5595 .task_wait = selinux_task_wait,
5596 .task_prctl = selinux_task_prctl,
5597 .task_reparent_to_init = selinux_task_reparent_to_init,
Eric Paris828dfe12008-04-17 13:17:49 -04005598 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
5600 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005601 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
5603 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5604 .msg_msg_free_security = selinux_msg_msg_free_security,
5605
5606 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5607 .msg_queue_free_security = selinux_msg_queue_free_security,
5608 .msg_queue_associate = selinux_msg_queue_associate,
5609 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5610 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5611 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5612
5613 .shm_alloc_security = selinux_shm_alloc_security,
5614 .shm_free_security = selinux_shm_free_security,
5615 .shm_associate = selinux_shm_associate,
5616 .shm_shmctl = selinux_shm_shmctl,
5617 .shm_shmat = selinux_shm_shmat,
5618
Eric Paris828dfe12008-04-17 13:17:49 -04005619 .sem_alloc_security = selinux_sem_alloc_security,
5620 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 .sem_associate = selinux_sem_associate,
5622 .sem_semctl = selinux_sem_semctl,
5623 .sem_semop = selinux_sem_semop,
5624
Eric Paris828dfe12008-04-17 13:17:49 -04005625 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Eric Paris828dfe12008-04-17 13:17:49 -04005627 .getprocattr = selinux_getprocattr,
5628 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005630 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005631 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005632 .release_secctx = selinux_release_secctx,
5633
Eric Paris828dfe12008-04-17 13:17:49 -04005634 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 .unix_may_send = selinux_socket_unix_may_send,
5636
5637 .socket_create = selinux_socket_create,
5638 .socket_post_create = selinux_socket_post_create,
5639 .socket_bind = selinux_socket_bind,
5640 .socket_connect = selinux_socket_connect,
5641 .socket_listen = selinux_socket_listen,
5642 .socket_accept = selinux_socket_accept,
5643 .socket_sendmsg = selinux_socket_sendmsg,
5644 .socket_recvmsg = selinux_socket_recvmsg,
5645 .socket_getsockname = selinux_socket_getsockname,
5646 .socket_getpeername = selinux_socket_getpeername,
5647 .socket_getsockopt = selinux_socket_getsockopt,
5648 .socket_setsockopt = selinux_socket_setsockopt,
5649 .socket_shutdown = selinux_socket_shutdown,
5650 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005651 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5652 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 .sk_alloc_security = selinux_sk_alloc_security,
5654 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005655 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005656 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005657 .sock_graft = selinux_sock_graft,
5658 .inet_conn_request = selinux_inet_conn_request,
5659 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005660 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005661 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005662
5663#ifdef CONFIG_SECURITY_NETWORK_XFRM
5664 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5665 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5666 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005667 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005668 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5669 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005670 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005671 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005672 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005673 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005675
5676#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005677 .key_alloc = selinux_key_alloc,
5678 .key_free = selinux_key_free,
5679 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005680 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005681#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005682
5683#ifdef CONFIG_AUDIT
5684 .audit_rule_init = selinux_audit_rule_init,
5685 .audit_rule_known = selinux_audit_rule_known,
5686 .audit_rule_match = selinux_audit_rule_match,
5687 .audit_rule_free = selinux_audit_rule_free,
5688#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689};
5690
5691static __init int selinux_init(void)
5692{
5693 struct task_security_struct *tsec;
5694
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005695 if (!security_module_enable(&selinux_ops)) {
5696 selinux_enabled = 0;
5697 return 0;
5698 }
5699
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 if (!selinux_enabled) {
5701 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5702 return 0;
5703 }
5704
5705 printk(KERN_INFO "SELinux: Initializing.\n");
5706
5707 /* Set the security state for the initial task. */
David Howellsf1752ee2008-11-14 10:39:17 +11005708 if (cred_alloc_security(current->cred))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 panic("SELinux: Failed to initialize initial task.\n");
David Howellsb6dff3e2008-11-14 10:39:16 +11005710 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 tsec->osid = tsec->sid = SECINITSID_KERNEL;
5712
James Morris7cae7e22006-03-22 00:09:22 -08005713 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5714 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005715 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 avc_init();
5717
James Morris6f0f0fd2008-07-10 17:02:07 +09005718 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005720 panic("SELinux: No initial security operations\n");
5721 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 panic("SELinux: Unable to register with kernel.\n");
5723
Eric Paris828dfe12008-04-17 13:17:49 -04005724 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005725 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005726 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005727 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005728
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 return 0;
5730}
5731
5732void selinux_complete_init(void)
5733{
Eric Parisfadcdb42007-02-22 18:11:31 -05005734 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
5736 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005737 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005738 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 spin_lock(&sb_security_lock);
5740next_sb:
5741 if (!list_empty(&superblock_security_head)) {
5742 struct superblock_security_struct *sbsec =
5743 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005744 struct superblock_security_struct,
5745 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005749 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 down_read(&sb->s_umount);
5751 if (sb->s_root)
5752 superblock_doinit(sb, NULL);
5753 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005754 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 spin_lock(&sb_security_lock);
5756 list_del_init(&sbsec->list);
5757 goto next_sb;
5758 }
5759 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005760 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761}
5762
5763/* SELinux requires early initialization in order to label
5764 all processes and objects when they are created. */
5765security_initcall(selinux_init);
5766
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005767#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Paul Mooreeffad8d2008-01-29 08:49:27 -05005769static struct nf_hook_ops selinux_ipv4_ops[] = {
5770 {
5771 .hook = selinux_ipv4_postroute,
5772 .owner = THIS_MODULE,
5773 .pf = PF_INET,
5774 .hooknum = NF_INET_POST_ROUTING,
5775 .priority = NF_IP_PRI_SELINUX_LAST,
5776 },
5777 {
5778 .hook = selinux_ipv4_forward,
5779 .owner = THIS_MODULE,
5780 .pf = PF_INET,
5781 .hooknum = NF_INET_FORWARD,
5782 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005783 },
5784 {
5785 .hook = selinux_ipv4_output,
5786 .owner = THIS_MODULE,
5787 .pf = PF_INET,
5788 .hooknum = NF_INET_LOCAL_OUT,
5789 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791};
5792
5793#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5794
Paul Mooreeffad8d2008-01-29 08:49:27 -05005795static struct nf_hook_ops selinux_ipv6_ops[] = {
5796 {
5797 .hook = selinux_ipv6_postroute,
5798 .owner = THIS_MODULE,
5799 .pf = PF_INET6,
5800 .hooknum = NF_INET_POST_ROUTING,
5801 .priority = NF_IP6_PRI_SELINUX_LAST,
5802 },
5803 {
5804 .hook = selinux_ipv6_forward,
5805 .owner = THIS_MODULE,
5806 .pf = PF_INET6,
5807 .hooknum = NF_INET_FORWARD,
5808 .priority = NF_IP6_PRI_SELINUX_FIRST,
5809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810};
5811
5812#endif /* IPV6 */
5813
5814static int __init selinux_nf_ip_init(void)
5815{
5816 int err = 0;
5817
5818 if (!selinux_enabled)
5819 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005820
5821 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5822
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005823 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5824 if (err)
5825 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826
5827#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005828 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5829 if (err)
5830 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005832
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833out:
5834 return err;
5835}
5836
5837__initcall(selinux_nf_ip_init);
5838
5839#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5840static void selinux_nf_ip_exit(void)
5841{
Eric Parisfadcdb42007-02-22 18:11:31 -05005842 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005844 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005846 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847#endif /* IPV6 */
5848}
5849#endif
5850
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005851#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852
5853#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5854#define selinux_nf_ip_exit()
5855#endif
5856
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005857#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858
5859#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005860static int selinux_disabled;
5861
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862int selinux_disable(void)
5863{
5864 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865
5866 if (ss_initialized) {
5867 /* Not permitted after initial policy load. */
5868 return -EINVAL;
5869 }
5870
5871 if (selinux_disabled) {
5872 /* Only do this once. */
5873 return -EINVAL;
5874 }
5875
5876 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5877
5878 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005879 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880
5881 /* Reset security_ops to the secondary module, dummy or capability. */
5882 security_ops = secondary_ops;
5883
5884 /* Unregister netfilter hooks. */
5885 selinux_nf_ip_exit();
5886
5887 /* Unregister selinuxfs. */
5888 exit_sel_fs();
5889
5890 return 0;
5891}
5892#endif