blob: 658435dce37cd05a0280a15b1696443f3cb4dc6b [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static int inode_alloc_security(struct inode *inode)
176{
David Howellsb6dff3e2008-11-14 10:39:16 +1100177 struct task_security_struct *tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 struct inode_security_struct *isec;
179
Josef Bacika02fe132008-04-04 09:35:05 +1100180 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 if (!isec)
182 return -ENOMEM;
183
Eric Paris23970742006-09-25 23:32:01 -0700184 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 isec->inode = inode;
187 isec->sid = SECINITSID_UNLABELED;
188 isec->sclass = SECCLASS_FILE;
Stephen Smalley9ac49d22006-02-01 03:05:56 -0800189 isec->task_sid = tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 inode->i_security = isec;
191
192 return 0;
193}
194
195static void inode_free_security(struct inode *inode)
196{
197 struct inode_security_struct *isec = inode->i_security;
198 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 spin_lock(&sbsec->isec_lock);
201 if (!list_empty(&isec->list))
202 list_del_init(&isec->list);
203 spin_unlock(&sbsec->isec_lock);
204
205 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800206 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
209static int file_alloc_security(struct file *file)
210{
David Howellsb6dff3e2008-11-14 10:39:16 +1100211 struct task_security_struct *tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 struct file_security_struct *fsec;
213
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800214 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 if (!fsec)
216 return -ENOMEM;
217
Stephen Smalley9ac49d22006-02-01 03:05:56 -0800218 fsec->sid = tsec->sid;
219 fsec->fown_sid = tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 file->f_security = fsec;
221
222 return 0;
223}
224
225static void file_free_security(struct file *file)
226{
227 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 file->f_security = NULL;
229 kfree(fsec);
230}
231
232static int superblock_alloc_security(struct super_block *sb)
233{
234 struct superblock_security_struct *sbsec;
235
James Morris89d155e2005-10-30 14:59:21 -0800236 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (!sbsec)
238 return -ENOMEM;
239
Eric Parisbc7e9822006-09-25 23:32:02 -0700240 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 INIT_LIST_HEAD(&sbsec->list);
242 INIT_LIST_HEAD(&sbsec->isec_head);
243 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 sbsec->sb = sb;
245 sbsec->sid = SECINITSID_UNLABELED;
246 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700247 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 sb->s_security = sbsec;
249
250 return 0;
251}
252
253static void superblock_free_security(struct super_block *sb)
254{
255 struct superblock_security_struct *sbsec = sb->s_security;
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 spin_lock(&sb_security_lock);
258 if (!list_empty(&sbsec->list))
259 list_del_init(&sbsec->list);
260 spin_unlock(&sb_security_lock);
261
262 sb->s_security = NULL;
263 kfree(sbsec);
264}
265
Al Viro7d877f32005-10-21 03:20:43 -0400266static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 struct sk_security_struct *ssec;
269
James Morris89d155e2005-10-30 14:59:21 -0800270 ssec = kzalloc(sizeof(*ssec), priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 if (!ssec)
272 return -ENOMEM;
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 ssec->peer_sid = SECINITSID_UNLABELED;
Venkat Yekkirala892c1412006-08-04 23:08:56 -0700275 ssec->sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 sk->sk_security = ssec;
277
Paul Mooref74af6e2008-02-25 11:40:33 -0500278 selinux_netlbl_sk_security_reset(ssec, family);
Paul Moore99f59ed2006-08-29 17:53:48 -0700279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 return 0;
281}
282
283static void sk_free_security(struct sock *sk)
284{
285 struct sk_security_struct *ssec = sk->sk_security;
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 sk->sk_security = NULL;
Paul Moore6c5b3fc2008-10-10 10:16:33 -0400288 selinux_netlbl_sk_security_free(ssec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 kfree(ssec);
290}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292/* The security server must be initialized before
293 any labeling or access decisions can be provided. */
294extern int ss_initialized;
295
296/* The file system's label must be initialized prior to use. */
297
298static char *labeling_behaviors[6] = {
299 "uses xattr",
300 "uses transition SIDs",
301 "uses task SIDs",
302 "uses genfs_contexts",
303 "not configured for labeling",
304 "uses mountpoint labeling",
305};
306
307static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
308
309static inline int inode_doinit(struct inode *inode)
310{
311 return inode_doinit_with_dentry(inode, NULL);
312}
313
314enum {
Eric Paris31e87932007-09-19 17:19:12 -0400315 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 Opt_context = 1,
317 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500318 Opt_defcontext = 3,
319 Opt_rootcontext = 4,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320};
321
Steven Whitehousea447c092008-10-13 10:46:57 +0100322static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400323 {Opt_context, CONTEXT_STR "%s"},
324 {Opt_fscontext, FSCONTEXT_STR "%s"},
325 {Opt_defcontext, DEFCONTEXT_STR "%s"},
326 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
Eric Paris31e87932007-09-19 17:19:12 -0400327 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328};
329
330#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
331
Eric Parisc312feb2006-07-10 04:43:53 -0700332static int may_context_mount_sb_relabel(u32 sid,
333 struct superblock_security_struct *sbsec,
334 struct task_security_struct *tsec)
335{
336 int rc;
337
338 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
339 FILESYSTEM__RELABELFROM, NULL);
340 if (rc)
341 return rc;
342
343 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
344 FILESYSTEM__RELABELTO, NULL);
345 return rc;
346}
347
Eric Paris08089252006-07-10 04:43:55 -0700348static int may_context_mount_inode_relabel(u32 sid,
349 struct superblock_security_struct *sbsec,
350 struct task_security_struct *tsec)
351{
352 int rc;
353 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
354 FILESYSTEM__RELABELFROM, NULL);
355 if (rc)
356 return rc;
357
358 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
359 FILESYSTEM__ASSOCIATE, NULL);
360 return rc;
361}
362
Eric Parisc9180a52007-11-30 13:00:35 -0500363static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 struct superblock_security_struct *sbsec = sb->s_security;
366 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500367 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 int rc = 0;
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
371 /* Make sure that the xattr handler exists and that no
372 error other than -ENODATA is returned by getxattr on
373 the root directory. -ENODATA is ok, as this may be
374 the first boot of the SELinux kernel before we have
375 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500376 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
378 "xattr support\n", sb->s_id, sb->s_type->name);
379 rc = -EOPNOTSUPP;
380 goto out;
381 }
Eric Parisc9180a52007-11-30 13:00:35 -0500382 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 if (rc < 0 && rc != -ENODATA) {
384 if (rc == -EOPNOTSUPP)
385 printk(KERN_WARNING "SELinux: (dev %s, type "
386 "%s) has no security xattr handler\n",
387 sb->s_id, sb->s_type->name);
388 else
389 printk(KERN_WARNING "SELinux: (dev %s, type "
390 "%s) getxattr errno %d\n", sb->s_id,
391 sb->s_type->name, -rc);
392 goto out;
393 }
394 }
395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 sbsec->initialized = 1;
397
Eric Parisc9180a52007-11-30 13:00:35 -0500398 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500399 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500401 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500402 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 sb->s_id, sb->s_type->name,
404 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500407 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 /* Initialize any other inodes associated with the superblock, e.g.
410 inodes created prior to initial policy load or inodes created
411 during get_sb by a pseudo filesystem that directly
412 populates itself. */
413 spin_lock(&sbsec->isec_lock);
414next_inode:
415 if (!list_empty(&sbsec->isec_head)) {
416 struct inode_security_struct *isec =
417 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500418 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 struct inode *inode = isec->inode;
420 spin_unlock(&sbsec->isec_lock);
421 inode = igrab(inode);
422 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500423 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 inode_doinit(inode);
425 iput(inode);
426 }
427 spin_lock(&sbsec->isec_lock);
428 list_del_init(&isec->list);
429 goto next_inode;
430 }
431 spin_unlock(&sbsec->isec_lock);
432out:
Eric Parisc9180a52007-11-30 13:00:35 -0500433 return rc;
434}
435
436/*
437 * This function should allow an FS to ask what it's mount security
438 * options were so it can use those later for submounts, displaying
439 * mount options, or whatever.
440 */
441static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500442 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500443{
444 int rc = 0, i;
445 struct superblock_security_struct *sbsec = sb->s_security;
446 char *context = NULL;
447 u32 len;
448 char tmp;
449
Eric Parise0007522008-03-05 10:31:54 -0500450 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500451
452 if (!sbsec->initialized)
453 return -EINVAL;
454
455 if (!ss_initialized)
456 return -EINVAL;
457
458 /*
459 * if we ever use sbsec flags for anything other than tracking mount
460 * settings this is going to need a mask
461 */
462 tmp = sbsec->flags;
463 /* count the number of mount options for this sb */
464 for (i = 0; i < 8; i++) {
465 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500466 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500467 tmp >>= 1;
468 }
469
Eric Parise0007522008-03-05 10:31:54 -0500470 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
471 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500472 rc = -ENOMEM;
473 goto out_free;
474 }
475
Eric Parise0007522008-03-05 10:31:54 -0500476 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
477 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500478 rc = -ENOMEM;
479 goto out_free;
480 }
481
482 i = 0;
483 if (sbsec->flags & FSCONTEXT_MNT) {
484 rc = security_sid_to_context(sbsec->sid, &context, &len);
485 if (rc)
486 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500487 opts->mnt_opts[i] = context;
488 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500489 }
490 if (sbsec->flags & CONTEXT_MNT) {
491 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
492 if (rc)
493 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500494 opts->mnt_opts[i] = context;
495 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500496 }
497 if (sbsec->flags & DEFCONTEXT_MNT) {
498 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
499 if (rc)
500 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500501 opts->mnt_opts[i] = context;
502 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500503 }
504 if (sbsec->flags & ROOTCONTEXT_MNT) {
505 struct inode *root = sbsec->sb->s_root->d_inode;
506 struct inode_security_struct *isec = root->i_security;
507
508 rc = security_sid_to_context(isec->sid, &context, &len);
509 if (rc)
510 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500511 opts->mnt_opts[i] = context;
512 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500513 }
514
Eric Parise0007522008-03-05 10:31:54 -0500515 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500516
517 return 0;
518
519out_free:
Eric Parise0007522008-03-05 10:31:54 -0500520 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500521 return rc;
522}
523
524static int bad_option(struct superblock_security_struct *sbsec, char flag,
525 u32 old_sid, u32 new_sid)
526{
527 /* check if the old mount command had the same options */
528 if (sbsec->initialized)
529 if (!(sbsec->flags & flag) ||
530 (old_sid != new_sid))
531 return 1;
532
533 /* check if we were passed the same options twice,
534 * aka someone passed context=a,context=b
535 */
536 if (!sbsec->initialized)
537 if (sbsec->flags & flag)
538 return 1;
539 return 0;
540}
Eric Parise0007522008-03-05 10:31:54 -0500541
Eric Parisc9180a52007-11-30 13:00:35 -0500542/*
543 * Allow filesystems with binary mount data to explicitly set mount point
544 * labeling information.
545 */
Eric Parise0007522008-03-05 10:31:54 -0500546static int selinux_set_mnt_opts(struct super_block *sb,
547 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500548{
549 int rc = 0, i;
David Howellsb6dff3e2008-11-14 10:39:16 +1100550 struct task_security_struct *tsec = current->cred->security;
Eric Parisc9180a52007-11-30 13:00:35 -0500551 struct superblock_security_struct *sbsec = sb->s_security;
552 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000553 struct inode *inode = sbsec->sb->s_root->d_inode;
554 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500555 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
556 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500557 char **mount_options = opts->mnt_opts;
558 int *flags = opts->mnt_opts_flags;
559 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500560
561 mutex_lock(&sbsec->lock);
562
563 if (!ss_initialized) {
564 if (!num_opts) {
565 /* Defer initialization until selinux_complete_init,
566 after the initial policy is loaded and the security
567 server is ready to handle calls. */
568 spin_lock(&sb_security_lock);
569 if (list_empty(&sbsec->list))
570 list_add(&sbsec->list, &superblock_security_head);
571 spin_unlock(&sb_security_lock);
572 goto out;
573 }
574 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400575 printk(KERN_WARNING "SELinux: Unable to set superblock options "
576 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500577 goto out;
578 }
579
580 /*
Eric Parise0007522008-03-05 10:31:54 -0500581 * Binary mount data FS will come through this function twice. Once
582 * from an explicit call and once from the generic calls from the vfs.
583 * Since the generic VFS calls will not contain any security mount data
584 * we need to skip the double mount verification.
585 *
586 * This does open a hole in which we will not notice if the first
587 * mount using this sb set explict options and a second mount using
588 * this sb does not set any security options. (The first options
589 * will be used for both mounts)
590 */
591 if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
592 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400593 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500594
595 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500596 * parse the mount options, check if they are valid sids.
597 * also check if someone is trying to mount the same sb more
598 * than once with different security options.
599 */
600 for (i = 0; i < num_opts; i++) {
601 u32 sid;
602 rc = security_context_to_sid(mount_options[i],
603 strlen(mount_options[i]), &sid);
604 if (rc) {
605 printk(KERN_WARNING "SELinux: security_context_to_sid"
606 "(%s) failed for (dev %s, type %s) errno=%d\n",
607 mount_options[i], sb->s_id, name, rc);
608 goto out;
609 }
610 switch (flags[i]) {
611 case FSCONTEXT_MNT:
612 fscontext_sid = sid;
613
614 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
615 fscontext_sid))
616 goto out_double_mount;
617
618 sbsec->flags |= FSCONTEXT_MNT;
619 break;
620 case CONTEXT_MNT:
621 context_sid = sid;
622
623 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
624 context_sid))
625 goto out_double_mount;
626
627 sbsec->flags |= CONTEXT_MNT;
628 break;
629 case ROOTCONTEXT_MNT:
630 rootcontext_sid = sid;
631
632 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
633 rootcontext_sid))
634 goto out_double_mount;
635
636 sbsec->flags |= ROOTCONTEXT_MNT;
637
638 break;
639 case DEFCONTEXT_MNT:
640 defcontext_sid = sid;
641
642 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
643 defcontext_sid))
644 goto out_double_mount;
645
646 sbsec->flags |= DEFCONTEXT_MNT;
647
648 break;
649 default:
650 rc = -EINVAL;
651 goto out;
652 }
653 }
654
655 if (sbsec->initialized) {
656 /* previously mounted with options, but not on this attempt? */
657 if (sbsec->flags && !num_opts)
658 goto out_double_mount;
659 rc = 0;
660 goto out;
661 }
662
James Morris089be432008-07-15 18:32:49 +1000663 if (strcmp(sb->s_type->name, "proc") == 0)
Eric Parisc9180a52007-11-30 13:00:35 -0500664 sbsec->proc = 1;
665
666 /* Determine the labeling behavior to use for this filesystem type. */
James Morris089be432008-07-15 18:32:49 +1000667 rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500668 if (rc) {
669 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000670 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500671 goto out;
672 }
673
674 /* sets the context of the superblock for the fs being mounted. */
675 if (fscontext_sid) {
676
677 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
678 if (rc)
679 goto out;
680
681 sbsec->sid = fscontext_sid;
682 }
683
684 /*
685 * Switch to using mount point labeling behavior.
686 * sets the label used on all file below the mountpoint, and will set
687 * the superblock context if not already set.
688 */
689 if (context_sid) {
690 if (!fscontext_sid) {
691 rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
692 if (rc)
693 goto out;
694 sbsec->sid = context_sid;
695 } else {
696 rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
697 if (rc)
698 goto out;
699 }
700 if (!rootcontext_sid)
701 rootcontext_sid = context_sid;
702
703 sbsec->mntpoint_sid = context_sid;
704 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
705 }
706
707 if (rootcontext_sid) {
708 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
709 if (rc)
710 goto out;
711
712 root_isec->sid = rootcontext_sid;
713 root_isec->initialized = 1;
714 }
715
716 if (defcontext_sid) {
717 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
718 rc = -EINVAL;
719 printk(KERN_WARNING "SELinux: defcontext option is "
720 "invalid for this filesystem type\n");
721 goto out;
722 }
723
724 if (defcontext_sid != sbsec->def_sid) {
725 rc = may_context_mount_inode_relabel(defcontext_sid,
726 sbsec, tsec);
727 if (rc)
728 goto out;
729 }
730
731 sbsec->def_sid = defcontext_sid;
732 }
733
734 rc = sb_finish_set_opts(sb);
735out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700736 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500738out_double_mount:
739 rc = -EINVAL;
740 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
741 "security settings for (dev %s, type %s)\n", sb->s_id, name);
742 goto out;
743}
744
745static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
746 struct super_block *newsb)
747{
748 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
749 struct superblock_security_struct *newsbsec = newsb->s_security;
750
751 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
752 int set_context = (oldsbsec->flags & CONTEXT_MNT);
753 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
754
Eric Paris0f5e6422008-04-21 16:24:11 -0400755 /*
756 * if the parent was able to be mounted it clearly had no special lsm
757 * mount options. thus we can safely put this sb on the list and deal
758 * with it later
759 */
760 if (!ss_initialized) {
761 spin_lock(&sb_security_lock);
762 if (list_empty(&newsbsec->list))
763 list_add(&newsbsec->list, &superblock_security_head);
764 spin_unlock(&sb_security_lock);
765 return;
766 }
Eric Parisc9180a52007-11-30 13:00:35 -0500767
Eric Parisc9180a52007-11-30 13:00:35 -0500768 /* how can we clone if the old one wasn't set up?? */
769 BUG_ON(!oldsbsec->initialized);
770
Eric Paris5a552612008-04-09 14:08:35 -0400771 /* if fs is reusing a sb, just let its options stand... */
772 if (newsbsec->initialized)
773 return;
774
Eric Parisc9180a52007-11-30 13:00:35 -0500775 mutex_lock(&newsbsec->lock);
776
777 newsbsec->flags = oldsbsec->flags;
778
779 newsbsec->sid = oldsbsec->sid;
780 newsbsec->def_sid = oldsbsec->def_sid;
781 newsbsec->behavior = oldsbsec->behavior;
782
783 if (set_context) {
784 u32 sid = oldsbsec->mntpoint_sid;
785
786 if (!set_fscontext)
787 newsbsec->sid = sid;
788 if (!set_rootcontext) {
789 struct inode *newinode = newsb->s_root->d_inode;
790 struct inode_security_struct *newisec = newinode->i_security;
791 newisec->sid = sid;
792 }
793 newsbsec->mntpoint_sid = sid;
794 }
795 if (set_rootcontext) {
796 const struct inode *oldinode = oldsb->s_root->d_inode;
797 const struct inode_security_struct *oldisec = oldinode->i_security;
798 struct inode *newinode = newsb->s_root->d_inode;
799 struct inode_security_struct *newisec = newinode->i_security;
800
801 newisec->sid = oldisec->sid;
802 }
803
804 sb_finish_set_opts(newsb);
805 mutex_unlock(&newsbsec->lock);
806}
807
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200808static int selinux_parse_opts_str(char *options,
809 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500810{
Eric Parise0007522008-03-05 10:31:54 -0500811 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500812 char *context = NULL, *defcontext = NULL;
813 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500814 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500815
Eric Parise0007522008-03-05 10:31:54 -0500816 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500817
818 /* Standard string-based options. */
819 while ((p = strsep(&options, "|")) != NULL) {
820 int token;
821 substring_t args[MAX_OPT_ARGS];
822
823 if (!*p)
824 continue;
825
826 token = match_token(p, tokens, args);
827
828 switch (token) {
829 case Opt_context:
830 if (context || defcontext) {
831 rc = -EINVAL;
832 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
833 goto out_err;
834 }
835 context = match_strdup(&args[0]);
836 if (!context) {
837 rc = -ENOMEM;
838 goto out_err;
839 }
840 break;
841
842 case Opt_fscontext:
843 if (fscontext) {
844 rc = -EINVAL;
845 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
846 goto out_err;
847 }
848 fscontext = match_strdup(&args[0]);
849 if (!fscontext) {
850 rc = -ENOMEM;
851 goto out_err;
852 }
853 break;
854
855 case Opt_rootcontext:
856 if (rootcontext) {
857 rc = -EINVAL;
858 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
859 goto out_err;
860 }
861 rootcontext = match_strdup(&args[0]);
862 if (!rootcontext) {
863 rc = -ENOMEM;
864 goto out_err;
865 }
866 break;
867
868 case Opt_defcontext:
869 if (context || defcontext) {
870 rc = -EINVAL;
871 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
872 goto out_err;
873 }
874 defcontext = match_strdup(&args[0]);
875 if (!defcontext) {
876 rc = -ENOMEM;
877 goto out_err;
878 }
879 break;
880
881 default:
882 rc = -EINVAL;
883 printk(KERN_WARNING "SELinux: unknown mount option\n");
884 goto out_err;
885
886 }
887 }
888
Eric Parise0007522008-03-05 10:31:54 -0500889 rc = -ENOMEM;
890 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
891 if (!opts->mnt_opts)
892 goto out_err;
893
894 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
895 if (!opts->mnt_opts_flags) {
896 kfree(opts->mnt_opts);
897 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500898 }
899
Eric Parise0007522008-03-05 10:31:54 -0500900 if (fscontext) {
901 opts->mnt_opts[num_mnt_opts] = fscontext;
902 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
903 }
904 if (context) {
905 opts->mnt_opts[num_mnt_opts] = context;
906 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
907 }
908 if (rootcontext) {
909 opts->mnt_opts[num_mnt_opts] = rootcontext;
910 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
911 }
912 if (defcontext) {
913 opts->mnt_opts[num_mnt_opts] = defcontext;
914 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
915 }
916
917 opts->num_mnt_opts = num_mnt_opts;
918 return 0;
919
Eric Parisc9180a52007-11-30 13:00:35 -0500920out_err:
921 kfree(context);
922 kfree(defcontext);
923 kfree(fscontext);
924 kfree(rootcontext);
925 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926}
Eric Parise0007522008-03-05 10:31:54 -0500927/*
928 * string mount options parsing and call set the sbsec
929 */
930static int superblock_doinit(struct super_block *sb, void *data)
931{
932 int rc = 0;
933 char *options = data;
934 struct security_mnt_opts opts;
935
936 security_init_mnt_opts(&opts);
937
938 if (!data)
939 goto out;
940
941 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
942
943 rc = selinux_parse_opts_str(options, &opts);
944 if (rc)
945 goto out_err;
946
947out:
948 rc = selinux_set_mnt_opts(sb, &opts);
949
950out_err:
951 security_free_mnt_opts(&opts);
952 return rc;
953}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Adrian Bunk3583a712008-07-22 20:21:23 +0300955static void selinux_write_opts(struct seq_file *m,
956 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000957{
958 int i;
959 char *prefix;
960
961 for (i = 0; i < opts->num_mnt_opts; i++) {
962 char *has_comma = strchr(opts->mnt_opts[i], ',');
963
964 switch (opts->mnt_opts_flags[i]) {
965 case CONTEXT_MNT:
966 prefix = CONTEXT_STR;
967 break;
968 case FSCONTEXT_MNT:
969 prefix = FSCONTEXT_STR;
970 break;
971 case ROOTCONTEXT_MNT:
972 prefix = ROOTCONTEXT_STR;
973 break;
974 case DEFCONTEXT_MNT:
975 prefix = DEFCONTEXT_STR;
976 break;
977 default:
978 BUG();
979 };
980 /* we need a comma before each option */
981 seq_putc(m, ',');
982 seq_puts(m, prefix);
983 if (has_comma)
984 seq_putc(m, '\"');
985 seq_puts(m, opts->mnt_opts[i]);
986 if (has_comma)
987 seq_putc(m, '\"');
988 }
989}
990
991static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
992{
993 struct security_mnt_opts opts;
994 int rc;
995
996 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -0400997 if (rc) {
998 /* before policy load we may get EINVAL, don't show anything */
999 if (rc == -EINVAL)
1000 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001001 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001002 }
Eric Paris2069f452008-07-04 09:47:13 +10001003
1004 selinux_write_opts(m, &opts);
1005
1006 security_free_mnt_opts(&opts);
1007
1008 return rc;
1009}
1010
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011static inline u16 inode_mode_to_security_class(umode_t mode)
1012{
1013 switch (mode & S_IFMT) {
1014 case S_IFSOCK:
1015 return SECCLASS_SOCK_FILE;
1016 case S_IFLNK:
1017 return SECCLASS_LNK_FILE;
1018 case S_IFREG:
1019 return SECCLASS_FILE;
1020 case S_IFBLK:
1021 return SECCLASS_BLK_FILE;
1022 case S_IFDIR:
1023 return SECCLASS_DIR;
1024 case S_IFCHR:
1025 return SECCLASS_CHR_FILE;
1026 case S_IFIFO:
1027 return SECCLASS_FIFO_FILE;
1028
1029 }
1030
1031 return SECCLASS_FILE;
1032}
1033
James Morris13402582005-09-30 14:24:34 -04001034static inline int default_protocol_stream(int protocol)
1035{
1036 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1037}
1038
1039static inline int default_protocol_dgram(int protocol)
1040{
1041 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1042}
1043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1045{
1046 switch (family) {
1047 case PF_UNIX:
1048 switch (type) {
1049 case SOCK_STREAM:
1050 case SOCK_SEQPACKET:
1051 return SECCLASS_UNIX_STREAM_SOCKET;
1052 case SOCK_DGRAM:
1053 return SECCLASS_UNIX_DGRAM_SOCKET;
1054 }
1055 break;
1056 case PF_INET:
1057 case PF_INET6:
1058 switch (type) {
1059 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001060 if (default_protocol_stream(protocol))
1061 return SECCLASS_TCP_SOCKET;
1062 else
1063 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001065 if (default_protocol_dgram(protocol))
1066 return SECCLASS_UDP_SOCKET;
1067 else
1068 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001069 case SOCK_DCCP:
1070 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001071 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return SECCLASS_RAWIP_SOCKET;
1073 }
1074 break;
1075 case PF_NETLINK:
1076 switch (protocol) {
1077 case NETLINK_ROUTE:
1078 return SECCLASS_NETLINK_ROUTE_SOCKET;
1079 case NETLINK_FIREWALL:
1080 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001081 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1083 case NETLINK_NFLOG:
1084 return SECCLASS_NETLINK_NFLOG_SOCKET;
1085 case NETLINK_XFRM:
1086 return SECCLASS_NETLINK_XFRM_SOCKET;
1087 case NETLINK_SELINUX:
1088 return SECCLASS_NETLINK_SELINUX_SOCKET;
1089 case NETLINK_AUDIT:
1090 return SECCLASS_NETLINK_AUDIT_SOCKET;
1091 case NETLINK_IP6_FW:
1092 return SECCLASS_NETLINK_IP6FW_SOCKET;
1093 case NETLINK_DNRTMSG:
1094 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001095 case NETLINK_KOBJECT_UEVENT:
1096 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 default:
1098 return SECCLASS_NETLINK_SOCKET;
1099 }
1100 case PF_PACKET:
1101 return SECCLASS_PACKET_SOCKET;
1102 case PF_KEY:
1103 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001104 case PF_APPLETALK:
1105 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 }
1107
1108 return SECCLASS_SOCKET;
1109}
1110
1111#ifdef CONFIG_PROC_FS
1112static int selinux_proc_get_sid(struct proc_dir_entry *de,
1113 u16 tclass,
1114 u32 *sid)
1115{
1116 int buflen, rc;
1117 char *buffer, *path, *end;
1118
Eric Paris828dfe12008-04-17 13:17:49 -04001119 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 if (!buffer)
1121 return -ENOMEM;
1122
1123 buflen = PAGE_SIZE;
1124 end = buffer+buflen;
1125 *--end = '\0';
1126 buflen--;
1127 path = end-1;
1128 *path = '/';
1129 while (de && de != de->parent) {
1130 buflen -= de->namelen + 1;
1131 if (buflen < 0)
1132 break;
1133 end -= de->namelen;
1134 memcpy(end, de->name, de->namelen);
1135 *--end = '/';
1136 path = end;
1137 de = de->parent;
1138 }
1139 rc = security_genfs_sid("proc", path, tclass, sid);
1140 free_page((unsigned long)buffer);
1141 return rc;
1142}
1143#else
1144static int selinux_proc_get_sid(struct proc_dir_entry *de,
1145 u16 tclass,
1146 u32 *sid)
1147{
1148 return -EINVAL;
1149}
1150#endif
1151
1152/* The inode's security attributes must be initialized before first use. */
1153static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1154{
1155 struct superblock_security_struct *sbsec = NULL;
1156 struct inode_security_struct *isec = inode->i_security;
1157 u32 sid;
1158 struct dentry *dentry;
1159#define INITCONTEXTLEN 255
1160 char *context = NULL;
1161 unsigned len = 0;
1162 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 if (isec->initialized)
1165 goto out;
1166
Eric Paris23970742006-09-25 23:32:01 -07001167 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001169 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 sbsec = inode->i_sb->s_security;
1172 if (!sbsec->initialized) {
1173 /* Defer initialization until selinux_complete_init,
1174 after the initial policy is loaded and the security
1175 server is ready to handle calls. */
1176 spin_lock(&sbsec->isec_lock);
1177 if (list_empty(&isec->list))
1178 list_add(&isec->list, &sbsec->isec_head);
1179 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001180 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182
1183 switch (sbsec->behavior) {
1184 case SECURITY_FS_USE_XATTR:
1185 if (!inode->i_op->getxattr) {
1186 isec->sid = sbsec->def_sid;
1187 break;
1188 }
1189
1190 /* Need a dentry, since the xattr API requires one.
1191 Life would be simpler if we could just pass the inode. */
1192 if (opt_dentry) {
1193 /* Called from d_instantiate or d_splice_alias. */
1194 dentry = dget(opt_dentry);
1195 } else {
1196 /* Called from selinux_complete_init, try to find a dentry. */
1197 dentry = d_find_alias(inode);
1198 }
1199 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001200 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001201 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001203 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 }
1205
1206 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001207 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (!context) {
1209 rc = -ENOMEM;
1210 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001211 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
1213 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1214 context, len);
1215 if (rc == -ERANGE) {
1216 /* Need a larger buffer. Query for the right size. */
1217 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1218 NULL, 0);
1219 if (rc < 0) {
1220 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001221 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 }
1223 kfree(context);
1224 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001225 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 if (!context) {
1227 rc = -ENOMEM;
1228 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001229 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 }
1231 rc = inode->i_op->getxattr(dentry,
1232 XATTR_NAME_SELINUX,
1233 context, len);
1234 }
1235 dput(dentry);
1236 if (rc < 0) {
1237 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001238 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001239 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 -rc, inode->i_sb->s_id, inode->i_ino);
1241 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001242 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 }
1244 /* Map ENODATA to the default file SID */
1245 sid = sbsec->def_sid;
1246 rc = 0;
1247 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001248 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001249 sbsec->def_sid,
1250 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001252 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001254 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 inode->i_sb->s_id, inode->i_ino);
1256 kfree(context);
1257 /* Leave with the unlabeled SID */
1258 rc = 0;
1259 break;
1260 }
1261 }
1262 kfree(context);
1263 isec->sid = sid;
1264 break;
1265 case SECURITY_FS_USE_TASK:
1266 isec->sid = isec->task_sid;
1267 break;
1268 case SECURITY_FS_USE_TRANS:
1269 /* Default to the fs SID. */
1270 isec->sid = sbsec->sid;
1271
1272 /* Try to obtain a transition SID. */
1273 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1274 rc = security_transition_sid(isec->task_sid,
1275 sbsec->sid,
1276 isec->sclass,
1277 &sid);
1278 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001279 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 isec->sid = sid;
1281 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001282 case SECURITY_FS_USE_MNTPOINT:
1283 isec->sid = sbsec->mntpoint_sid;
1284 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001286 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 isec->sid = sbsec->sid;
1288
Stephen Smalleyea6b1842008-09-22 15:41:19 -04001289 if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 struct proc_inode *proci = PROC_I(inode);
1291 if (proci->pde) {
1292 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1293 rc = selinux_proc_get_sid(proci->pde,
1294 isec->sclass,
1295 &sid);
1296 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001297 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 isec->sid = sid;
1299 }
1300 }
1301 break;
1302 }
1303
1304 isec->initialized = 1;
1305
Eric Paris23970742006-09-25 23:32:01 -07001306out_unlock:
1307 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308out:
1309 if (isec->sclass == SECCLASS_FILE)
1310 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 return rc;
1312}
1313
1314/* Convert a Linux signal to an access vector. */
1315static inline u32 signal_to_av(int sig)
1316{
1317 u32 perm = 0;
1318
1319 switch (sig) {
1320 case SIGCHLD:
1321 /* Commonly granted from child to parent. */
1322 perm = PROCESS__SIGCHLD;
1323 break;
1324 case SIGKILL:
1325 /* Cannot be caught or ignored */
1326 perm = PROCESS__SIGKILL;
1327 break;
1328 case SIGSTOP:
1329 /* Cannot be caught or ignored */
1330 perm = PROCESS__SIGSTOP;
1331 break;
1332 default:
1333 /* All other signals. */
1334 perm = PROCESS__SIGNAL;
1335 break;
1336 }
1337
1338 return perm;
1339}
1340
1341/* Check permission betweeen a pair of tasks, e.g. signal checks,
1342 fork check, ptrace check, etc. */
1343static int task_has_perm(struct task_struct *tsk1,
1344 struct task_struct *tsk2,
1345 u32 perms)
1346{
1347 struct task_security_struct *tsec1, *tsec2;
1348
David Howellsb6dff3e2008-11-14 10:39:16 +11001349 tsec1 = tsk1->cred->security;
1350 tsec2 = tsk2->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return avc_has_perm(tsec1->sid, tsec2->sid,
1352 SECCLASS_PROCESS, perms, NULL);
1353}
1354
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001355#if CAP_LAST_CAP > 63
1356#error Fix SELinux to handle capabilities > 63.
1357#endif
1358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359/* Check whether a task is allowed to use a capability. */
1360static int task_has_capability(struct task_struct *tsk,
Eric Paris06112162008-11-11 22:02:50 +11001361 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362{
1363 struct task_security_struct *tsec;
1364 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001365 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001366 u16 sclass;
1367 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001368 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
David Howellsb6dff3e2008-11-14 10:39:16 +11001370 tsec = tsk->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Eric Paris828dfe12008-04-17 13:17:49 -04001372 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 ad.tsk = tsk;
1374 ad.u.cap = cap;
1375
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001376 switch (CAP_TO_INDEX(cap)) {
1377 case 0:
1378 sclass = SECCLASS_CAPABILITY;
1379 break;
1380 case 1:
1381 sclass = SECCLASS_CAPABILITY2;
1382 break;
1383 default:
1384 printk(KERN_ERR
1385 "SELinux: out of range capability %d\n", cap);
1386 BUG();
1387 }
Eric Paris06112162008-11-11 22:02:50 +11001388
1389 rc = avc_has_perm_noaudit(tsec->sid, tsec->sid, sclass, av, 0, &avd);
1390 if (audit == SECURITY_CAP_AUDIT)
1391 avc_audit(tsec->sid, tsec->sid, sclass, av, &avd, rc, &ad);
1392 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393}
1394
1395/* Check whether a task is allowed to use a system operation. */
1396static int task_has_system(struct task_struct *tsk,
1397 u32 perms)
1398{
1399 struct task_security_struct *tsec;
1400
David Howellsb6dff3e2008-11-14 10:39:16 +11001401 tsec = tsk->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
1404 SECCLASS_SYSTEM, perms, NULL);
1405}
1406
1407/* Check whether a task has a particular permission to an inode.
1408 The 'adp' parameter is optional and allows other audit
1409 data to be passed (e.g. the dentry). */
1410static int inode_has_perm(struct task_struct *tsk,
1411 struct inode *inode,
1412 u32 perms,
1413 struct avc_audit_data *adp)
1414{
1415 struct task_security_struct *tsec;
1416 struct inode_security_struct *isec;
1417 struct avc_audit_data ad;
1418
Eric Paris828dfe12008-04-17 13:17:49 -04001419 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001420 return 0;
1421
David Howellsb6dff3e2008-11-14 10:39:16 +11001422 tsec = tsk->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 isec = inode->i_security;
1424
1425 if (!adp) {
1426 adp = &ad;
1427 AVC_AUDIT_DATA_INIT(&ad, FS);
1428 ad.u.fs.inode = inode;
1429 }
1430
1431 return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp);
1432}
1433
1434/* Same as inode_has_perm, but pass explicit audit data containing
1435 the dentry to help the auditing code to more easily generate the
1436 pathname if needed. */
1437static inline int dentry_has_perm(struct task_struct *tsk,
1438 struct vfsmount *mnt,
1439 struct dentry *dentry,
1440 u32 av)
1441{
1442 struct inode *inode = dentry->d_inode;
1443 struct avc_audit_data ad;
Eric Paris828dfe12008-04-17 13:17:49 -04001444 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001445 ad.u.fs.path.mnt = mnt;
1446 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 return inode_has_perm(tsk, inode, av, &ad);
1448}
1449
1450/* Check whether a task can use an open file descriptor to
1451 access an inode in a given way. Check access to the
1452 descriptor itself, and then use dentry_has_perm to
1453 check a particular permission to the file.
1454 Access to the descriptor is implicitly granted if it
1455 has the same SID as the process. If av is zero, then
1456 access to the file is not checked, e.g. for cases
1457 where only the descriptor is affected like seek. */
Arjan van de Ven858119e2006-01-14 13:20:43 -08001458static int file_has_perm(struct task_struct *tsk,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 struct file *file,
1460 u32 av)
1461{
David Howellsb6dff3e2008-11-14 10:39:16 +11001462 struct task_security_struct *tsec = tsk->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001464 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 struct avc_audit_data ad;
1466 int rc;
1467
1468 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001469 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
1471 if (tsec->sid != fsec->sid) {
1472 rc = avc_has_perm(tsec->sid, fsec->sid,
1473 SECCLASS_FD,
1474 FD__USE,
1475 &ad);
1476 if (rc)
1477 return rc;
1478 }
1479
1480 /* av is zero if only checking access to the descriptor. */
1481 if (av)
1482 return inode_has_perm(tsk, inode, av, &ad);
1483
1484 return 0;
1485}
1486
1487/* Check whether a task can create a file. */
1488static int may_create(struct inode *dir,
1489 struct dentry *dentry,
1490 u16 tclass)
1491{
1492 struct task_security_struct *tsec;
1493 struct inode_security_struct *dsec;
1494 struct superblock_security_struct *sbsec;
1495 u32 newsid;
1496 struct avc_audit_data ad;
1497 int rc;
1498
David Howellsb6dff3e2008-11-14 10:39:16 +11001499 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 dsec = dir->i_security;
1501 sbsec = dir->i_sb->s_security;
1502
1503 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001504 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
1506 rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
1507 DIR__ADD_NAME | DIR__SEARCH,
1508 &ad);
1509 if (rc)
1510 return rc;
1511
1512 if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
1513 newsid = tsec->create_sid;
1514 } else {
1515 rc = security_transition_sid(tsec->sid, dsec->sid, tclass,
1516 &newsid);
1517 if (rc)
1518 return rc;
1519 }
1520
1521 rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
1522 if (rc)
1523 return rc;
1524
1525 return avc_has_perm(newsid, sbsec->sid,
1526 SECCLASS_FILESYSTEM,
1527 FILESYSTEM__ASSOCIATE, &ad);
1528}
1529
Michael LeMay4eb582c2006-06-26 00:24:57 -07001530/* Check whether a task can create a key. */
1531static int may_create_key(u32 ksid,
1532 struct task_struct *ctx)
1533{
1534 struct task_security_struct *tsec;
1535
David Howellsb6dff3e2008-11-14 10:39:16 +11001536 tsec = ctx->cred->security;
Michael LeMay4eb582c2006-06-26 00:24:57 -07001537
1538 return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
1539}
1540
Eric Paris828dfe12008-04-17 13:17:49 -04001541#define MAY_LINK 0
1542#define MAY_UNLINK 1
1543#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545/* Check whether a task can link, unlink, or rmdir a file/directory. */
1546static int may_link(struct inode *dir,
1547 struct dentry *dentry,
1548 int kind)
1549
1550{
1551 struct task_security_struct *tsec;
1552 struct inode_security_struct *dsec, *isec;
1553 struct avc_audit_data ad;
1554 u32 av;
1555 int rc;
1556
David Howellsb6dff3e2008-11-14 10:39:16 +11001557 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 dsec = dir->i_security;
1559 isec = dentry->d_inode->i_security;
1560
1561 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001562 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
1564 av = DIR__SEARCH;
1565 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
1566 rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad);
1567 if (rc)
1568 return rc;
1569
1570 switch (kind) {
1571 case MAY_LINK:
1572 av = FILE__LINK;
1573 break;
1574 case MAY_UNLINK:
1575 av = FILE__UNLINK;
1576 break;
1577 case MAY_RMDIR:
1578 av = DIR__RMDIR;
1579 break;
1580 default:
Eric Paris744ba352008-04-17 11:52:44 -04001581 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1582 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return 0;
1584 }
1585
1586 rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad);
1587 return rc;
1588}
1589
1590static inline int may_rename(struct inode *old_dir,
1591 struct dentry *old_dentry,
1592 struct inode *new_dir,
1593 struct dentry *new_dentry)
1594{
1595 struct task_security_struct *tsec;
1596 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1597 struct avc_audit_data ad;
1598 u32 av;
1599 int old_is_dir, new_is_dir;
1600 int rc;
1601
David Howellsb6dff3e2008-11-14 10:39:16 +11001602 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 old_dsec = old_dir->i_security;
1604 old_isec = old_dentry->d_inode->i_security;
1605 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1606 new_dsec = new_dir->i_security;
1607
1608 AVC_AUDIT_DATA_INIT(&ad, FS);
1609
Jan Blunck44707fd2008-02-14 19:38:33 -08001610 ad.u.fs.path.dentry = old_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR,
1612 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1613 if (rc)
1614 return rc;
1615 rc = avc_has_perm(tsec->sid, old_isec->sid,
1616 old_isec->sclass, FILE__RENAME, &ad);
1617 if (rc)
1618 return rc;
1619 if (old_is_dir && new_dir != old_dir) {
1620 rc = avc_has_perm(tsec->sid, old_isec->sid,
1621 old_isec->sclass, DIR__REPARENT, &ad);
1622 if (rc)
1623 return rc;
1624 }
1625
Jan Blunck44707fd2008-02-14 19:38:33 -08001626 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 av = DIR__ADD_NAME | DIR__SEARCH;
1628 if (new_dentry->d_inode)
1629 av |= DIR__REMOVE_NAME;
1630 rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
1631 if (rc)
1632 return rc;
1633 if (new_dentry->d_inode) {
1634 new_isec = new_dentry->d_inode->i_security;
1635 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
1636 rc = avc_has_perm(tsec->sid, new_isec->sid,
1637 new_isec->sclass,
1638 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1639 if (rc)
1640 return rc;
1641 }
1642
1643 return 0;
1644}
1645
1646/* Check whether a task can perform a filesystem operation. */
1647static int superblock_has_perm(struct task_struct *tsk,
1648 struct super_block *sb,
1649 u32 perms,
1650 struct avc_audit_data *ad)
1651{
1652 struct task_security_struct *tsec;
1653 struct superblock_security_struct *sbsec;
1654
David Howellsb6dff3e2008-11-14 10:39:16 +11001655 tsec = tsk->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 sbsec = sb->s_security;
1657 return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
1658 perms, ad);
1659}
1660
1661/* Convert a Linux mode and permission mask to an access vector. */
1662static inline u32 file_mask_to_av(int mode, int mask)
1663{
1664 u32 av = 0;
1665
1666 if ((mode & S_IFMT) != S_IFDIR) {
1667 if (mask & MAY_EXEC)
1668 av |= FILE__EXECUTE;
1669 if (mask & MAY_READ)
1670 av |= FILE__READ;
1671
1672 if (mask & MAY_APPEND)
1673 av |= FILE__APPEND;
1674 else if (mask & MAY_WRITE)
1675 av |= FILE__WRITE;
1676
1677 } else {
1678 if (mask & MAY_EXEC)
1679 av |= DIR__SEARCH;
1680 if (mask & MAY_WRITE)
1681 av |= DIR__WRITE;
1682 if (mask & MAY_READ)
1683 av |= DIR__READ;
1684 }
1685
1686 return av;
1687}
1688
1689/* Convert a Linux file to an access vector. */
1690static inline u32 file_to_av(struct file *file)
1691{
1692 u32 av = 0;
1693
1694 if (file->f_mode & FMODE_READ)
1695 av |= FILE__READ;
1696 if (file->f_mode & FMODE_WRITE) {
1697 if (file->f_flags & O_APPEND)
1698 av |= FILE__APPEND;
1699 else
1700 av |= FILE__WRITE;
1701 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001702 if (!av) {
1703 /*
1704 * Special file opened with flags 3 for ioctl-only use.
1705 */
1706 av = FILE__IOCTL;
1707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 return av;
1710}
1711
Eric Paris8b6a5a32008-10-29 17:06:46 -04001712/*
1713 * Convert a file to an access vector and include the correct open
1714 * open permission.
1715 */
1716static inline u32 open_file_to_av(struct file *file)
1717{
1718 u32 av = file_to_av(file);
1719
1720 if (selinux_policycap_openperm) {
1721 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1722 /*
1723 * lnk files and socks do not really have an 'open'
1724 */
1725 if (S_ISREG(mode))
1726 av |= FILE__OPEN;
1727 else if (S_ISCHR(mode))
1728 av |= CHR_FILE__OPEN;
1729 else if (S_ISBLK(mode))
1730 av |= BLK_FILE__OPEN;
1731 else if (S_ISFIFO(mode))
1732 av |= FIFO_FILE__OPEN;
1733 else if (S_ISDIR(mode))
1734 av |= DIR__OPEN;
1735 else
1736 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1737 "unknown mode:%o\n", __func__, mode);
1738 }
1739 return av;
1740}
1741
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742/* Hook functions begin here. */
1743
David Howells5cd9c582008-08-14 11:37:28 +01001744static int selinux_ptrace_may_access(struct task_struct *child,
1745 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 int rc;
1748
David Howells5cd9c582008-08-14 11:37:28 +01001749 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 if (rc)
1751 return rc;
1752
Stephen Smalley006ebb42008-05-19 08:32:49 -04001753 if (mode == PTRACE_MODE_READ) {
David Howellsb6dff3e2008-11-14 10:39:16 +11001754 struct task_security_struct *tsec = current->cred->security;
1755 struct task_security_struct *csec = child->cred->security;
Stephen Smalley006ebb42008-05-19 08:32:49 -04001756 return avc_has_perm(tsec->sid, csec->sid,
1757 SECCLASS_FILE, FILE__READ, NULL);
1758 }
1759
David Howells5cd9c582008-08-14 11:37:28 +01001760 return task_has_perm(current, child, PROCESS__PTRACE);
1761}
1762
1763static int selinux_ptrace_traceme(struct task_struct *parent)
1764{
1765 int rc;
1766
1767 rc = secondary_ops->ptrace_traceme(parent);
1768 if (rc)
1769 return rc;
1770
1771 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772}
1773
1774static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001775 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776{
1777 int error;
1778
1779 error = task_has_perm(current, target, PROCESS__GETCAP);
1780 if (error)
1781 return error;
1782
1783 return secondary_ops->capget(target, effective, inheritable, permitted);
1784}
1785
David Howells15a24602008-11-14 10:39:15 +11001786static int selinux_capset_check(const kernel_cap_t *effective,
1787 const kernel_cap_t *inheritable,
1788 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
1790 int error;
1791
David Howells1cdcbec2008-11-14 10:39:14 +11001792 error = secondary_ops->capset_check(effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if (error)
1794 return error;
1795
David Howells1cdcbec2008-11-14 10:39:14 +11001796 return task_has_perm(current, current, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797}
1798
David Howells15a24602008-11-14 10:39:15 +11001799static void selinux_capset_set(const kernel_cap_t *effective,
1800 const kernel_cap_t *inheritable,
1801 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802{
David Howells1cdcbec2008-11-14 10:39:14 +11001803 secondary_ops->capset_set(effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804}
1805
Eric Paris06112162008-11-11 22:02:50 +11001806static int selinux_capable(struct task_struct *tsk, int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807{
1808 int rc;
1809
Eric Paris06112162008-11-11 22:02:50 +11001810 rc = secondary_ops->capable(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 if (rc)
1812 return rc;
1813
Eric Paris06112162008-11-11 22:02:50 +11001814 return task_has_capability(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815}
1816
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001817static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1818{
1819 int buflen, rc;
1820 char *buffer, *path, *end;
1821
1822 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001823 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001824 if (!buffer)
1825 goto out;
1826
1827 buflen = PAGE_SIZE;
1828 end = buffer+buflen;
1829 *--end = '\0';
1830 buflen--;
1831 path = end-1;
1832 *path = '/';
1833 while (table) {
1834 const char *name = table->procname;
1835 size_t namelen = strlen(name);
1836 buflen -= namelen + 1;
1837 if (buflen < 0)
1838 goto out_free;
1839 end -= namelen;
1840 memcpy(end, name, namelen);
1841 *--end = '/';
1842 path = end;
1843 table = table->parent;
1844 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001845 buflen -= 4;
1846 if (buflen < 0)
1847 goto out_free;
1848 end -= 4;
1849 memcpy(end, "/sys", 4);
1850 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001851 rc = security_genfs_sid("proc", path, tclass, sid);
1852out_free:
1853 free_page((unsigned long)buffer);
1854out:
1855 return rc;
1856}
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858static int selinux_sysctl(ctl_table *table, int op)
1859{
1860 int error = 0;
1861 u32 av;
1862 struct task_security_struct *tsec;
1863 u32 tsid;
1864 int rc;
1865
1866 rc = secondary_ops->sysctl(table, op);
1867 if (rc)
1868 return rc;
1869
David Howellsb6dff3e2008-11-14 10:39:16 +11001870 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001872 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1873 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (rc) {
1875 /* Default to the well-defined sysctl SID. */
1876 tsid = SECINITSID_SYSCTL;
1877 }
1878
1879 /* The op values are "defined" in sysctl.c, thereby creating
1880 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001881 if (op == 001) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 error = avc_has_perm(tsec->sid, tsid,
1883 SECCLASS_DIR, DIR__SEARCH, NULL);
1884 } else {
1885 av = 0;
1886 if (op & 004)
1887 av |= FILE__READ;
1888 if (op & 002)
1889 av |= FILE__WRITE;
1890 if (av)
1891 error = avc_has_perm(tsec->sid, tsid,
1892 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
1895 return error;
1896}
1897
1898static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1899{
1900 int rc = 0;
1901
1902 if (!sb)
1903 return 0;
1904
1905 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001906 case Q_SYNC:
1907 case Q_QUOTAON:
1908 case Q_QUOTAOFF:
1909 case Q_SETINFO:
1910 case Q_SETQUOTA:
1911 rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
1912 NULL);
1913 break;
1914 case Q_GETFMT:
1915 case Q_GETINFO:
1916 case Q_GETQUOTA:
1917 rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
1918 NULL);
1919 break;
1920 default:
1921 rc = 0; /* let the kernel handle invalid cmds */
1922 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 }
1924 return rc;
1925}
1926
1927static int selinux_quota_on(struct dentry *dentry)
1928{
1929 return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
1930}
1931
1932static int selinux_syslog(int type)
1933{
1934 int rc;
1935
1936 rc = secondary_ops->syslog(type);
1937 if (rc)
1938 return rc;
1939
1940 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04001941 case 3: /* Read last kernel messages */
1942 case 10: /* Return size of the log buffer */
1943 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1944 break;
1945 case 6: /* Disable logging to console */
1946 case 7: /* Enable logging to console */
1947 case 8: /* Set level of messages printed to console */
1948 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1949 break;
1950 case 0: /* Close log */
1951 case 1: /* Open log */
1952 case 2: /* Read from log */
1953 case 4: /* Read/clear last kernel messages */
1954 case 5: /* Clear ring buffer */
1955 default:
1956 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1957 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 }
1959 return rc;
1960}
1961
1962/*
1963 * Check that a process has enough memory to allocate a new virtual
1964 * mapping. 0 means there is enough memory for the allocation to
1965 * succeed and -ENOMEM implies there is not.
1966 *
1967 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
1968 * if the capability is granted, but __vm_enough_memory requires 1 if
1969 * the capability is granted.
1970 *
1971 * Do not audit the selinux permission check, as this is applied to all
1972 * processes that allocate mappings.
1973 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001974static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975{
1976 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Eric Paris06674672008-11-11 22:02:57 +11001978 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 if (rc == 0)
1980 cap_sys_admin = 1;
1981
Alan Cox34b4e4a2007-08-22 14:01:28 -07001982 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983}
1984
1985/* binprm security operations */
1986
1987static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
1988{
1989 struct bprm_security_struct *bsec;
1990
James Morris89d155e2005-10-30 14:59:21 -08001991 bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 if (!bsec)
1993 return -ENOMEM;
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 bsec->sid = SECINITSID_UNLABELED;
1996 bsec->set = 0;
1997
1998 bprm->security = bsec;
1999 return 0;
2000}
2001
2002static int selinux_bprm_set_security(struct linux_binprm *bprm)
2003{
2004 struct task_security_struct *tsec;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002005 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 struct inode_security_struct *isec;
2007 struct bprm_security_struct *bsec;
2008 u32 newsid;
2009 struct avc_audit_data ad;
2010 int rc;
2011
2012 rc = secondary_ops->bprm_set_security(bprm);
2013 if (rc)
2014 return rc;
2015
2016 bsec = bprm->security;
2017
2018 if (bsec->set)
2019 return 0;
2020
David Howellsb6dff3e2008-11-14 10:39:16 +11002021 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 isec = inode->i_security;
2023
2024 /* Default to the current task SID. */
2025 bsec->sid = tsec->sid;
2026
Michael LeMay28eba5b2006-06-27 02:53:42 -07002027 /* Reset fs, key, and sock SIDs on execve. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 tsec->create_sid = 0;
Michael LeMay28eba5b2006-06-27 02:53:42 -07002029 tsec->keycreate_sid = 0;
Eric Paris42c3e032006-06-26 00:26:03 -07002030 tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031
2032 if (tsec->exec_sid) {
2033 newsid = tsec->exec_sid;
2034 /* Reset exec SID on execve. */
2035 tsec->exec_sid = 0;
2036 } else {
2037 /* Check for a default transition on this program. */
2038 rc = security_transition_sid(tsec->sid, isec->sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002039 SECCLASS_PROCESS, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 if (rc)
2041 return rc;
2042 }
2043
2044 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002045 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
Josef Sipek3d5ff522006-12-08 02:37:38 -08002047 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 newsid = tsec->sid;
2049
Eric Paris828dfe12008-04-17 13:17:49 -04002050 if (tsec->sid == newsid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 rc = avc_has_perm(tsec->sid, isec->sid,
2052 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2053 if (rc)
2054 return rc;
2055 } else {
2056 /* Check permissions for the transition. */
2057 rc = avc_has_perm(tsec->sid, newsid,
2058 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2059 if (rc)
2060 return rc;
2061
2062 rc = avc_has_perm(newsid, isec->sid,
2063 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2064 if (rc)
2065 return rc;
2066
2067 /* Clear any possibly unsafe personality bits on exec: */
2068 current->personality &= ~PER_CLEAR_ON_SETID;
2069
2070 /* Set the security field to the new SID. */
2071 bsec->sid = newsid;
2072 }
2073
2074 bsec->set = 1;
2075 return 0;
2076}
2077
Eric Paris828dfe12008-04-17 13:17:49 -04002078static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
2080 return secondary_ops->bprm_check_security(bprm);
2081}
2082
2083
Eric Paris828dfe12008-04-17 13:17:49 -04002084static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085{
David Howellsb6dff3e2008-11-14 10:39:16 +11002086 struct task_security_struct *tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 int atsecure = 0;
2088
2089 if (tsec->osid != tsec->sid) {
2090 /* Enable secure mode for SIDs transitions unless
2091 the noatsecure permission is granted between
2092 the two SIDs, i.e. ahp returns 0. */
2093 atsecure = avc_has_perm(tsec->osid, tsec->sid,
2094 SECCLASS_PROCESS,
2095 PROCESS__NOATSECURE, NULL);
2096 }
2097
2098 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2099}
2100
2101static void selinux_bprm_free_security(struct linux_binprm *bprm)
2102{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07002103 kfree(bprm->security);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 bprm->security = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105}
2106
2107extern struct vfsmount *selinuxfs_mount;
2108extern struct dentry *selinux_null;
2109
2110/* Derived from fs/exec.c:flush_old_files. */
Eric Paris828dfe12008-04-17 13:17:49 -04002111static inline void flush_unauthorized_files(struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
2113 struct avc_audit_data ad;
2114 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002115 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002116 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002118 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002120 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if (tty) {
2122 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002123 if (!list_empty(&tty->tty_files)) {
2124 struct inode *inode;
2125
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 /* Revalidate access to controlling tty.
2127 Use inode_has_perm on the tty inode directly rather
2128 than using file_has_perm, as this particular open
2129 file may belong to another process and we are only
2130 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002131 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2132 inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 if (inode_has_perm(current, inode,
2134 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002135 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 }
2137 }
2138 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002139 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002141 /* Reset controlling tty. */
2142 if (drop_tty)
2143 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
2145 /* Revalidate access to inherited open files. */
2146
Eric Paris828dfe12008-04-17 13:17:49 -04002147 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
2149 spin_lock(&files->file_lock);
2150 for (;;) {
2151 unsigned long set, i;
2152 int fd;
2153
2154 j++;
2155 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002156 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002157 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002159 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (!set)
2161 continue;
2162 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002163 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (set & 1) {
2165 file = fget(i);
2166 if (!file)
2167 continue;
2168 if (file_has_perm(current,
2169 file,
2170 file_to_av(file))) {
2171 sys_close(i);
2172 fd = get_unused_fd();
2173 if (fd != i) {
2174 if (fd >= 0)
2175 put_unused_fd(fd);
2176 fput(file);
2177 continue;
2178 }
2179 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002180 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 } else {
2182 devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002183 if (IS_ERR(devnull)) {
2184 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 put_unused_fd(fd);
2186 fput(file);
2187 continue;
2188 }
2189 }
2190 fd_install(fd, devnull);
2191 }
2192 fput(file);
2193 }
2194 }
2195 spin_lock(&files->file_lock);
2196
2197 }
2198 spin_unlock(&files->file_lock);
2199}
2200
2201static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
2202{
2203 struct task_security_struct *tsec;
2204 struct bprm_security_struct *bsec;
2205 u32 sid;
2206 int rc;
2207
2208 secondary_ops->bprm_apply_creds(bprm, unsafe);
2209
David Howellsb6dff3e2008-11-14 10:39:16 +11002210 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212 bsec = bprm->security;
2213 sid = bsec->sid;
2214
2215 tsec->osid = tsec->sid;
2216 bsec->unsafe = 0;
2217 if (tsec->sid != sid) {
2218 /* Check for shared state. If not ok, leave SID
2219 unchanged and kill. */
2220 if (unsafe & LSM_UNSAFE_SHARE) {
2221 rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
2222 PROCESS__SHARE, NULL);
2223 if (rc) {
2224 bsec->unsafe = 1;
2225 return;
2226 }
2227 }
2228
2229 /* Check for ptracing, and update the task SID if ok.
2230 Otherwise, leave SID unchanged and kill. */
2231 if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
Roland McGrath03563572008-03-26 15:46:39 -07002232 struct task_struct *tracer;
2233 struct task_security_struct *sec;
2234 u32 ptsid = 0;
2235
2236 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07002237 tracer = tracehook_tracer_task(current);
Roland McGrath03563572008-03-26 15:46:39 -07002238 if (likely(tracer != NULL)) {
David Howellsb6dff3e2008-11-14 10:39:16 +11002239 sec = tracer->cred->security;
Roland McGrath03563572008-03-26 15:46:39 -07002240 ptsid = sec->sid;
2241 }
2242 rcu_read_unlock();
2243
2244 if (ptsid != 0) {
2245 rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
2246 PROCESS__PTRACE, NULL);
2247 if (rc) {
2248 bsec->unsafe = 1;
2249 return;
2250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 }
2252 }
2253 tsec->sid = sid;
2254 }
2255}
2256
2257/*
2258 * called after apply_creds without the task lock held
2259 */
2260static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
2261{
2262 struct task_security_struct *tsec;
2263 struct rlimit *rlim, *initrlim;
2264 struct itimerval itimer;
2265 struct bprm_security_struct *bsec;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002266 struct sighand_struct *psig;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 int rc, i;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002268 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
David Howellsb6dff3e2008-11-14 10:39:16 +11002270 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 bsec = bprm->security;
2272
2273 if (bsec->unsafe) {
2274 force_sig_specific(SIGKILL, current);
2275 return;
2276 }
2277 if (tsec->osid == tsec->sid)
2278 return;
2279
2280 /* Close files for which the new task SID is not authorized. */
2281 flush_unauthorized_files(current->files);
2282
2283 /* Check whether the new SID can inherit signal state
2284 from the old SID. If not, clear itimers to avoid
2285 subsequent signal generation and flush and unblock
2286 signals. This must occur _after_ the task SID has
2287 been updated so that any kill done after the flush
2288 will be checked against the new SID. */
2289 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2290 PROCESS__SIGINH, NULL);
2291 if (rc) {
2292 memset(&itimer, 0, sizeof itimer);
2293 for (i = 0; i < 3; i++)
2294 do_setitimer(i, &itimer, NULL);
2295 flush_signals(current);
2296 spin_lock_irq(&current->sighand->siglock);
2297 flush_signal_handlers(current, 1);
2298 sigemptyset(&current->blocked);
2299 recalc_sigpending();
2300 spin_unlock_irq(&current->sighand->siglock);
2301 }
2302
Stephen Smalley4ac212a2007-08-29 08:51:50 -04002303 /* Always clear parent death signal on SID transitions. */
2304 current->pdeath_signal = 0;
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 /* Check whether the new SID can inherit resource limits
2307 from the old SID. If not, reset all soft limits to
2308 the lower of the current task's hard limit and the init
2309 task's soft limit. Note that the setting of hard limits
2310 (even to lower them) can be controlled by the setrlimit
2311 check. The inclusion of the init task's soft limit into
2312 the computation is to avoid resetting soft limits higher
2313 than the default soft limit for cases where the default
2314 is lower than the hard limit, e.g. RLIMIT_CORE or
2315 RLIMIT_STACK.*/
2316 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2317 PROCESS__RLIMITINH, NULL);
2318 if (rc) {
2319 for (i = 0; i < RLIM_NLIMITS; i++) {
2320 rlim = current->signal->rlim + i;
2321 initrlim = init_task.signal->rlim+i;
Eric Paris828dfe12008-04-17 13:17:49 -04002322 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
Frank Mayharf06febc2008-09-12 09:54:39 -07002324 update_rlimit_cpu(rlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 }
2326
2327 /* Wake up the parent if it is waiting so that it can
2328 recheck wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002329 read_lock_irq(&tasklist_lock);
2330 psig = current->parent->sighand;
2331 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002333 spin_unlock_irqrestore(&psig->siglock, flags);
2334 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335}
2336
2337/* superblock security operations */
2338
2339static int selinux_sb_alloc_security(struct super_block *sb)
2340{
2341 return superblock_alloc_security(sb);
2342}
2343
2344static void selinux_sb_free_security(struct super_block *sb)
2345{
2346 superblock_free_security(sb);
2347}
2348
2349static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2350{
2351 if (plen > olen)
2352 return 0;
2353
2354 return !memcmp(prefix, option, plen);
2355}
2356
2357static inline int selinux_option(char *option, int len)
2358{
Eric Paris832cbd92008-04-01 13:24:09 -04002359 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2360 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2361 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2362 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363}
2364
2365static inline void take_option(char **to, char *from, int *first, int len)
2366{
2367 if (!*first) {
2368 **to = ',';
2369 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002370 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 *first = 0;
2372 memcpy(*to, from, len);
2373 *to += len;
2374}
2375
Eric Paris828dfe12008-04-17 13:17:49 -04002376static inline void take_selinux_option(char **to, char *from, int *first,
2377 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002378{
2379 int current_size = 0;
2380
2381 if (!*first) {
2382 **to = '|';
2383 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002384 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002385 *first = 0;
2386
2387 while (current_size < len) {
2388 if (*from != '"') {
2389 **to = *from;
2390 *to += 1;
2391 }
2392 from += 1;
2393 current_size += 1;
2394 }
2395}
2396
Eric Parise0007522008-03-05 10:31:54 -05002397static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398{
2399 int fnosec, fsec, rc = 0;
2400 char *in_save, *in_curr, *in_end;
2401 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002402 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
2404 in_curr = orig;
2405 sec_curr = copy;
2406
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2408 if (!nosec) {
2409 rc = -ENOMEM;
2410 goto out;
2411 }
2412
2413 nosec_save = nosec;
2414 fnosec = fsec = 1;
2415 in_save = in_end = orig;
2416
2417 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002418 if (*in_end == '"')
2419 open_quote = !open_quote;
2420 if ((*in_end == ',' && open_quote == 0) ||
2421 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 int len = in_end - in_curr;
2423
2424 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002425 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 else
2427 take_option(&nosec, in_curr, &fnosec, len);
2428
2429 in_curr = in_end + 1;
2430 }
2431 } while (*in_end++);
2432
Eric Paris6931dfc2005-06-30 02:58:51 -07002433 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002434 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435out:
2436 return rc;
2437}
2438
2439static int selinux_sb_kern_mount(struct super_block *sb, void *data)
2440{
2441 struct avc_audit_data ad;
2442 int rc;
2443
2444 rc = superblock_doinit(sb, data);
2445 if (rc)
2446 return rc;
2447
Eric Paris828dfe12008-04-17 13:17:49 -04002448 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002449 ad.u.fs.path.dentry = sb->s_root;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
2451}
2452
David Howells726c3342006-06-23 02:02:58 -07002453static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454{
2455 struct avc_audit_data ad;
2456
Eric Paris828dfe12008-04-17 13:17:49 -04002457 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002458 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells726c3342006-06-23 02:02:58 -07002459 return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460}
2461
Eric Paris828dfe12008-04-17 13:17:49 -04002462static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002463 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002464 char *type,
2465 unsigned long flags,
2466 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467{
2468 int rc;
2469
Al Virob5266eb2008-03-22 17:48:24 -04002470 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 if (rc)
2472 return rc;
2473
2474 if (flags & MS_REMOUNT)
Al Virob5266eb2008-03-22 17:48:24 -04002475 return superblock_has_perm(current, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002476 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 else
Al Virob5266eb2008-03-22 17:48:24 -04002478 return dentry_has_perm(current, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002479 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480}
2481
2482static int selinux_umount(struct vfsmount *mnt, int flags)
2483{
2484 int rc;
2485
2486 rc = secondary_ops->sb_umount(mnt, flags);
2487 if (rc)
2488 return rc;
2489
Eric Paris828dfe12008-04-17 13:17:49 -04002490 return superblock_has_perm(current, mnt->mnt_sb,
2491 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492}
2493
2494/* inode security operations */
2495
2496static int selinux_inode_alloc_security(struct inode *inode)
2497{
2498 return inode_alloc_security(inode);
2499}
2500
2501static void selinux_inode_free_security(struct inode *inode)
2502{
2503 inode_free_security(inode);
2504}
2505
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002506static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2507 char **name, void **value,
2508 size_t *len)
2509{
2510 struct task_security_struct *tsec;
2511 struct inode_security_struct *dsec;
2512 struct superblock_security_struct *sbsec;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002513 u32 newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002514 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002515 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002516
David Howellsb6dff3e2008-11-14 10:39:16 +11002517 tsec = current->cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002518 dsec = dir->i_security;
2519 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002520
2521 if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
2522 newsid = tsec->create_sid;
2523 } else {
2524 rc = security_transition_sid(tsec->sid, dsec->sid,
2525 inode_mode_to_security_class(inode->i_mode),
2526 &newsid);
2527 if (rc) {
2528 printk(KERN_WARNING "%s: "
2529 "security_transition_sid failed, rc=%d (dev=%s "
2530 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002531 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002532 -rc, inode->i_sb->s_id, inode->i_ino);
2533 return rc;
2534 }
2535 }
2536
Eric Paris296fddf2006-09-25 23:32:00 -07002537 /* Possibly defer initialization to selinux_complete_init. */
2538 if (sbsec->initialized) {
2539 struct inode_security_struct *isec = inode->i_security;
2540 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2541 isec->sid = newsid;
2542 isec->initialized = 1;
2543 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002544
Stephen Smalley8aad3872006-03-22 00:09:13 -08002545 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002546 return -EOPNOTSUPP;
2547
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002548 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002549 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002550 if (!namep)
2551 return -ENOMEM;
2552 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002553 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002554
2555 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002556 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002557 if (rc) {
2558 kfree(namep);
2559 return rc;
2560 }
2561 *value = context;
2562 *len = clen;
2563 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002564
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002565 return 0;
2566}
2567
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2569{
2570 return may_create(dir, dentry, SECCLASS_FILE);
2571}
2572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2574{
2575 int rc;
2576
Eric Paris828dfe12008-04-17 13:17:49 -04002577 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 if (rc)
2579 return rc;
2580 return may_link(dir, old_dentry, MAY_LINK);
2581}
2582
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2584{
2585 int rc;
2586
2587 rc = secondary_ops->inode_unlink(dir, dentry);
2588 if (rc)
2589 return rc;
2590 return may_link(dir, dentry, MAY_UNLINK);
2591}
2592
2593static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2594{
2595 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2596}
2597
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2599{
2600 return may_create(dir, dentry, SECCLASS_DIR);
2601}
2602
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2604{
2605 return may_link(dir, dentry, MAY_RMDIR);
2606}
2607
2608static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2609{
2610 int rc;
2611
2612 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2613 if (rc)
2614 return rc;
2615
2616 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2617}
2618
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002620 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
2622 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2623}
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625static int selinux_inode_readlink(struct dentry *dentry)
2626{
2627 return dentry_has_perm(current, NULL, dentry, FILE__READ);
2628}
2629
2630static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2631{
2632 int rc;
2633
Eric Paris828dfe12008-04-17 13:17:49 -04002634 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 if (rc)
2636 return rc;
2637 return dentry_has_perm(current, NULL, dentry, FILE__READ);
2638}
2639
Al Virob77b0642008-07-17 09:37:02 -04002640static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641{
2642 int rc;
2643
Al Virob77b0642008-07-17 09:37:02 -04002644 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 if (rc)
2646 return rc;
2647
2648 if (!mask) {
2649 /* No permission to check. Existence test. */
2650 return 0;
2651 }
2652
2653 return inode_has_perm(current, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002654 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655}
2656
2657static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2658{
2659 int rc;
2660
2661 rc = secondary_ops->inode_setattr(dentry, iattr);
2662 if (rc)
2663 return rc;
2664
2665 if (iattr->ia_valid & ATTR_FORCE)
2666 return 0;
2667
2668 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2669 ATTR_ATIME_SET | ATTR_MTIME_SET))
2670 return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
2671
2672 return dentry_has_perm(current, NULL, dentry, FILE__WRITE);
2673}
2674
2675static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2676{
2677 return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
2678}
2679
David Howells8f0cfa52008-04-29 00:59:41 -07002680static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002681{
2682 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2683 sizeof XATTR_SECURITY_PREFIX - 1)) {
2684 if (!strcmp(name, XATTR_NAME_CAPS)) {
2685 if (!capable(CAP_SETFCAP))
2686 return -EPERM;
2687 } else if (!capable(CAP_SYS_ADMIN)) {
2688 /* A different attribute in the security namespace.
2689 Restrict to administrator. */
2690 return -EPERM;
2691 }
2692 }
2693
2694 /* Not an attribute we recognize, so just check the
2695 ordinary setattr permission. */
2696 return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
2697}
2698
David Howells8f0cfa52008-04-29 00:59:41 -07002699static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2700 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701{
David Howellsb6dff3e2008-11-14 10:39:16 +11002702 struct task_security_struct *tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 struct inode *inode = dentry->d_inode;
2704 struct inode_security_struct *isec = inode->i_security;
2705 struct superblock_security_struct *sbsec;
2706 struct avc_audit_data ad;
2707 u32 newsid;
2708 int rc = 0;
2709
Serge E. Hallynb5376772007-10-16 23:31:36 -07002710 if (strcmp(name, XATTR_NAME_SELINUX))
2711 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 sbsec = inode->i_sb->s_security;
2714 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2715 return -EOPNOTSUPP;
2716
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302717 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return -EPERM;
2719
Eric Paris828dfe12008-04-17 13:17:49 -04002720 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002721 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723 rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
2724 FILE__RELABELFROM, &ad);
2725 if (rc)
2726 return rc;
2727
2728 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002729 if (rc == -EINVAL) {
2730 if (!capable(CAP_MAC_ADMIN))
2731 return rc;
2732 rc = security_context_to_sid_force(value, size, &newsid);
2733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 if (rc)
2735 return rc;
2736
2737 rc = avc_has_perm(tsec->sid, newsid, isec->sclass,
2738 FILE__RELABELTO, &ad);
2739 if (rc)
2740 return rc;
2741
2742 rc = security_validate_transition(isec->sid, newsid, tsec->sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002743 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 if (rc)
2745 return rc;
2746
2747 return avc_has_perm(newsid,
2748 sbsec->sid,
2749 SECCLASS_FILESYSTEM,
2750 FILESYSTEM__ASSOCIATE,
2751 &ad);
2752}
2753
David Howells8f0cfa52008-04-29 00:59:41 -07002754static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002755 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002756 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757{
2758 struct inode *inode = dentry->d_inode;
2759 struct inode_security_struct *isec = inode->i_security;
2760 u32 newsid;
2761 int rc;
2762
2763 if (strcmp(name, XATTR_NAME_SELINUX)) {
2764 /* Not an attribute we recognize, so nothing to do. */
2765 return;
2766 }
2767
Stephen Smalley12b29f32008-05-07 13:03:20 -04002768 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002770 printk(KERN_ERR "SELinux: unable to map context to SID"
2771 "for (%s, %lu), rc=%d\n",
2772 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 return;
2774 }
2775
2776 isec->sid = newsid;
2777 return;
2778}
2779
David Howells8f0cfa52008-04-29 00:59:41 -07002780static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
2783}
2784
Eric Paris828dfe12008-04-17 13:17:49 -04002785static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786{
2787 return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
2788}
2789
David Howells8f0cfa52008-04-29 00:59:41 -07002790static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002792 if (strcmp(name, XATTR_NAME_SELINUX))
2793 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
2795 /* No one is allowed to remove a SELinux security label.
2796 You can change the label, but all data must be labeled. */
2797 return -EACCES;
2798}
2799
James Morrisd381d8a2005-10-30 14:59:22 -08002800/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002801 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002802 *
2803 * Permission check is handled by selinux_inode_getxattr hook.
2804 */
David P. Quigley42492592008-02-04 22:29:39 -08002805static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806{
David P. Quigley42492592008-02-04 22:29:39 -08002807 u32 size;
2808 int error;
2809 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002812 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2813 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002815 /*
2816 * If the caller has CAP_MAC_ADMIN, then get the raw context
2817 * value even if it is not defined by current policy; otherwise,
2818 * use the in-core value under current policy.
2819 * Use the non-auditing forms of the permission checks since
2820 * getxattr may be called by unprivileged processes commonly
2821 * and lack of permission just means that we fall back to the
2822 * in-core context value, not a denial.
2823 */
Eric Paris06674672008-11-11 22:02:57 +11002824 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002825 if (!error)
2826 error = security_sid_to_context_force(isec->sid, &context,
2827 &size);
2828 else
2829 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002830 if (error)
2831 return error;
2832 error = size;
2833 if (alloc) {
2834 *buffer = context;
2835 goto out_nofree;
2836 }
2837 kfree(context);
2838out_nofree:
2839 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840}
2841
2842static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002843 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844{
2845 struct inode_security_struct *isec = inode->i_security;
2846 u32 newsid;
2847 int rc;
2848
2849 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2850 return -EOPNOTSUPP;
2851
2852 if (!value || !size)
2853 return -EACCES;
2854
Eric Paris828dfe12008-04-17 13:17:49 -04002855 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 if (rc)
2857 return rc;
2858
2859 isec->sid = newsid;
2860 return 0;
2861}
2862
2863static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2864{
2865 const int len = sizeof(XATTR_NAME_SELINUX);
2866 if (buffer && len <= buffer_size)
2867 memcpy(buffer, XATTR_NAME_SELINUX, len);
2868 return len;
2869}
2870
Serge E. Hallynb5376772007-10-16 23:31:36 -07002871static int selinux_inode_need_killpriv(struct dentry *dentry)
2872{
2873 return secondary_ops->inode_need_killpriv(dentry);
2874}
2875
2876static int selinux_inode_killpriv(struct dentry *dentry)
2877{
2878 return secondary_ops->inode_killpriv(dentry);
2879}
2880
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002881static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2882{
2883 struct inode_security_struct *isec = inode->i_security;
2884 *secid = isec->sid;
2885}
2886
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887/* file security operations */
2888
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002889static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002891 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002892 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894 if (!mask) {
2895 /* No permission to check. Existence test. */
2896 return 0;
2897 }
2898
2899 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2900 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2901 mask |= MAY_APPEND;
2902
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002903 rc = file_has_perm(current, file,
2904 file_mask_to_av(inode->i_mode, mask));
2905 if (rc)
2906 return rc;
2907
2908 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909}
2910
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002911static int selinux_file_permission(struct file *file, int mask)
2912{
2913 struct inode *inode = file->f_path.dentry->d_inode;
David Howellsb6dff3e2008-11-14 10:39:16 +11002914 struct task_security_struct *tsec = current->cred->security;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002915 struct file_security_struct *fsec = file->f_security;
2916 struct inode_security_struct *isec = inode->i_security;
2917
2918 if (!mask) {
2919 /* No permission to check. Existence test. */
2920 return 0;
2921 }
2922
2923 if (tsec->sid == fsec->sid && fsec->isid == isec->sid
2924 && fsec->pseqno == avc_policy_seqno())
2925 return selinux_netlbl_inode_permission(inode, mask);
2926
2927 return selinux_revalidate_file_permission(file, mask);
2928}
2929
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930static int selinux_file_alloc_security(struct file *file)
2931{
2932 return file_alloc_security(file);
2933}
2934
2935static void selinux_file_free_security(struct file *file)
2936{
2937 file_free_security(file);
2938}
2939
2940static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2941 unsigned long arg)
2942{
Stephen Smalley242631c2008-06-05 09:21:28 -04002943 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Stephen Smalley242631c2008-06-05 09:21:28 -04002945 if (_IOC_DIR(cmd) & _IOC_WRITE)
2946 av |= FILE__WRITE;
2947 if (_IOC_DIR(cmd) & _IOC_READ)
2948 av |= FILE__READ;
2949 if (!av)
2950 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
Stephen Smalley242631c2008-06-05 09:21:28 -04002952 return file_has_perm(current, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953}
2954
2955static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
2956{
2957#ifndef CONFIG_PPC32
2958 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
2959 /*
2960 * We are making executable an anonymous mapping or a
2961 * private file mapping that will also be writable.
2962 * This has an additional check.
2963 */
2964 int rc = task_has_perm(current, current, PROCESS__EXECMEM);
2965 if (rc)
2966 return rc;
2967 }
2968#endif
2969
2970 if (file) {
2971 /* read access is always possible with a mapping */
2972 u32 av = FILE__READ;
2973
2974 /* write access only matters if the mapping is shared */
2975 if (shared && (prot & PROT_WRITE))
2976 av |= FILE__WRITE;
2977
2978 if (prot & PROT_EXEC)
2979 av |= FILE__EXECUTE;
2980
2981 return file_has_perm(current, file, av);
2982 }
2983 return 0;
2984}
2985
2986static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04002987 unsigned long prot, unsigned long flags,
2988 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989{
Eric Parised032182007-06-28 15:55:21 -04002990 int rc = 0;
David Howellsb6dff3e2008-11-14 10:39:16 +11002991 u32 sid = ((struct task_security_struct *)
2992 (current->cred->security))->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
Eric Parised032182007-06-28 15:55:21 -04002994 if (addr < mmap_min_addr)
2995 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
2996 MEMPROTECT__MMAP_ZERO, NULL);
2997 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 return rc;
2999
3000 if (selinux_checkreqprot)
3001 prot = reqprot;
3002
3003 return file_map_prot_check(file, prot,
3004 (flags & MAP_TYPE) == MAP_SHARED);
3005}
3006
3007static int selinux_file_mprotect(struct vm_area_struct *vma,
3008 unsigned long reqprot,
3009 unsigned long prot)
3010{
3011 int rc;
3012
3013 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3014 if (rc)
3015 return rc;
3016
3017 if (selinux_checkreqprot)
3018 prot = reqprot;
3019
3020#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003021 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3022 rc = 0;
3023 if (vma->vm_start >= vma->vm_mm->start_brk &&
3024 vma->vm_end <= vma->vm_mm->brk) {
3025 rc = task_has_perm(current, current,
3026 PROCESS__EXECHEAP);
3027 } else if (!vma->vm_file &&
3028 vma->vm_start <= vma->vm_mm->start_stack &&
3029 vma->vm_end >= vma->vm_mm->start_stack) {
3030 rc = task_has_perm(current, current, PROCESS__EXECSTACK);
3031 } else if (vma->vm_file && vma->anon_vma) {
3032 /*
3033 * We are making executable a file mapping that has
3034 * had some COW done. Since pages might have been
3035 * written, check ability to execute the possibly
3036 * modified content. This typically should only
3037 * occur for text relocations.
3038 */
3039 rc = file_has_perm(current, vma->vm_file,
3040 FILE__EXECMOD);
3041 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003042 if (rc)
3043 return rc;
3044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045#endif
3046
3047 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3048}
3049
3050static int selinux_file_lock(struct file *file, unsigned int cmd)
3051{
3052 return file_has_perm(current, file, FILE__LOCK);
3053}
3054
3055static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3056 unsigned long arg)
3057{
3058 int err = 0;
3059
3060 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003061 case F_SETFL:
3062 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3063 err = -EINVAL;
3064 break;
3065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
Eric Paris828dfe12008-04-17 13:17:49 -04003067 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
3068 err = file_has_perm(current, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003070 }
3071 /* fall through */
3072 case F_SETOWN:
3073 case F_SETSIG:
3074 case F_GETFL:
3075 case F_GETOWN:
3076 case F_GETSIG:
3077 /* Just check FD__USE permission */
3078 err = file_has_perm(current, file, 0);
3079 break;
3080 case F_GETLK:
3081 case F_SETLK:
3082 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003084 case F_GETLK64:
3085 case F_SETLK64:
3086 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003088 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3089 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003091 }
3092 err = file_has_perm(current, file, FILE__LOCK);
3093 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 }
3095
3096 return err;
3097}
3098
3099static int selinux_file_set_fowner(struct file *file)
3100{
3101 struct task_security_struct *tsec;
3102 struct file_security_struct *fsec;
3103
David Howellsb6dff3e2008-11-14 10:39:16 +11003104 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 fsec = file->f_security;
3106 fsec->fown_sid = tsec->sid;
3107
3108 return 0;
3109}
3110
3111static int selinux_file_send_sigiotask(struct task_struct *tsk,
3112 struct fown_struct *fown, int signum)
3113{
Eric Paris828dfe12008-04-17 13:17:49 -04003114 struct file *file;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 u32 perm;
3116 struct task_security_struct *tsec;
3117 struct file_security_struct *fsec;
3118
3119 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003120 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
David Howellsb6dff3e2008-11-14 10:39:16 +11003122 tsec = tsk->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 fsec = file->f_security;
3124
3125 if (!signum)
3126 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3127 else
3128 perm = signal_to_av(signum);
3129
3130 return avc_has_perm(fsec->fown_sid, tsec->sid,
3131 SECCLASS_PROCESS, perm, NULL);
3132}
3133
3134static int selinux_file_receive(struct file *file)
3135{
3136 return file_has_perm(current, file, file_to_av(file));
3137}
3138
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003139static int selinux_dentry_open(struct file *file)
3140{
3141 struct file_security_struct *fsec;
3142 struct inode *inode;
3143 struct inode_security_struct *isec;
3144 inode = file->f_path.dentry->d_inode;
3145 fsec = file->f_security;
3146 isec = inode->i_security;
3147 /*
3148 * Save inode label and policy sequence number
3149 * at open-time so that selinux_file_permission
3150 * can determine whether revalidation is necessary.
3151 * Task label is already saved in the file security
3152 * struct as its SID.
3153 */
3154 fsec->isid = isec->sid;
3155 fsec->pseqno = avc_policy_seqno();
3156 /*
3157 * Since the inode label or policy seqno may have changed
3158 * between the selinux_inode_permission check and the saving
3159 * of state above, recheck that access is still permitted.
3160 * Otherwise, access might never be revalidated against the
3161 * new inode label or new policy.
3162 * This check is not redundant - do not remove.
3163 */
Eric Paris8b6a5a32008-10-29 17:06:46 -04003164 return inode_has_perm(current, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003165}
3166
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167/* task security operations */
3168
3169static int selinux_task_create(unsigned long clone_flags)
3170{
3171 int rc;
3172
3173 rc = secondary_ops->task_create(clone_flags);
3174 if (rc)
3175 return rc;
3176
3177 return task_has_perm(current, current, PROCESS__FORK);
3178}
3179
David Howellsf1752ee2008-11-14 10:39:17 +11003180static int selinux_cred_alloc_security(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181{
3182 struct task_security_struct *tsec1, *tsec2;
3183 int rc;
3184
David Howellsb6dff3e2008-11-14 10:39:16 +11003185 tsec1 = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
David Howellsf1752ee2008-11-14 10:39:17 +11003187 rc = cred_alloc_security(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 if (rc)
3189 return rc;
David Howellsf1752ee2008-11-14 10:39:17 +11003190 tsec2 = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192 tsec2->osid = tsec1->osid;
3193 tsec2->sid = tsec1->sid;
3194
Michael LeMay28eba5b2006-06-27 02:53:42 -07003195 /* Retain the exec, fs, key, and sock SIDs across fork */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 tsec2->exec_sid = tsec1->exec_sid;
3197 tsec2->create_sid = tsec1->create_sid;
Michael LeMay28eba5b2006-06-27 02:53:42 -07003198 tsec2->keycreate_sid = tsec1->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07003199 tsec2->sockcreate_sid = tsec1->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 return 0;
3202}
3203
David Howellsf1752ee2008-11-14 10:39:17 +11003204/*
3205 * detach and free the LSM part of a set of credentials
3206 */
3207static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
David Howellsf1752ee2008-11-14 10:39:17 +11003209 struct task_security_struct *tsec = cred->security;
3210 cred->security = NULL;
3211 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212}
3213
3214static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3215{
3216 /* Since setuid only affects the current process, and
3217 since the SELinux controls are not based on the Linux
3218 identity attributes, SELinux does not need to control
3219 this operation. However, SELinux does control the use
3220 of the CAP_SETUID and CAP_SETGID capabilities using the
3221 capable hook. */
3222 return 0;
3223}
3224
3225static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3226{
Eric Paris828dfe12008-04-17 13:17:49 -04003227 return secondary_ops->task_post_setuid(id0, id1, id2, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228}
3229
3230static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3231{
3232 /* See the comment for setuid above. */
3233 return 0;
3234}
3235
3236static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3237{
3238 return task_has_perm(current, p, PROCESS__SETPGID);
3239}
3240
3241static int selinux_task_getpgid(struct task_struct *p)
3242{
3243 return task_has_perm(current, p, PROCESS__GETPGID);
3244}
3245
3246static int selinux_task_getsid(struct task_struct *p)
3247{
3248 return task_has_perm(current, p, PROCESS__GETSESSION);
3249}
3250
David Quigleyf9008e42006-06-30 01:55:46 -07003251static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3252{
David Howellsb6dff3e2008-11-14 10:39:16 +11003253 struct task_security_struct *tsec = p->cred->security;
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02003254 *secid = tsec->sid;
David Quigleyf9008e42006-06-30 01:55:46 -07003255}
3256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257static int selinux_task_setgroups(struct group_info *group_info)
3258{
3259 /* See the comment for setuid above. */
3260 return 0;
3261}
3262
3263static int selinux_task_setnice(struct task_struct *p, int nice)
3264{
3265 int rc;
3266
3267 rc = secondary_ops->task_setnice(p, nice);
3268 if (rc)
3269 return rc;
3270
Eric Paris828dfe12008-04-17 13:17:49 -04003271 return task_has_perm(current, p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272}
3273
James Morris03e68062006-06-23 02:03:58 -07003274static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3275{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003276 int rc;
3277
3278 rc = secondary_ops->task_setioprio(p, ioprio);
3279 if (rc)
3280 return rc;
3281
James Morris03e68062006-06-23 02:03:58 -07003282 return task_has_perm(current, p, PROCESS__SETSCHED);
3283}
3284
David Quigleya1836a42006-06-30 01:55:49 -07003285static int selinux_task_getioprio(struct task_struct *p)
3286{
3287 return task_has_perm(current, p, PROCESS__GETSCHED);
3288}
3289
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3291{
3292 struct rlimit *old_rlim = current->signal->rlim + resource;
3293 int rc;
3294
3295 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3296 if (rc)
3297 return rc;
3298
3299 /* Control the ability to change the hard limit (whether
3300 lowering or raising it), so that the hard limit can
3301 later be used as a safe reset point for the soft limit
3302 upon context transitions. See selinux_bprm_apply_creds. */
3303 if (old_rlim->rlim_max != new_rlim->rlim_max)
3304 return task_has_perm(current, current, PROCESS__SETRLIMIT);
3305
3306 return 0;
3307}
3308
3309static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3310{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003311 int rc;
3312
3313 rc = secondary_ops->task_setscheduler(p, policy, lp);
3314 if (rc)
3315 return rc;
3316
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 return task_has_perm(current, p, PROCESS__SETSCHED);
3318}
3319
3320static int selinux_task_getscheduler(struct task_struct *p)
3321{
3322 return task_has_perm(current, p, PROCESS__GETSCHED);
3323}
3324
David Quigley35601542006-06-23 02:04:01 -07003325static int selinux_task_movememory(struct task_struct *p)
3326{
3327 return task_has_perm(current, p, PROCESS__SETSCHED);
3328}
3329
David Quigleyf9008e42006-06-30 01:55:46 -07003330static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3331 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332{
3333 u32 perm;
3334 int rc;
David Quigleyf9008e42006-06-30 01:55:46 -07003335 struct task_security_struct *tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336
David Quigleyf9008e42006-06-30 01:55:46 -07003337 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 if (rc)
3339 return rc;
3340
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 if (!sig)
3342 perm = PROCESS__SIGNULL; /* null signal; existence test */
3343 else
3344 perm = signal_to_av(sig);
David Howellsb6dff3e2008-11-14 10:39:16 +11003345 tsec = p->cred->security;
David Quigleyf9008e42006-06-30 01:55:46 -07003346 if (secid)
3347 rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
3348 else
3349 rc = task_has_perm(current, p, perm);
3350 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351}
3352
3353static int selinux_task_prctl(int option,
3354 unsigned long arg2,
3355 unsigned long arg3,
3356 unsigned long arg4,
Andrew G. Morgan3898b1b2008-04-28 02:13:40 -07003357 unsigned long arg5,
3358 long *rc_p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359{
3360 /* The current prctl operations do not appear to require
3361 any SELinux controls since they merely observe or modify
3362 the state of the current process. */
Andrew G. Morgan3898b1b2008-04-28 02:13:40 -07003363 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364}
3365
3366static int selinux_task_wait(struct task_struct *p)
3367{
Eric Paris8a535142007-10-22 16:10:31 -04003368 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369}
3370
3371static void selinux_task_reparent_to_init(struct task_struct *p)
3372{
Eric Paris828dfe12008-04-17 13:17:49 -04003373 struct task_security_struct *tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374
3375 secondary_ops->task_reparent_to_init(p);
3376
David Howellsb6dff3e2008-11-14 10:39:16 +11003377 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 tsec->osid = tsec->sid;
3379 tsec->sid = SECINITSID_KERNEL;
3380 return;
3381}
3382
3383static void selinux_task_to_inode(struct task_struct *p,
3384 struct inode *inode)
3385{
David Howellsb6dff3e2008-11-14 10:39:16 +11003386 struct task_security_struct *tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 struct inode_security_struct *isec = inode->i_security;
3388
3389 isec->sid = tsec->sid;
3390 isec->initialized = 1;
3391 return;
3392}
3393
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003395static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3396 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397{
3398 int offset, ihlen, ret = -EINVAL;
3399 struct iphdr _iph, *ih;
3400
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003401 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3403 if (ih == NULL)
3404 goto out;
3405
3406 ihlen = ih->ihl * 4;
3407 if (ihlen < sizeof(_iph))
3408 goto out;
3409
3410 ad->u.net.v4info.saddr = ih->saddr;
3411 ad->u.net.v4info.daddr = ih->daddr;
3412 ret = 0;
3413
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003414 if (proto)
3415 *proto = ih->protocol;
3416
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003418 case IPPROTO_TCP: {
3419 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
Eric Paris828dfe12008-04-17 13:17:49 -04003421 if (ntohs(ih->frag_off) & IP_OFFSET)
3422 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
3424 offset += ihlen;
3425 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3426 if (th == NULL)
3427 break;
3428
3429 ad->u.net.sport = th->source;
3430 ad->u.net.dport = th->dest;
3431 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433
Eric Paris828dfe12008-04-17 13:17:49 -04003434 case IPPROTO_UDP: {
3435 struct udphdr _udph, *uh;
3436
3437 if (ntohs(ih->frag_off) & IP_OFFSET)
3438 break;
3439
3440 offset += ihlen;
3441 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3442 if (uh == NULL)
3443 break;
3444
3445 ad->u.net.sport = uh->source;
3446 ad->u.net.dport = uh->dest;
3447 break;
3448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
James Morris2ee92d42006-11-13 16:09:01 -08003450 case IPPROTO_DCCP: {
3451 struct dccp_hdr _dccph, *dh;
3452
3453 if (ntohs(ih->frag_off) & IP_OFFSET)
3454 break;
3455
3456 offset += ihlen;
3457 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3458 if (dh == NULL)
3459 break;
3460
3461 ad->u.net.sport = dh->dccph_sport;
3462 ad->u.net.dport = dh->dccph_dport;
3463 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003464 }
James Morris2ee92d42006-11-13 16:09:01 -08003465
Eric Paris828dfe12008-04-17 13:17:49 -04003466 default:
3467 break;
3468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469out:
3470 return ret;
3471}
3472
3473#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3474
3475/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003476static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3477 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478{
3479 u8 nexthdr;
3480 int ret = -EINVAL, offset;
3481 struct ipv6hdr _ipv6h, *ip6;
3482
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003483 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3485 if (ip6 == NULL)
3486 goto out;
3487
3488 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3489 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3490 ret = 0;
3491
3492 nexthdr = ip6->nexthdr;
3493 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003494 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 if (offset < 0)
3496 goto out;
3497
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003498 if (proto)
3499 *proto = nexthdr;
3500
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 switch (nexthdr) {
3502 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003503 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
3505 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3506 if (th == NULL)
3507 break;
3508
3509 ad->u.net.sport = th->source;
3510 ad->u.net.dport = th->dest;
3511 break;
3512 }
3513
3514 case IPPROTO_UDP: {
3515 struct udphdr _udph, *uh;
3516
3517 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3518 if (uh == NULL)
3519 break;
3520
3521 ad->u.net.sport = uh->source;
3522 ad->u.net.dport = uh->dest;
3523 break;
3524 }
3525
James Morris2ee92d42006-11-13 16:09:01 -08003526 case IPPROTO_DCCP: {
3527 struct dccp_hdr _dccph, *dh;
3528
3529 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3530 if (dh == NULL)
3531 break;
3532
3533 ad->u.net.sport = dh->dccph_sport;
3534 ad->u.net.dport = dh->dccph_dport;
3535 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003536 }
James Morris2ee92d42006-11-13 16:09:01 -08003537
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 /* includes fragments */
3539 default:
3540 break;
3541 }
3542out:
3543 return ret;
3544}
3545
3546#endif /* IPV6 */
3547
3548static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003549 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550{
David Howellscf9481e2008-07-27 21:31:07 +10003551 char *addrp;
3552 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
3554 switch (ad->u.net.family) {
3555 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003556 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003557 if (ret)
3558 goto parse_error;
3559 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3560 &ad->u.net.v4info.daddr);
3561 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
3563#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3564 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003565 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003566 if (ret)
3567 goto parse_error;
3568 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3569 &ad->u.net.v6info.daddr);
3570 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571#endif /* IPV6 */
3572 default:
David Howellscf9481e2008-07-27 21:31:07 +10003573 addrp = NULL;
3574 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 }
3576
David Howellscf9481e2008-07-27 21:31:07 +10003577parse_error:
3578 printk(KERN_WARNING
3579 "SELinux: failure in selinux_parse_skb(),"
3580 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003582
3583okay:
3584 if (_addrp)
3585 *_addrp = addrp;
3586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587}
3588
Paul Moore4f6a9932007-03-01 14:35:22 -05003589/**
Paul Moore220deb92008-01-29 08:38:23 -05003590 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003591 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003592 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003593 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003594 *
3595 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003596 * Check the various different forms of network peer labeling and determine
3597 * the peer label/SID for the packet; most of the magic actually occurs in
3598 * the security server function security_net_peersid_cmp(). The function
3599 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3600 * or -EACCES if @sid is invalid due to inconsistencies with the different
3601 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003602 *
3603 */
Paul Moore220deb92008-01-29 08:38:23 -05003604static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003605{
Paul Moore71f1cb02008-01-29 08:51:16 -05003606 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003607 u32 xfrm_sid;
3608 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003609 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003610
3611 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003612 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003613
Paul Moore71f1cb02008-01-29 08:51:16 -05003614 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3615 if (unlikely(err)) {
3616 printk(KERN_WARNING
3617 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3618 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003619 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003620 }
Paul Moore220deb92008-01-29 08:38:23 -05003621
3622 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003623}
3624
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625/* socket security operations */
3626static int socket_has_perm(struct task_struct *task, struct socket *sock,
3627 u32 perms)
3628{
3629 struct inode_security_struct *isec;
3630 struct task_security_struct *tsec;
3631 struct avc_audit_data ad;
3632 int err = 0;
3633
David Howellsb6dff3e2008-11-14 10:39:16 +11003634 tsec = task->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 isec = SOCK_INODE(sock)->i_security;
3636
3637 if (isec->sid == SECINITSID_KERNEL)
3638 goto out;
3639
Eric Paris828dfe12008-04-17 13:17:49 -04003640 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 ad.u.net.sk = sock->sk;
3642 err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
3643
3644out:
3645 return err;
3646}
3647
3648static int selinux_socket_create(int family, int type,
3649 int protocol, int kern)
3650{
3651 int err = 0;
3652 struct task_security_struct *tsec;
Eric Paris42c3e032006-06-26 00:26:03 -07003653 u32 newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654
3655 if (kern)
3656 goto out;
3657
David Howellsb6dff3e2008-11-14 10:39:16 +11003658 tsec = current->cred->security;
Eric Paris42c3e032006-06-26 00:26:03 -07003659 newsid = tsec->sockcreate_sid ? : tsec->sid;
3660 err = avc_has_perm(tsec->sid, newsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 socket_type_to_security_class(family, type,
3662 protocol), SOCKET__CREATE, NULL);
3663
3664out:
3665 return err;
3666}
3667
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003668static int selinux_socket_post_create(struct socket *sock, int family,
3669 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003671 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 struct inode_security_struct *isec;
3673 struct task_security_struct *tsec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003674 struct sk_security_struct *sksec;
Eric Paris42c3e032006-06-26 00:26:03 -07003675 u32 newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
3677 isec = SOCK_INODE(sock)->i_security;
3678
David Howellsb6dff3e2008-11-14 10:39:16 +11003679 tsec = current->cred->security;
Eric Paris42c3e032006-06-26 00:26:03 -07003680 newsid = tsec->sockcreate_sid ? : tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 isec->sclass = socket_type_to_security_class(family, type, protocol);
Eric Paris42c3e032006-06-26 00:26:03 -07003682 isec->sid = kern ? SECINITSID_KERNEL : newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 isec->initialized = 1;
3684
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003685 if (sock->sk) {
3686 sksec = sock->sk->sk_security;
3687 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003688 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003689 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003690 }
3691
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003692 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693}
3694
3695/* Range of port numbers used to automatically bind.
3696 Need to determine whether we should perform a name_bind
3697 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698
3699static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3700{
3701 u16 family;
3702 int err;
3703
3704 err = socket_has_perm(current, sock, SOCKET__BIND);
3705 if (err)
3706 goto out;
3707
3708 /*
3709 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003710 * Multiple address binding for SCTP is not supported yet: we just
3711 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 */
3713 family = sock->sk->sk_family;
3714 if (family == PF_INET || family == PF_INET6) {
3715 char *addrp;
3716 struct inode_security_struct *isec;
3717 struct task_security_struct *tsec;
3718 struct avc_audit_data ad;
3719 struct sockaddr_in *addr4 = NULL;
3720 struct sockaddr_in6 *addr6 = NULL;
3721 unsigned short snum;
3722 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003723 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
David Howellsb6dff3e2008-11-14 10:39:16 +11003725 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 isec = SOCK_INODE(sock)->i_security;
3727
3728 if (family == PF_INET) {
3729 addr4 = (struct sockaddr_in *)address;
3730 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 addrp = (char *)&addr4->sin_addr.s_addr;
3732 } else {
3733 addr6 = (struct sockaddr_in6 *)address;
3734 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 addrp = (char *)&addr6->sin6_addr.s6_addr;
3736 }
3737
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003738 if (snum) {
3739 int low, high;
3740
3741 inet_get_local_port_range(&low, &high);
3742
3743 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003744 err = sel_netport_sid(sk->sk_protocol,
3745 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003746 if (err)
3747 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003748 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003749 ad.u.net.sport = htons(snum);
3750 ad.u.net.family = family;
3751 err = avc_has_perm(isec->sid, sid,
3752 isec->sclass,
3753 SOCKET__NAME_BIND, &ad);
3754 if (err)
3755 goto out;
3756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 }
Eric Paris828dfe12008-04-17 13:17:49 -04003758
3759 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003760 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 node_perm = TCP_SOCKET__NODE_BIND;
3762 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003763
James Morris13402582005-09-30 14:24:34 -04003764 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 node_perm = UDP_SOCKET__NODE_BIND;
3766 break;
James Morris2ee92d42006-11-13 16:09:01 -08003767
3768 case SECCLASS_DCCP_SOCKET:
3769 node_perm = DCCP_SOCKET__NODE_BIND;
3770 break;
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 default:
3773 node_perm = RAWIP_SOCKET__NODE_BIND;
3774 break;
3775 }
Eric Paris828dfe12008-04-17 13:17:49 -04003776
Paul Moore224dfbd2008-01-29 08:38:13 -05003777 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 if (err)
3779 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003780
3781 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 ad.u.net.sport = htons(snum);
3783 ad.u.net.family = family;
3784
3785 if (family == PF_INET)
3786 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3787 else
3788 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3789
3790 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003791 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 if (err)
3793 goto out;
3794 }
3795out:
3796 return err;
3797}
3798
3799static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3800{
Paul Moore014ab192008-10-10 10:16:33 -04003801 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 struct inode_security_struct *isec;
3803 int err;
3804
3805 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3806 if (err)
3807 return err;
3808
3809 /*
James Morris2ee92d42006-11-13 16:09:01 -08003810 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 */
3812 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003813 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3814 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 struct avc_audit_data ad;
3816 struct sockaddr_in *addr4 = NULL;
3817 struct sockaddr_in6 *addr6 = NULL;
3818 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003819 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
3821 if (sk->sk_family == PF_INET) {
3822 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003823 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 return -EINVAL;
3825 snum = ntohs(addr4->sin_port);
3826 } else {
3827 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003828 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 return -EINVAL;
3830 snum = ntohs(addr6->sin6_port);
3831 }
3832
Paul Moore3e112172008-04-10 10:48:14 -04003833 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 if (err)
3835 goto out;
3836
James Morris2ee92d42006-11-13 16:09:01 -08003837 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3838 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3839
Eric Paris828dfe12008-04-17 13:17:49 -04003840 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 ad.u.net.dport = htons(snum);
3842 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003843 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 if (err)
3845 goto out;
3846 }
3847
Paul Moore014ab192008-10-10 10:16:33 -04003848 err = selinux_netlbl_socket_connect(sk, address);
3849
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850out:
3851 return err;
3852}
3853
3854static int selinux_socket_listen(struct socket *sock, int backlog)
3855{
3856 return socket_has_perm(current, sock, SOCKET__LISTEN);
3857}
3858
3859static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3860{
3861 int err;
3862 struct inode_security_struct *isec;
3863 struct inode_security_struct *newisec;
3864
3865 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3866 if (err)
3867 return err;
3868
3869 newisec = SOCK_INODE(newsock)->i_security;
3870
3871 isec = SOCK_INODE(sock)->i_security;
3872 newisec->sclass = isec->sclass;
3873 newisec->sid = isec->sid;
3874 newisec->initialized = 1;
3875
3876 return 0;
3877}
3878
3879static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003880 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003882 int rc;
3883
3884 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3885 if (rc)
3886 return rc;
3887
3888 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889}
3890
3891static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3892 int size, int flags)
3893{
3894 return socket_has_perm(current, sock, SOCKET__READ);
3895}
3896
3897static int selinux_socket_getsockname(struct socket *sock)
3898{
3899 return socket_has_perm(current, sock, SOCKET__GETATTR);
3900}
3901
3902static int selinux_socket_getpeername(struct socket *sock)
3903{
3904 return socket_has_perm(current, sock, SOCKET__GETATTR);
3905}
3906
Eric Paris828dfe12008-04-17 13:17:49 -04003907static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908{
Paul Mooref8687af2006-10-30 15:22:15 -08003909 int err;
3910
3911 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3912 if (err)
3913 return err;
3914
3915 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916}
3917
3918static int selinux_socket_getsockopt(struct socket *sock, int level,
3919 int optname)
3920{
3921 return socket_has_perm(current, sock, SOCKET__GETOPT);
3922}
3923
3924static int selinux_socket_shutdown(struct socket *sock, int how)
3925{
3926 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
3927}
3928
3929static int selinux_socket_unix_stream_connect(struct socket *sock,
3930 struct socket *other,
3931 struct sock *newsk)
3932{
3933 struct sk_security_struct *ssec;
3934 struct inode_security_struct *isec;
3935 struct inode_security_struct *other_isec;
3936 struct avc_audit_data ad;
3937 int err;
3938
3939 err = secondary_ops->unix_stream_connect(sock, other, newsk);
3940 if (err)
3941 return err;
3942
3943 isec = SOCK_INODE(sock)->i_security;
3944 other_isec = SOCK_INODE(other)->i_security;
3945
Eric Paris828dfe12008-04-17 13:17:49 -04003946 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 ad.u.net.sk = other->sk;
3948
3949 err = avc_has_perm(isec->sid, other_isec->sid,
3950 isec->sclass,
3951 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
3952 if (err)
3953 return err;
3954
3955 /* connecting socket */
3956 ssec = sock->sk->sk_security;
3957 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04003958
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 /* server child socket */
3960 ssec = newsk->sk_security;
3961 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07003962 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
3963
3964 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965}
3966
3967static int selinux_socket_unix_may_send(struct socket *sock,
3968 struct socket *other)
3969{
3970 struct inode_security_struct *isec;
3971 struct inode_security_struct *other_isec;
3972 struct avc_audit_data ad;
3973 int err;
3974
3975 isec = SOCK_INODE(sock)->i_security;
3976 other_isec = SOCK_INODE(other)->i_security;
3977
Eric Paris828dfe12008-04-17 13:17:49 -04003978 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 ad.u.net.sk = other->sk;
3980
3981 err = avc_has_perm(isec->sid, other_isec->sid,
3982 isec->sclass, SOCKET__SENDTO, &ad);
3983 if (err)
3984 return err;
3985
3986 return 0;
3987}
3988
Paul Mooreeffad8d2008-01-29 08:49:27 -05003989static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
3990 u32 peer_sid,
3991 struct avc_audit_data *ad)
3992{
3993 int err;
3994 u32 if_sid;
3995 u32 node_sid;
3996
3997 err = sel_netif_sid(ifindex, &if_sid);
3998 if (err)
3999 return err;
4000 err = avc_has_perm(peer_sid, if_sid,
4001 SECCLASS_NETIF, NETIF__INGRESS, ad);
4002 if (err)
4003 return err;
4004
4005 err = sel_netnode_sid(addrp, family, &node_sid);
4006 if (err)
4007 return err;
4008 return avc_has_perm(peer_sid, node_sid,
4009 SECCLASS_NODE, NODE__RECVFROM, ad);
4010}
4011
Paul Moore220deb92008-01-29 08:38:23 -05004012static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4013 struct sk_buff *skb,
4014 struct avc_audit_data *ad,
4015 u16 family,
4016 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017{
Paul Moore220deb92008-01-29 08:38:23 -05004018 int err;
4019 struct sk_security_struct *sksec = sk->sk_security;
4020 u16 sk_class;
4021 u32 netif_perm, node_perm, recv_perm;
4022 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004023
Paul Moore220deb92008-01-29 08:38:23 -05004024 sk_sid = sksec->sid;
4025 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
Paul Moore220deb92008-01-29 08:38:23 -05004027 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 case SECCLASS_UDP_SOCKET:
4029 netif_perm = NETIF__UDP_RECV;
4030 node_perm = NODE__UDP_RECV;
4031 recv_perm = UDP_SOCKET__RECV_MSG;
4032 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 case SECCLASS_TCP_SOCKET:
4034 netif_perm = NETIF__TCP_RECV;
4035 node_perm = NODE__TCP_RECV;
4036 recv_perm = TCP_SOCKET__RECV_MSG;
4037 break;
James Morris2ee92d42006-11-13 16:09:01 -08004038 case SECCLASS_DCCP_SOCKET:
4039 netif_perm = NETIF__DCCP_RECV;
4040 node_perm = NODE__DCCP_RECV;
4041 recv_perm = DCCP_SOCKET__RECV_MSG;
4042 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 default:
4044 netif_perm = NETIF__RAWIP_RECV;
4045 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004046 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 break;
4048 }
4049
Paul Moore220deb92008-01-29 08:38:23 -05004050 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004052 return err;
4053 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4054 if (err)
4055 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004056
Paul Moore224dfbd2008-01-29 08:38:13 -05004057 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004059 return err;
4060 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004062 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
Paul Moore220deb92008-01-29 08:38:23 -05004064 if (!recv_perm)
4065 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004066 err = sel_netport_sid(sk->sk_protocol,
4067 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004068 if (unlikely(err)) {
4069 printk(KERN_WARNING
4070 "SELinux: failure in"
4071 " selinux_sock_rcv_skb_iptables_compat(),"
4072 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004073 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004074 }
Paul Moore220deb92008-01-29 08:38:23 -05004075 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4076}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077
Paul Moore220deb92008-01-29 08:38:23 -05004078static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004079 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004080{
4081 int err;
4082 struct sk_security_struct *sksec = sk->sk_security;
4083 u32 peer_sid;
4084 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004085 struct avc_audit_data ad;
4086 char *addrp;
4087
4088 AVC_AUDIT_DATA_INIT(&ad, NET);
4089 ad.u.net.netif = skb->iif;
4090 ad.u.net.family = family;
4091 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4092 if (err)
4093 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004094
4095 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004096 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004097 family, addrp);
4098 else
4099 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004100 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004101 if (err)
4102 return err;
4103
4104 if (selinux_policycap_netpeer) {
4105 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004107 return err;
4108 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004109 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004110 if (err)
4111 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004112 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004113 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004114 if (err)
4115 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004116 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004118
James Morris4e5ab4c2006-06-09 00:33:33 -07004119 return err;
4120}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004121
James Morris4e5ab4c2006-06-09 00:33:33 -07004122static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4123{
Paul Moore220deb92008-01-29 08:38:23 -05004124 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004125 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004126 u16 family = sk->sk_family;
4127 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004128 struct avc_audit_data ad;
4129 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004130 u8 secmark_active;
4131 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004132
James Morris4e5ab4c2006-06-09 00:33:33 -07004133 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004134 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004135
4136 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004137 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004138 family = PF_INET;
4139
Paul Moored8395c82008-10-10 10:16:30 -04004140 /* If any sort of compatibility mode is enabled then handoff processing
4141 * to the selinux_sock_rcv_skb_compat() function to deal with the
4142 * special handling. We do this in an attempt to keep this function
4143 * as fast and as clean as possible. */
4144 if (selinux_compat_net || !selinux_policycap_netpeer)
4145 return selinux_sock_rcv_skb_compat(sk, skb, family);
4146
4147 secmark_active = selinux_secmark_enabled();
4148 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4149 if (!secmark_active && !peerlbl_active)
4150 return 0;
4151
James Morris4e5ab4c2006-06-09 00:33:33 -07004152 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004153 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004154 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004155 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004156 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004157 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004158
Paul Moored8395c82008-10-10 10:16:30 -04004159 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004160 u32 peer_sid;
4161
4162 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4163 if (err)
4164 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004165 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4166 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004167 if (err) {
4168 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004169 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004170 }
Paul Moored621d352008-01-29 08:43:36 -05004171 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4172 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004173 if (err)
4174 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004175 }
4176
Paul Moored8395c82008-10-10 10:16:30 -04004177 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004178 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4179 PACKET__RECV, &ad);
4180 if (err)
4181 return err;
4182 }
4183
Paul Moored621d352008-01-29 08:43:36 -05004184 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185}
4186
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004187static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4188 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189{
4190 int err = 0;
4191 char *scontext;
4192 u32 scontext_len;
4193 struct sk_security_struct *ssec;
4194 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004195 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
4197 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004198
Paul Moore3de4bab2006-11-17 17:38:54 -05004199 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4200 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004201 ssec = sock->sk->sk_security;
4202 peer_sid = ssec->peer_sid;
4203 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004204 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 err = -ENOPROTOOPT;
4206 goto out;
4207 }
4208
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004209 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4210
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 if (err)
4212 goto out;
4213
4214 if (scontext_len > len) {
4215 err = -ERANGE;
4216 goto out_len;
4217 }
4218
4219 if (copy_to_user(optval, scontext, scontext_len))
4220 err = -EFAULT;
4221
4222out_len:
4223 if (put_user(scontext_len, optlen))
4224 err = -EFAULT;
4225
4226 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004227out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 return err;
4229}
4230
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004231static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004232{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004233 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004234 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004235
Paul Mooreaa862902008-10-10 10:16:29 -04004236 if (skb && skb->protocol == htons(ETH_P_IP))
4237 family = PF_INET;
4238 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4239 family = PF_INET6;
4240 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004241 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004242 else
4243 goto out;
4244
4245 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004246 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004247 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004248 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004249
Paul Moore75e22912008-01-29 08:38:04 -05004250out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004251 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004252 if (peer_secid == SECSID_NULL)
4253 return -EINVAL;
4254 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004255}
4256
Al Viro7d877f32005-10-21 03:20:43 -04004257static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258{
4259 return sk_alloc_security(sk, family, priority);
4260}
4261
4262static void selinux_sk_free_security(struct sock *sk)
4263{
4264 sk_free_security(sk);
4265}
4266
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004267static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4268{
4269 struct sk_security_struct *ssec = sk->sk_security;
4270 struct sk_security_struct *newssec = newsk->sk_security;
4271
4272 newssec->sid = ssec->sid;
4273 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004274 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004275
Paul Mooref74af6e2008-02-25 11:40:33 -05004276 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004277}
4278
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004279static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004280{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004281 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004282 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004283 else {
4284 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004285
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004286 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004287 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004288}
4289
Eric Paris828dfe12008-04-17 13:17:49 -04004290static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004291{
4292 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4293 struct sk_security_struct *sksec = sk->sk_security;
4294
David Woodhouse2148ccc2006-09-29 15:50:25 -07004295 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4296 sk->sk_family == PF_UNIX)
4297 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004298 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004299}
4300
Adrian Bunk9a673e52006-08-15 00:03:53 -07004301static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4302 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004303{
4304 struct sk_security_struct *sksec = sk->sk_security;
4305 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004306 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004307 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004308 u32 peersid;
4309
Paul Mooreaa862902008-10-10 10:16:29 -04004310 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4311 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4312 family = PF_INET;
4313
4314 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004315 if (err)
4316 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004317 if (peersid == SECSID_NULL) {
4318 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004319 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004320 return 0;
4321 }
4322
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004323 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4324 if (err)
4325 return err;
4326
4327 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004328 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004329 return 0;
4330}
4331
Adrian Bunk9a673e52006-08-15 00:03:53 -07004332static void selinux_inet_csk_clone(struct sock *newsk,
4333 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004334{
4335 struct sk_security_struct *newsksec = newsk->sk_security;
4336
4337 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004338 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004339 /* NOTE: Ideally, we should also get the isec->sid for the
4340 new socket in sync, but we don't have the isec available yet.
4341 So we will wait until sock_graft to do it, by which
4342 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004343
Paul Moore9f2ad662006-11-17 17:38:53 -05004344 /* We don't need to take any sort of lock here as we are the only
4345 * thread with access to newsksec */
4346 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004347}
4348
Paul Moore014ab192008-10-10 10:16:33 -04004349static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004350{
Paul Mooreaa862902008-10-10 10:16:29 -04004351 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004352 struct sk_security_struct *sksec = sk->sk_security;
4353
Paul Mooreaa862902008-10-10 10:16:29 -04004354 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4355 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4356 family = PF_INET;
4357
4358 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004359
4360 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004361}
4362
Adrian Bunk9a673e52006-08-15 00:03:53 -07004363static void selinux_req_classify_flow(const struct request_sock *req,
4364 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004365{
4366 fl->secid = req->secid;
4367}
4368
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4370{
4371 int err = 0;
4372 u32 perm;
4373 struct nlmsghdr *nlh;
4374 struct socket *sock = sk->sk_socket;
4375 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004376
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 if (skb->len < NLMSG_SPACE(0)) {
4378 err = -EINVAL;
4379 goto out;
4380 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004381 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004382
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4384 if (err) {
4385 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004386 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 "SELinux: unrecognized netlink message"
4388 " type=%hu for sclass=%hu\n",
4389 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004390 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 err = 0;
4392 }
4393
4394 /* Ignore */
4395 if (err == -ENOENT)
4396 err = 0;
4397 goto out;
4398 }
4399
4400 err = socket_has_perm(current, sock, perm);
4401out:
4402 return err;
4403}
4404
4405#ifdef CONFIG_NETFILTER
4406
Paul Mooreeffad8d2008-01-29 08:49:27 -05004407static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4408 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409{
Paul Mooredfaebe92008-10-10 10:16:31 -04004410 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004411 char *addrp;
4412 u32 peer_sid;
4413 struct avc_audit_data ad;
4414 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004415 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004416 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004417
Paul Mooreeffad8d2008-01-29 08:49:27 -05004418 if (!selinux_policycap_netpeer)
4419 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004420
Paul Mooreeffad8d2008-01-29 08:49:27 -05004421 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004422 netlbl_active = netlbl_enabled();
4423 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004424 if (!secmark_active && !peerlbl_active)
4425 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004426
Paul Moored8395c82008-10-10 10:16:30 -04004427 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4428 return NF_DROP;
4429
Paul Mooreeffad8d2008-01-29 08:49:27 -05004430 AVC_AUDIT_DATA_INIT(&ad, NET);
4431 ad.u.net.netif = ifindex;
4432 ad.u.net.family = family;
4433 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4434 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Paul Mooredfaebe92008-10-10 10:16:31 -04004436 if (peerlbl_active) {
4437 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4438 peer_sid, &ad);
4439 if (err) {
4440 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004441 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004442 }
4443 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004444
4445 if (secmark_active)
4446 if (avc_has_perm(peer_sid, skb->secmark,
4447 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4448 return NF_DROP;
4449
Paul Moore948bf852008-10-10 10:16:32 -04004450 if (netlbl_active)
4451 /* we do this in the FORWARD path and not the POST_ROUTING
4452 * path because we want to make sure we apply the necessary
4453 * labeling before IPsec is applied so we can leverage AH
4454 * protection */
4455 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4456 return NF_DROP;
4457
Paul Mooreeffad8d2008-01-29 08:49:27 -05004458 return NF_ACCEPT;
4459}
4460
4461static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4462 struct sk_buff *skb,
4463 const struct net_device *in,
4464 const struct net_device *out,
4465 int (*okfn)(struct sk_buff *))
4466{
4467 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4468}
4469
4470#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4471static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4472 struct sk_buff *skb,
4473 const struct net_device *in,
4474 const struct net_device *out,
4475 int (*okfn)(struct sk_buff *))
4476{
4477 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4478}
4479#endif /* IPV6 */
4480
Paul Moore948bf852008-10-10 10:16:32 -04004481static unsigned int selinux_ip_output(struct sk_buff *skb,
4482 u16 family)
4483{
4484 u32 sid;
4485
4486 if (!netlbl_enabled())
4487 return NF_ACCEPT;
4488
4489 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4490 * because we want to make sure we apply the necessary labeling
4491 * before IPsec is applied so we can leverage AH protection */
4492 if (skb->sk) {
4493 struct sk_security_struct *sksec = skb->sk->sk_security;
4494 sid = sksec->sid;
4495 } else
4496 sid = SECINITSID_KERNEL;
4497 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4498 return NF_DROP;
4499
4500 return NF_ACCEPT;
4501}
4502
4503static unsigned int selinux_ipv4_output(unsigned int hooknum,
4504 struct sk_buff *skb,
4505 const struct net_device *in,
4506 const struct net_device *out,
4507 int (*okfn)(struct sk_buff *))
4508{
4509 return selinux_ip_output(skb, PF_INET);
4510}
4511
Paul Mooreeffad8d2008-01-29 08:49:27 -05004512static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4513 int ifindex,
4514 struct avc_audit_data *ad,
4515 u16 family, char *addrp)
4516{
4517 int err;
4518 struct sk_security_struct *sksec = sk->sk_security;
4519 u16 sk_class;
4520 u32 netif_perm, node_perm, send_perm;
4521 u32 port_sid, node_sid, if_sid, sk_sid;
4522
4523 sk_sid = sksec->sid;
4524 sk_class = sksec->sclass;
4525
4526 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 case SECCLASS_UDP_SOCKET:
4528 netif_perm = NETIF__UDP_SEND;
4529 node_perm = NODE__UDP_SEND;
4530 send_perm = UDP_SOCKET__SEND_MSG;
4531 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 case SECCLASS_TCP_SOCKET:
4533 netif_perm = NETIF__TCP_SEND;
4534 node_perm = NODE__TCP_SEND;
4535 send_perm = TCP_SOCKET__SEND_MSG;
4536 break;
James Morris2ee92d42006-11-13 16:09:01 -08004537 case SECCLASS_DCCP_SOCKET:
4538 netif_perm = NETIF__DCCP_SEND;
4539 node_perm = NODE__DCCP_SEND;
4540 send_perm = DCCP_SOCKET__SEND_MSG;
4541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 default:
4543 netif_perm = NETIF__RAWIP_SEND;
4544 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004545 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 break;
4547 }
4548
Paul Mooreeffad8d2008-01-29 08:49:27 -05004549 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004550 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004551 return err;
4552 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4553 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004554
Paul Moore224dfbd2008-01-29 08:38:13 -05004555 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004556 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004557 return err;
4558 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004559 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004560 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561
Paul Mooreeffad8d2008-01-29 08:49:27 -05004562 if (send_perm != 0)
4563 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
Paul Moore3e112172008-04-10 10:48:14 -04004565 err = sel_netport_sid(sk->sk_protocol,
4566 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004567 if (unlikely(err)) {
4568 printk(KERN_WARNING
4569 "SELinux: failure in"
4570 " selinux_ip_postroute_iptables_compat(),"
4571 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004572 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004573 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004574 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004575}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576
Paul Mooreeffad8d2008-01-29 08:49:27 -05004577static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4578 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004579 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004580{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004581 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004582 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004583 struct avc_audit_data ad;
4584 char *addrp;
4585 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004586
Paul Mooreeffad8d2008-01-29 08:49:27 -05004587 if (sk == NULL)
4588 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004589 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004590
Paul Moored8395c82008-10-10 10:16:30 -04004591 AVC_AUDIT_DATA_INIT(&ad, NET);
4592 ad.u.net.netif = ifindex;
4593 ad.u.net.family = family;
4594 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4595 return NF_DROP;
4596
Paul Mooreeffad8d2008-01-29 08:49:27 -05004597 if (selinux_compat_net) {
4598 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004599 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004600 return NF_DROP;
4601 } else {
4602 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004603 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004604 return NF_DROP;
4605 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004606
Paul Mooreeffad8d2008-01-29 08:49:27 -05004607 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004608 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004609 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004610
Paul Mooreeffad8d2008-01-29 08:49:27 -05004611 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612}
4613
Paul Mooreeffad8d2008-01-29 08:49:27 -05004614static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4615 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004617 u32 secmark_perm;
4618 u32 peer_sid;
4619 struct sock *sk;
4620 struct avc_audit_data ad;
4621 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004622 u8 secmark_active;
4623 u8 peerlbl_active;
4624
Paul Mooreeffad8d2008-01-29 08:49:27 -05004625 /* If any sort of compatibility mode is enabled then handoff processing
4626 * to the selinux_ip_postroute_compat() function to deal with the
4627 * special handling. We do this in an attempt to keep this function
4628 * as fast and as clean as possible. */
4629 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004630 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004631
4632 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4633 * packet transformation so allow the packet to pass without any checks
4634 * since we'll have another chance to perform access control checks
4635 * when the packet is on it's final way out.
4636 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4637 * is NULL, in this case go ahead and apply access control. */
4638 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4639 return NF_ACCEPT;
4640
4641 secmark_active = selinux_secmark_enabled();
4642 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4643 if (!secmark_active && !peerlbl_active)
4644 return NF_ACCEPT;
4645
Paul Moored8395c82008-10-10 10:16:30 -04004646 /* if the packet is being forwarded then get the peer label from the
4647 * packet itself; otherwise check to see if it is from a local
4648 * application or the kernel, if from an application get the peer label
4649 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004650 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004651 if (sk == NULL) {
4652 switch (family) {
4653 case PF_INET:
4654 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4655 secmark_perm = PACKET__FORWARD_OUT;
4656 else
4657 secmark_perm = PACKET__SEND;
4658 break;
4659 case PF_INET6:
4660 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4661 secmark_perm = PACKET__FORWARD_OUT;
4662 else
4663 secmark_perm = PACKET__SEND;
4664 break;
4665 default:
4666 return NF_DROP;
4667 }
4668 if (secmark_perm == PACKET__FORWARD_OUT) {
4669 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4670 return NF_DROP;
4671 } else
4672 peer_sid = SECINITSID_KERNEL;
4673 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004674 struct sk_security_struct *sksec = sk->sk_security;
4675 peer_sid = sksec->sid;
4676 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004677 }
4678
Paul Moored8395c82008-10-10 10:16:30 -04004679 AVC_AUDIT_DATA_INIT(&ad, NET);
4680 ad.u.net.netif = ifindex;
4681 ad.u.net.family = family;
4682 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4683 return NF_DROP;
4684
Paul Mooreeffad8d2008-01-29 08:49:27 -05004685 if (secmark_active)
4686 if (avc_has_perm(peer_sid, skb->secmark,
4687 SECCLASS_PACKET, secmark_perm, &ad))
4688 return NF_DROP;
4689
4690 if (peerlbl_active) {
4691 u32 if_sid;
4692 u32 node_sid;
4693
4694 if (sel_netif_sid(ifindex, &if_sid))
4695 return NF_DROP;
4696 if (avc_has_perm(peer_sid, if_sid,
4697 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4698 return NF_DROP;
4699
4700 if (sel_netnode_sid(addrp, family, &node_sid))
4701 return NF_DROP;
4702 if (avc_has_perm(peer_sid, node_sid,
4703 SECCLASS_NODE, NODE__SENDTO, &ad))
4704 return NF_DROP;
4705 }
4706
4707 return NF_ACCEPT;
4708}
4709
4710static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4711 struct sk_buff *skb,
4712 const struct net_device *in,
4713 const struct net_device *out,
4714 int (*okfn)(struct sk_buff *))
4715{
4716 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717}
4718
4719#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004720static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4721 struct sk_buff *skb,
4722 const struct net_device *in,
4723 const struct net_device *out,
4724 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004726 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728#endif /* IPV6 */
4729
4730#endif /* CONFIG_NETFILTER */
4731
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4733{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 int err;
4735
4736 err = secondary_ops->netlink_send(sk, skb);
4737 if (err)
4738 return err;
4739
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4741 err = selinux_nlmsg_perm(sk, skb);
4742
4743 return err;
4744}
4745
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004746static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004748 int err;
4749 struct avc_audit_data ad;
4750
4751 err = secondary_ops->netlink_recv(skb, capability);
4752 if (err)
4753 return err;
4754
4755 AVC_AUDIT_DATA_INIT(&ad, CAP);
4756 ad.u.cap = capability;
4757
4758 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004759 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760}
4761
4762static int ipc_alloc_security(struct task_struct *task,
4763 struct kern_ipc_perm *perm,
4764 u16 sclass)
4765{
David Howellsb6dff3e2008-11-14 10:39:16 +11004766 struct task_security_struct *tsec = task->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 struct ipc_security_struct *isec;
4768
James Morris89d155e2005-10-30 14:59:21 -08004769 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 if (!isec)
4771 return -ENOMEM;
4772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 isec->sclass = sclass;
Stephen Smalley9ac49d22006-02-01 03:05:56 -08004774 isec->sid = tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 perm->security = isec;
4776
4777 return 0;
4778}
4779
4780static void ipc_free_security(struct kern_ipc_perm *perm)
4781{
4782 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 perm->security = NULL;
4784 kfree(isec);
4785}
4786
4787static int msg_msg_alloc_security(struct msg_msg *msg)
4788{
4789 struct msg_security_struct *msec;
4790
James Morris89d155e2005-10-30 14:59:21 -08004791 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 if (!msec)
4793 return -ENOMEM;
4794
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 msec->sid = SECINITSID_UNLABELED;
4796 msg->security = msec;
4797
4798 return 0;
4799}
4800
4801static void msg_msg_free_security(struct msg_msg *msg)
4802{
4803 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804
4805 msg->security = NULL;
4806 kfree(msec);
4807}
4808
4809static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004810 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811{
4812 struct task_security_struct *tsec;
4813 struct ipc_security_struct *isec;
4814 struct avc_audit_data ad;
4815
David Howellsb6dff3e2008-11-14 10:39:16 +11004816 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 isec = ipc_perms->security;
4818
4819 AVC_AUDIT_DATA_INIT(&ad, IPC);
4820 ad.u.ipc_id = ipc_perms->key;
4821
Stephen Smalley6af963f2005-05-01 08:58:39 -07004822 return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823}
4824
4825static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4826{
4827 return msg_msg_alloc_security(msg);
4828}
4829
4830static void selinux_msg_msg_free_security(struct msg_msg *msg)
4831{
4832 msg_msg_free_security(msg);
4833}
4834
4835/* message queue security operations */
4836static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4837{
4838 struct task_security_struct *tsec;
4839 struct ipc_security_struct *isec;
4840 struct avc_audit_data ad;
4841 int rc;
4842
4843 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4844 if (rc)
4845 return rc;
4846
David Howellsb6dff3e2008-11-14 10:39:16 +11004847 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 isec = msq->q_perm.security;
4849
4850 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004851 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
4853 rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
4854 MSGQ__CREATE, &ad);
4855 if (rc) {
4856 ipc_free_security(&msq->q_perm);
4857 return rc;
4858 }
4859 return 0;
4860}
4861
4862static void selinux_msg_queue_free_security(struct msg_queue *msq)
4863{
4864 ipc_free_security(&msq->q_perm);
4865}
4866
4867static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4868{
4869 struct task_security_struct *tsec;
4870 struct ipc_security_struct *isec;
4871 struct avc_audit_data ad;
4872
David Howellsb6dff3e2008-11-14 10:39:16 +11004873 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 isec = msq->q_perm.security;
4875
4876 AVC_AUDIT_DATA_INIT(&ad, IPC);
4877 ad.u.ipc_id = msq->q_perm.key;
4878
4879 return avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
4880 MSGQ__ASSOCIATE, &ad);
4881}
4882
4883static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4884{
4885 int err;
4886 int perms;
4887
Eric Paris828dfe12008-04-17 13:17:49 -04004888 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 case IPC_INFO:
4890 case MSG_INFO:
4891 /* No specific object, just general system-wide information. */
4892 return task_has_system(current, SYSTEM__IPC_INFO);
4893 case IPC_STAT:
4894 case MSG_STAT:
4895 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4896 break;
4897 case IPC_SET:
4898 perms = MSGQ__SETATTR;
4899 break;
4900 case IPC_RMID:
4901 perms = MSGQ__DESTROY;
4902 break;
4903 default:
4904 return 0;
4905 }
4906
Stephen Smalley6af963f2005-05-01 08:58:39 -07004907 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 return err;
4909}
4910
4911static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4912{
4913 struct task_security_struct *tsec;
4914 struct ipc_security_struct *isec;
4915 struct msg_security_struct *msec;
4916 struct avc_audit_data ad;
4917 int rc;
4918
David Howellsb6dff3e2008-11-14 10:39:16 +11004919 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 isec = msq->q_perm.security;
4921 msec = msg->security;
4922
4923 /*
4924 * First time through, need to assign label to the message
4925 */
4926 if (msec->sid == SECINITSID_UNLABELED) {
4927 /*
4928 * Compute new sid based on current process and
4929 * message queue this message will be stored in
4930 */
4931 rc = security_transition_sid(tsec->sid,
4932 isec->sid,
4933 SECCLASS_MSG,
4934 &msec->sid);
4935 if (rc)
4936 return rc;
4937 }
4938
4939 AVC_AUDIT_DATA_INIT(&ad, IPC);
4940 ad.u.ipc_id = msq->q_perm.key;
4941
4942 /* Can this process write to the queue? */
4943 rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
4944 MSGQ__WRITE, &ad);
4945 if (!rc)
4946 /* Can this process send the message */
4947 rc = avc_has_perm(tsec->sid, msec->sid,
4948 SECCLASS_MSG, MSG__SEND, &ad);
4949 if (!rc)
4950 /* Can the message be put in the queue? */
4951 rc = avc_has_perm(msec->sid, isec->sid,
4952 SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad);
4953
4954 return rc;
4955}
4956
4957static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
4958 struct task_struct *target,
4959 long type, int mode)
4960{
4961 struct task_security_struct *tsec;
4962 struct ipc_security_struct *isec;
4963 struct msg_security_struct *msec;
4964 struct avc_audit_data ad;
4965 int rc;
4966
David Howellsb6dff3e2008-11-14 10:39:16 +11004967 tsec = target->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 isec = msq->q_perm.security;
4969 msec = msg->security;
4970
4971 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004972 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973
4974 rc = avc_has_perm(tsec->sid, isec->sid,
4975 SECCLASS_MSGQ, MSGQ__READ, &ad);
4976 if (!rc)
4977 rc = avc_has_perm(tsec->sid, msec->sid,
4978 SECCLASS_MSG, MSG__RECEIVE, &ad);
4979 return rc;
4980}
4981
4982/* Shared Memory security operations */
4983static int selinux_shm_alloc_security(struct shmid_kernel *shp)
4984{
4985 struct task_security_struct *tsec;
4986 struct ipc_security_struct *isec;
4987 struct avc_audit_data ad;
4988 int rc;
4989
4990 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
4991 if (rc)
4992 return rc;
4993
David Howellsb6dff3e2008-11-14 10:39:16 +11004994 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 isec = shp->shm_perm.security;
4996
4997 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004998 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
5000 rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
5001 SHM__CREATE, &ad);
5002 if (rc) {
5003 ipc_free_security(&shp->shm_perm);
5004 return rc;
5005 }
5006 return 0;
5007}
5008
5009static void selinux_shm_free_security(struct shmid_kernel *shp)
5010{
5011 ipc_free_security(&shp->shm_perm);
5012}
5013
5014static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5015{
5016 struct task_security_struct *tsec;
5017 struct ipc_security_struct *isec;
5018 struct avc_audit_data ad;
5019
David Howellsb6dff3e2008-11-14 10:39:16 +11005020 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 isec = shp->shm_perm.security;
5022
5023 AVC_AUDIT_DATA_INIT(&ad, IPC);
5024 ad.u.ipc_id = shp->shm_perm.key;
5025
5026 return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
5027 SHM__ASSOCIATE, &ad);
5028}
5029
5030/* Note, at this point, shp is locked down */
5031static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5032{
5033 int perms;
5034 int err;
5035
Eric Paris828dfe12008-04-17 13:17:49 -04005036 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 case IPC_INFO:
5038 case SHM_INFO:
5039 /* No specific object, just general system-wide information. */
5040 return task_has_system(current, SYSTEM__IPC_INFO);
5041 case IPC_STAT:
5042 case SHM_STAT:
5043 perms = SHM__GETATTR | SHM__ASSOCIATE;
5044 break;
5045 case IPC_SET:
5046 perms = SHM__SETATTR;
5047 break;
5048 case SHM_LOCK:
5049 case SHM_UNLOCK:
5050 perms = SHM__LOCK;
5051 break;
5052 case IPC_RMID:
5053 perms = SHM__DESTROY;
5054 break;
5055 default:
5056 return 0;
5057 }
5058
Stephen Smalley6af963f2005-05-01 08:58:39 -07005059 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 return err;
5061}
5062
5063static int selinux_shm_shmat(struct shmid_kernel *shp,
5064 char __user *shmaddr, int shmflg)
5065{
5066 u32 perms;
5067 int rc;
5068
5069 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5070 if (rc)
5071 return rc;
5072
5073 if (shmflg & SHM_RDONLY)
5074 perms = SHM__READ;
5075 else
5076 perms = SHM__READ | SHM__WRITE;
5077
Stephen Smalley6af963f2005-05-01 08:58:39 -07005078 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079}
5080
5081/* Semaphore security operations */
5082static int selinux_sem_alloc_security(struct sem_array *sma)
5083{
5084 struct task_security_struct *tsec;
5085 struct ipc_security_struct *isec;
5086 struct avc_audit_data ad;
5087 int rc;
5088
5089 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5090 if (rc)
5091 return rc;
5092
David Howellsb6dff3e2008-11-14 10:39:16 +11005093 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 isec = sma->sem_perm.security;
5095
5096 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005097 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098
5099 rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
5100 SEM__CREATE, &ad);
5101 if (rc) {
5102 ipc_free_security(&sma->sem_perm);
5103 return rc;
5104 }
5105 return 0;
5106}
5107
5108static void selinux_sem_free_security(struct sem_array *sma)
5109{
5110 ipc_free_security(&sma->sem_perm);
5111}
5112
5113static int selinux_sem_associate(struct sem_array *sma, int semflg)
5114{
5115 struct task_security_struct *tsec;
5116 struct ipc_security_struct *isec;
5117 struct avc_audit_data ad;
5118
David Howellsb6dff3e2008-11-14 10:39:16 +11005119 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 isec = sma->sem_perm.security;
5121
5122 AVC_AUDIT_DATA_INIT(&ad, IPC);
5123 ad.u.ipc_id = sma->sem_perm.key;
5124
5125 return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
5126 SEM__ASSOCIATE, &ad);
5127}
5128
5129/* Note, at this point, sma is locked down */
5130static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5131{
5132 int err;
5133 u32 perms;
5134
Eric Paris828dfe12008-04-17 13:17:49 -04005135 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 case IPC_INFO:
5137 case SEM_INFO:
5138 /* No specific object, just general system-wide information. */
5139 return task_has_system(current, SYSTEM__IPC_INFO);
5140 case GETPID:
5141 case GETNCNT:
5142 case GETZCNT:
5143 perms = SEM__GETATTR;
5144 break;
5145 case GETVAL:
5146 case GETALL:
5147 perms = SEM__READ;
5148 break;
5149 case SETVAL:
5150 case SETALL:
5151 perms = SEM__WRITE;
5152 break;
5153 case IPC_RMID:
5154 perms = SEM__DESTROY;
5155 break;
5156 case IPC_SET:
5157 perms = SEM__SETATTR;
5158 break;
5159 case IPC_STAT:
5160 case SEM_STAT:
5161 perms = SEM__GETATTR | SEM__ASSOCIATE;
5162 break;
5163 default:
5164 return 0;
5165 }
5166
Stephen Smalley6af963f2005-05-01 08:58:39 -07005167 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 return err;
5169}
5170
5171static int selinux_sem_semop(struct sem_array *sma,
5172 struct sembuf *sops, unsigned nsops, int alter)
5173{
5174 u32 perms;
5175
5176 if (alter)
5177 perms = SEM__READ | SEM__WRITE;
5178 else
5179 perms = SEM__READ;
5180
Stephen Smalley6af963f2005-05-01 08:58:39 -07005181 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182}
5183
5184static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5185{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 u32 av = 0;
5187
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 av = 0;
5189 if (flag & S_IRUGO)
5190 av |= IPC__UNIX_READ;
5191 if (flag & S_IWUGO)
5192 av |= IPC__UNIX_WRITE;
5193
5194 if (av == 0)
5195 return 0;
5196
Stephen Smalley6af963f2005-05-01 08:58:39 -07005197 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198}
5199
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005200static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5201{
5202 struct ipc_security_struct *isec = ipcp->security;
5203 *secid = isec->sid;
5204}
5205
Eric Paris828dfe12008-04-17 13:17:49 -04005206static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207{
5208 if (inode)
5209 inode_doinit_with_dentry(inode, dentry);
5210}
5211
5212static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005213 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214{
5215 struct task_security_struct *tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005216 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005218 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219
5220 if (current != p) {
5221 error = task_has_perm(current, p, PROCESS__GETATTR);
5222 if (error)
5223 return error;
5224 }
5225
David Howellsb6dff3e2008-11-14 10:39:16 +11005226 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227
5228 if (!strcmp(name, "current"))
5229 sid = tsec->sid;
5230 else if (!strcmp(name, "prev"))
5231 sid = tsec->osid;
5232 else if (!strcmp(name, "exec"))
5233 sid = tsec->exec_sid;
5234 else if (!strcmp(name, "fscreate"))
5235 sid = tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005236 else if (!strcmp(name, "keycreate"))
5237 sid = tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005238 else if (!strcmp(name, "sockcreate"))
5239 sid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 else
5241 return -EINVAL;
5242
5243 if (!sid)
5244 return 0;
5245
Al Viro04ff9702007-03-12 16:17:58 +00005246 error = security_sid_to_context(sid, value, &len);
5247 if (error)
5248 return error;
5249 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250}
5251
5252static int selinux_setprocattr(struct task_struct *p,
5253 char *name, void *value, size_t size)
5254{
5255 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005256 struct task_struct *tracer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 u32 sid = 0;
5258 int error;
5259 char *str = value;
5260
5261 if (current != p) {
5262 /* SELinux only allows a process to change its own
5263 security attributes. */
5264 return -EACCES;
5265 }
5266
5267 /*
5268 * Basic control over ability to set these attributes at all.
5269 * current == p, but we'll pass them separately in case the
5270 * above restriction is ever removed.
5271 */
5272 if (!strcmp(name, "exec"))
5273 error = task_has_perm(current, p, PROCESS__SETEXEC);
5274 else if (!strcmp(name, "fscreate"))
5275 error = task_has_perm(current, p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005276 else if (!strcmp(name, "keycreate"))
5277 error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005278 else if (!strcmp(name, "sockcreate"))
5279 error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 else if (!strcmp(name, "current"))
5281 error = task_has_perm(current, p, PROCESS__SETCURRENT);
5282 else
5283 error = -EINVAL;
5284 if (error)
5285 return error;
5286
5287 /* Obtain a SID for the context, if one was specified. */
5288 if (size && str[1] && str[1] != '\n') {
5289 if (str[size-1] == '\n') {
5290 str[size-1] = 0;
5291 size--;
5292 }
5293 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005294 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5295 if (!capable(CAP_MAC_ADMIN))
5296 return error;
5297 error = security_context_to_sid_force(value, size,
5298 &sid);
5299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 if (error)
5301 return error;
5302 }
5303
5304 /* Permission checking based on the specified context is
5305 performed during the actual operation (execve,
5306 open/mkdir/...), when we know the full context of the
5307 operation. See selinux_bprm_set_security for the execve
5308 checks and may_create for the file creation checks. The
5309 operation will then fail if the context is not permitted. */
David Howellsb6dff3e2008-11-14 10:39:16 +11005310 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 if (!strcmp(name, "exec"))
5312 tsec->exec_sid = sid;
5313 else if (!strcmp(name, "fscreate"))
5314 tsec->create_sid = sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005315 else if (!strcmp(name, "keycreate")) {
5316 error = may_create_key(sid, p);
5317 if (error)
5318 return error;
5319 tsec->keycreate_sid = sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005320 } else if (!strcmp(name, "sockcreate"))
5321 tsec->sockcreate_sid = sid;
5322 else if (!strcmp(name, "current")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 struct av_decision avd;
5324
5325 if (sid == 0)
5326 return -EINVAL;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005327 /*
5328 * SELinux allows to change context in the following case only.
5329 * - Single threaded processes.
5330 * - Multi threaded processes intend to change its context into
5331 * more restricted domain (defined by TYPEBOUNDS statement).
5332 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 if (atomic_read(&p->mm->mm_users) != 1) {
5334 struct task_struct *g, *t;
5335 struct mm_struct *mm = p->mm;
5336 read_lock(&tasklist_lock);
James Morris2baf06d2008-06-12 01:42:35 +10005337 do_each_thread(g, t) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 if (t->mm == mm && t != p) {
5339 read_unlock(&tasklist_lock);
KaiGai Koheid9250de2008-08-28 16:35:57 +09005340 error = security_bounded_transition(tsec->sid, sid);
5341 if (!error)
5342 goto boundary_ok;
5343
5344 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 }
James Morris2baf06d2008-06-12 01:42:35 +10005346 } while_each_thread(g, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 read_unlock(&tasklist_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04005348 }
KaiGai Koheid9250de2008-08-28 16:35:57 +09005349boundary_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350
5351 /* Check permissions for the transition. */
5352 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005353 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 if (error)
5355 return error;
5356
5357 /* Check for ptracing, and update the task SID if ok.
5358 Otherwise, leave SID unchanged and fail. */
5359 task_lock(p);
Roland McGrath03563572008-03-26 15:46:39 -07005360 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07005361 tracer = tracehook_tracer_task(p);
Roland McGrath03563572008-03-26 15:46:39 -07005362 if (tracer != NULL) {
David Howellsb6dff3e2008-11-14 10:39:16 +11005363 struct task_security_struct *ptsec =
5364 tracer->cred->security;
Roland McGrath03563572008-03-26 15:46:39 -07005365 u32 ptsid = ptsec->sid;
5366 rcu_read_unlock();
5367 error = avc_has_perm_noaudit(ptsid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 SECCLASS_PROCESS,
Stephen Smalley2c3c05d2007-06-07 15:34:10 -04005369 PROCESS__PTRACE, 0, &avd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 if (!error)
5371 tsec->sid = sid;
5372 task_unlock(p);
Roland McGrath03563572008-03-26 15:46:39 -07005373 avc_audit(ptsid, sid, SECCLASS_PROCESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 PROCESS__PTRACE, &avd, error, NULL);
5375 if (error)
5376 return error;
5377 } else {
Roland McGrath03563572008-03-26 15:46:39 -07005378 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 tsec->sid = sid;
5380 task_unlock(p);
5381 }
Eric Paris828dfe12008-04-17 13:17:49 -04005382 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 return -EINVAL;
5384
5385 return size;
5386}
5387
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005388static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5389{
5390 return security_sid_to_context(secid, secdata, seclen);
5391}
5392
David Howells7bf570d2008-04-29 20:52:51 +01005393static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005394{
5395 return security_context_to_sid(secdata, seclen, secid);
5396}
5397
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005398static void selinux_release_secctx(char *secdata, u32 seclen)
5399{
Paul Moore088999e2007-08-01 11:12:58 -04005400 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005401}
5402
Michael LeMayd7200242006-06-22 14:47:17 -07005403#ifdef CONFIG_KEYS
5404
David Howells7e047ef2006-06-26 00:24:50 -07005405static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
5406 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005407{
David Howellsb6dff3e2008-11-14 10:39:16 +11005408 struct task_security_struct *tsec = tsk->cred->security;
Michael LeMayd7200242006-06-22 14:47:17 -07005409 struct key_security_struct *ksec;
5410
5411 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5412 if (!ksec)
5413 return -ENOMEM;
5414
Michael LeMay4eb582c2006-06-26 00:24:57 -07005415 if (tsec->keycreate_sid)
5416 ksec->sid = tsec->keycreate_sid;
5417 else
5418 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005419 k->security = ksec;
5420
5421 return 0;
5422}
5423
5424static void selinux_key_free(struct key *k)
5425{
5426 struct key_security_struct *ksec = k->security;
5427
5428 k->security = NULL;
5429 kfree(ksec);
5430}
5431
5432static int selinux_key_permission(key_ref_t key_ref,
5433 struct task_struct *ctx,
5434 key_perm_t perm)
5435{
5436 struct key *key;
5437 struct task_security_struct *tsec;
5438 struct key_security_struct *ksec;
5439
5440 key = key_ref_to_ptr(key_ref);
5441
David Howellsb6dff3e2008-11-14 10:39:16 +11005442 tsec = ctx->cred->security;
Michael LeMayd7200242006-06-22 14:47:17 -07005443 ksec = key->security;
5444
5445 /* if no specific permissions are requested, we skip the
5446 permission check. No serious, additional covert channels
5447 appear to be created. */
5448 if (perm == 0)
5449 return 0;
5450
5451 return avc_has_perm(tsec->sid, ksec->sid,
5452 SECCLASS_KEY, perm, NULL);
5453}
5454
David Howells70a5bb72008-04-29 01:01:26 -07005455static int selinux_key_getsecurity(struct key *key, char **_buffer)
5456{
5457 struct key_security_struct *ksec = key->security;
5458 char *context = NULL;
5459 unsigned len;
5460 int rc;
5461
5462 rc = security_sid_to_context(ksec->sid, &context, &len);
5463 if (!rc)
5464 rc = len;
5465 *_buffer = context;
5466 return rc;
5467}
5468
Michael LeMayd7200242006-06-22 14:47:17 -07005469#endif
5470
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005472 .name = "selinux",
5473
David Howells5cd9c582008-08-14 11:37:28 +01005474 .ptrace_may_access = selinux_ptrace_may_access,
5475 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 .capget = selinux_capget,
5477 .capset_check = selinux_capset_check,
5478 .capset_set = selinux_capset_set,
5479 .sysctl = selinux_sysctl,
5480 .capable = selinux_capable,
5481 .quotactl = selinux_quotactl,
5482 .quota_on = selinux_quota_on,
5483 .syslog = selinux_syslog,
5484 .vm_enough_memory = selinux_vm_enough_memory,
5485
5486 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005487 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
5489 .bprm_alloc_security = selinux_bprm_alloc_security,
5490 .bprm_free_security = selinux_bprm_free_security,
5491 .bprm_apply_creds = selinux_bprm_apply_creds,
5492 .bprm_post_apply_creds = selinux_bprm_post_apply_creds,
5493 .bprm_set_security = selinux_bprm_set_security,
5494 .bprm_check_security = selinux_bprm_check_security,
5495 .bprm_secureexec = selinux_bprm_secureexec,
5496
5497 .sb_alloc_security = selinux_sb_alloc_security,
5498 .sb_free_security = selinux_sb_free_security,
5499 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005500 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005501 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 .sb_statfs = selinux_sb_statfs,
5503 .sb_mount = selinux_mount,
5504 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005505 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005506 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005507 .sb_parse_opts_str = selinux_parse_opts_str,
5508
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
5510 .inode_alloc_security = selinux_inode_alloc_security,
5511 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005512 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 .inode_unlink = selinux_inode_unlink,
5516 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 .inode_rmdir = selinux_inode_rmdir,
5519 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 .inode_readlink = selinux_inode_readlink,
5522 .inode_follow_link = selinux_inode_follow_link,
5523 .inode_permission = selinux_inode_permission,
5524 .inode_setattr = selinux_inode_setattr,
5525 .inode_getattr = selinux_inode_getattr,
5526 .inode_setxattr = selinux_inode_setxattr,
5527 .inode_post_setxattr = selinux_inode_post_setxattr,
5528 .inode_getxattr = selinux_inode_getxattr,
5529 .inode_listxattr = selinux_inode_listxattr,
5530 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005531 .inode_getsecurity = selinux_inode_getsecurity,
5532 .inode_setsecurity = selinux_inode_setsecurity,
5533 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005534 .inode_need_killpriv = selinux_inode_need_killpriv,
5535 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005536 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
5538 .file_permission = selinux_file_permission,
5539 .file_alloc_security = selinux_file_alloc_security,
5540 .file_free_security = selinux_file_free_security,
5541 .file_ioctl = selinux_file_ioctl,
5542 .file_mmap = selinux_file_mmap,
5543 .file_mprotect = selinux_file_mprotect,
5544 .file_lock = selinux_file_lock,
5545 .file_fcntl = selinux_file_fcntl,
5546 .file_set_fowner = selinux_file_set_fowner,
5547 .file_send_sigiotask = selinux_file_send_sigiotask,
5548 .file_receive = selinux_file_receive,
5549
Eric Paris828dfe12008-04-17 13:17:49 -04005550 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005551
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005553 .cred_alloc_security = selinux_cred_alloc_security,
5554 .cred_free = selinux_cred_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 .task_setuid = selinux_task_setuid,
5556 .task_post_setuid = selinux_task_post_setuid,
5557 .task_setgid = selinux_task_setgid,
5558 .task_setpgid = selinux_task_setpgid,
5559 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005560 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005561 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 .task_setgroups = selinux_task_setgroups,
5563 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005564 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005565 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 .task_setrlimit = selinux_task_setrlimit,
5567 .task_setscheduler = selinux_task_setscheduler,
5568 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005569 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 .task_kill = selinux_task_kill,
5571 .task_wait = selinux_task_wait,
5572 .task_prctl = selinux_task_prctl,
5573 .task_reparent_to_init = selinux_task_reparent_to_init,
Eric Paris828dfe12008-04-17 13:17:49 -04005574 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
5576 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005577 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
5579 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5580 .msg_msg_free_security = selinux_msg_msg_free_security,
5581
5582 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5583 .msg_queue_free_security = selinux_msg_queue_free_security,
5584 .msg_queue_associate = selinux_msg_queue_associate,
5585 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5586 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5587 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5588
5589 .shm_alloc_security = selinux_shm_alloc_security,
5590 .shm_free_security = selinux_shm_free_security,
5591 .shm_associate = selinux_shm_associate,
5592 .shm_shmctl = selinux_shm_shmctl,
5593 .shm_shmat = selinux_shm_shmat,
5594
Eric Paris828dfe12008-04-17 13:17:49 -04005595 .sem_alloc_security = selinux_sem_alloc_security,
5596 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 .sem_associate = selinux_sem_associate,
5598 .sem_semctl = selinux_sem_semctl,
5599 .sem_semop = selinux_sem_semop,
5600
Eric Paris828dfe12008-04-17 13:17:49 -04005601 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
Eric Paris828dfe12008-04-17 13:17:49 -04005603 .getprocattr = selinux_getprocattr,
5604 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005606 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005607 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005608 .release_secctx = selinux_release_secctx,
5609
Eric Paris828dfe12008-04-17 13:17:49 -04005610 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 .unix_may_send = selinux_socket_unix_may_send,
5612
5613 .socket_create = selinux_socket_create,
5614 .socket_post_create = selinux_socket_post_create,
5615 .socket_bind = selinux_socket_bind,
5616 .socket_connect = selinux_socket_connect,
5617 .socket_listen = selinux_socket_listen,
5618 .socket_accept = selinux_socket_accept,
5619 .socket_sendmsg = selinux_socket_sendmsg,
5620 .socket_recvmsg = selinux_socket_recvmsg,
5621 .socket_getsockname = selinux_socket_getsockname,
5622 .socket_getpeername = selinux_socket_getpeername,
5623 .socket_getsockopt = selinux_socket_getsockopt,
5624 .socket_setsockopt = selinux_socket_setsockopt,
5625 .socket_shutdown = selinux_socket_shutdown,
5626 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005627 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5628 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 .sk_alloc_security = selinux_sk_alloc_security,
5630 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005631 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005632 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005633 .sock_graft = selinux_sock_graft,
5634 .inet_conn_request = selinux_inet_conn_request,
5635 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005636 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005637 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005638
5639#ifdef CONFIG_SECURITY_NETWORK_XFRM
5640 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5641 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5642 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005643 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005644 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5645 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005646 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005647 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005648 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005649 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005651
5652#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005653 .key_alloc = selinux_key_alloc,
5654 .key_free = selinux_key_free,
5655 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005656 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005657#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005658
5659#ifdef CONFIG_AUDIT
5660 .audit_rule_init = selinux_audit_rule_init,
5661 .audit_rule_known = selinux_audit_rule_known,
5662 .audit_rule_match = selinux_audit_rule_match,
5663 .audit_rule_free = selinux_audit_rule_free,
5664#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665};
5666
5667static __init int selinux_init(void)
5668{
5669 struct task_security_struct *tsec;
5670
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005671 if (!security_module_enable(&selinux_ops)) {
5672 selinux_enabled = 0;
5673 return 0;
5674 }
5675
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 if (!selinux_enabled) {
5677 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5678 return 0;
5679 }
5680
5681 printk(KERN_INFO "SELinux: Initializing.\n");
5682
5683 /* Set the security state for the initial task. */
David Howellsf1752ee2008-11-14 10:39:17 +11005684 if (cred_alloc_security(current->cred))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 panic("SELinux: Failed to initialize initial task.\n");
David Howellsb6dff3e2008-11-14 10:39:16 +11005686 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 tsec->osid = tsec->sid = SECINITSID_KERNEL;
5688
James Morris7cae7e22006-03-22 00:09:22 -08005689 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5690 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005691 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 avc_init();
5693
James Morris6f0f0fd2008-07-10 17:02:07 +09005694 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005696 panic("SELinux: No initial security operations\n");
5697 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 panic("SELinux: Unable to register with kernel.\n");
5699
Eric Paris828dfe12008-04-17 13:17:49 -04005700 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005701 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005702 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005703 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005704
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 return 0;
5706}
5707
5708void selinux_complete_init(void)
5709{
Eric Parisfadcdb42007-02-22 18:11:31 -05005710 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711
5712 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005713 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005714 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 spin_lock(&sb_security_lock);
5716next_sb:
5717 if (!list_empty(&superblock_security_head)) {
5718 struct superblock_security_struct *sbsec =
5719 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005720 struct superblock_security_struct,
5721 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005725 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 down_read(&sb->s_umount);
5727 if (sb->s_root)
5728 superblock_doinit(sb, NULL);
5729 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005730 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 spin_lock(&sb_security_lock);
5732 list_del_init(&sbsec->list);
5733 goto next_sb;
5734 }
5735 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005736 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737}
5738
5739/* SELinux requires early initialization in order to label
5740 all processes and objects when they are created. */
5741security_initcall(selinux_init);
5742
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005743#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744
Paul Mooreeffad8d2008-01-29 08:49:27 -05005745static struct nf_hook_ops selinux_ipv4_ops[] = {
5746 {
5747 .hook = selinux_ipv4_postroute,
5748 .owner = THIS_MODULE,
5749 .pf = PF_INET,
5750 .hooknum = NF_INET_POST_ROUTING,
5751 .priority = NF_IP_PRI_SELINUX_LAST,
5752 },
5753 {
5754 .hook = selinux_ipv4_forward,
5755 .owner = THIS_MODULE,
5756 .pf = PF_INET,
5757 .hooknum = NF_INET_FORWARD,
5758 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005759 },
5760 {
5761 .hook = selinux_ipv4_output,
5762 .owner = THIS_MODULE,
5763 .pf = PF_INET,
5764 .hooknum = NF_INET_LOCAL_OUT,
5765 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767};
5768
5769#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5770
Paul Mooreeffad8d2008-01-29 08:49:27 -05005771static struct nf_hook_ops selinux_ipv6_ops[] = {
5772 {
5773 .hook = selinux_ipv6_postroute,
5774 .owner = THIS_MODULE,
5775 .pf = PF_INET6,
5776 .hooknum = NF_INET_POST_ROUTING,
5777 .priority = NF_IP6_PRI_SELINUX_LAST,
5778 },
5779 {
5780 .hook = selinux_ipv6_forward,
5781 .owner = THIS_MODULE,
5782 .pf = PF_INET6,
5783 .hooknum = NF_INET_FORWARD,
5784 .priority = NF_IP6_PRI_SELINUX_FIRST,
5785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786};
5787
5788#endif /* IPV6 */
5789
5790static int __init selinux_nf_ip_init(void)
5791{
5792 int err = 0;
5793
5794 if (!selinux_enabled)
5795 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005796
5797 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5798
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005799 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5800 if (err)
5801 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
5803#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005804 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5805 if (err)
5806 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005808
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809out:
5810 return err;
5811}
5812
5813__initcall(selinux_nf_ip_init);
5814
5815#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5816static void selinux_nf_ip_exit(void)
5817{
Eric Parisfadcdb42007-02-22 18:11:31 -05005818 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005820 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005822 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823#endif /* IPV6 */
5824}
5825#endif
5826
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005827#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828
5829#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5830#define selinux_nf_ip_exit()
5831#endif
5832
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005833#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834
5835#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005836static int selinux_disabled;
5837
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838int selinux_disable(void)
5839{
5840 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
5842 if (ss_initialized) {
5843 /* Not permitted after initial policy load. */
5844 return -EINVAL;
5845 }
5846
5847 if (selinux_disabled) {
5848 /* Only do this once. */
5849 return -EINVAL;
5850 }
5851
5852 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5853
5854 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005855 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856
5857 /* Reset security_ops to the secondary module, dummy or capability. */
5858 security_ops = secondary_ops;
5859
5860 /* Unregister netfilter hooks. */
5861 selinux_nf_ip_exit();
5862
5863 /* Unregister selinuxfs. */
5864 exit_sel_fs();
5865
5866 return 0;
5867}
5868#endif