blob: f20cbd681ba66e1f38ab90ceab5f66c37fe45586 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * NSA Security-Enhanced Linux (SELinux) security module
3 *
4 * This file contains the SELinux hook function implementations.
5 *
6 * Authors: Stephen Smalley, <sds@epoch.ncsc.mil>
Eric Paris828dfe12008-04-17 13:17:49 -04007 * Chris Vance, <cvance@nai.com>
8 * Wayne Salamon, <wsalamon@nai.com>
9 * James Morris <jmorris@redhat.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * Copyright (C) 2001,2002 Networks Associates Technology, Inc.
Eric Paris2069f452008-07-04 09:47:13 +100012 * Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
13 * Eric Paris <eparis@redhat.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
Eric Paris828dfe12008-04-17 13:17:49 -040015 * <dgoeddel@trustedcs.com>
Paul Mooreeffad8d2008-01-29 08:49:27 -050016 * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
Eric Paris828dfe12008-04-17 13:17:49 -040017 * Paul Moore <paul.moore@hp.com>
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +090018 * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
Eric Paris828dfe12008-04-17 13:17:49 -040019 * Yuichi Nakamura <ynakam@hitachisoft.jp>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2,
Eric Paris828dfe12008-04-17 13:17:49 -040023 * as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/kernel.h>
Roland McGrath0d094ef2008-07-25 19:45:49 -070028#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/errno.h>
30#include <linux/sched.h>
31#include <linux/security.h>
32#include <linux/xattr.h>
33#include <linux/capability.h>
34#include <linux/unistd.h>
35#include <linux/mm.h>
36#include <linux/mman.h>
37#include <linux/slab.h>
38#include <linux/pagemap.h>
39#include <linux/swap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/spinlock.h>
41#include <linux/syscalls.h>
42#include <linux/file.h>
Al Viro9f3acc32008-04-24 07:44:08 -040043#include <linux/fdtable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/namei.h>
45#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/netfilter_ipv4.h>
48#include <linux/netfilter_ipv6.h>
49#include <linux/tty.h>
50#include <net/icmp.h>
Stephen Hemminger227b60f2007-10-10 17:30:46 -070051#include <net/ip.h> /* for local_port_range[] */
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
Paul Moore220deb92008-01-29 08:38:23 -050053#include <net/net_namespace.h>
Paul Moored621d352008-01-29 08:43:36 -050054#include <net/netlabel.h>
Eric Parisf5269712008-05-14 11:27:45 -040055#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <asm/ioctls.h>
Paul Moored621d352008-01-29 08:43:36 -050057#include <asm/atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <linux/bitops.h>
59#include <linux/interrupt.h>
60#include <linux/netdevice.h> /* for network interface checks */
61#include <linux/netlink.h>
62#include <linux/tcp.h>
63#include <linux/udp.h>
James Morris2ee92d42006-11-13 16:09:01 -080064#include <linux/dccp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#include <linux/quota.h>
66#include <linux/un.h> /* for Unix socket types */
67#include <net/af_unix.h> /* for Unix socket types */
68#include <linux/parser.h>
69#include <linux/nfs_mount.h>
70#include <net/ipv6.h>
71#include <linux/hugetlb.h>
72#include <linux/personality.h>
73#include <linux/sysctl.h>
74#include <linux/audit.h>
Eric Paris6931dfc2005-06-30 02:58:51 -070075#include <linux/string.h>
Catherine Zhang877ce7c2006-06-29 12:27:47 -070076#include <linux/selinux.h>
Eric Paris23970742006-09-25 23:32:01 -070077#include <linux/mutex.h>
Frank Mayharf06febc2008-09-12 09:54:39 -070078#include <linux/posix-timers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80#include "avc.h"
81#include "objsec.h"
82#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050083#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040084#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080085#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050086#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020087#include "audit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89#define XATTR_SELINUX_SUFFIX "selinux"
90#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
91
Eric Parisc9180a52007-11-30 13:00:35 -050092#define NUM_SEL_MNT_OPTS 4
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094extern unsigned int policydb_loaded_version;
95extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
James Morris4e5ab4c2006-06-09 00:33:33 -070096extern int selinux_compat_net;
James Morris20510f22007-10-16 23:31:32 -070097extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Paul Moored621d352008-01-29 08:43:36 -050099/* SECMARK reference count */
100atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400103int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105static int __init enforcing_setup(char *str)
106{
Eric Parisf5269712008-05-14 11:27:45 -0400107 unsigned long enforcing;
108 if (!strict_strtoul(str, 0, &enforcing))
109 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 return 1;
111}
112__setup("enforcing=", enforcing_setup);
113#endif
114
115#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
116int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
117
118static int __init selinux_enabled_setup(char *str)
119{
Eric Parisf5269712008-05-14 11:27:45 -0400120 unsigned long enabled;
121 if (!strict_strtoul(str, 0, &enabled))
122 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return 1;
124}
125__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400126#else
127int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#endif
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
James Morris6f0f0fd2008-07-10 17:02:07 +0900131/*
132 * Minimal support for a secondary security module,
133 * just to allow the use of the capability module.
134 */
Eric Paris828dfe12008-04-17 13:17:49 -0400135static struct security_operations *secondary_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137/* Lists of inode and superblock security structures initialized
138 before the policy was loaded. */
139static LIST_HEAD(superblock_security_head);
140static DEFINE_SPINLOCK(sb_security_lock);
141
Christoph Lametere18b8902006-12-06 20:33:20 -0800142static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800143
Paul Moored621d352008-01-29 08:43:36 -0500144/**
145 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
146 *
147 * Description:
148 * This function checks the SECMARK reference counter to see if any SECMARK
149 * targets are currently configured, if the reference counter is greater than
150 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
151 * enabled, false (0) if SECMARK is disabled.
152 *
153 */
154static int selinux_secmark_enabled(void)
155{
156 return (atomic_read(&selinux_secmark_refcount) > 0);
157}
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159/* Allocate and free functions for each kind of security blob. */
160
David Howellsf1752ee2008-11-14 10:39:17 +1100161static int cred_alloc_security(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 struct task_security_struct *tsec;
164
James Morris89d155e2005-10-30 14:59:21 -0800165 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 if (!tsec)
167 return -ENOMEM;
168
Roland McGrath03563572008-03-26 15:46:39 -0700169 tsec->osid = tsec->sid = SECINITSID_UNLABELED;
David Howellsf1752ee2008-11-14 10:39:17 +1100170 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 return 0;
173}
174
David Howells275bb412008-11-14 10:39:19 +1100175/*
David Howells88e67f32008-11-14 10:39:21 +1100176 * get the security ID of a set of credentials
177 */
178static inline u32 cred_sid(const struct cred *cred)
179{
180 const struct task_security_struct *tsec;
181
182 tsec = cred->security;
183 return tsec->sid;
184}
185
186/*
David Howells275bb412008-11-14 10:39:19 +1100187 * get the security ID of a task
188 */
189static inline u32 task_sid(const struct task_struct *task)
190{
David Howells275bb412008-11-14 10:39:19 +1100191 u32 sid;
192
193 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100194 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100195 rcu_read_unlock();
196 return sid;
197}
198
199/*
200 * get the security ID of the current task
201 */
202static inline u32 current_sid(void)
203{
204 const struct task_security_struct *tsec = current_cred()->security;
205
206 return tsec->sid;
207}
208
David Howells88e67f32008-11-14 10:39:21 +1100209/* Allocate and free functions for each kind of security blob. */
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211static int inode_alloc_security(struct inode *inode)
212{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100214 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Josef Bacika02fe132008-04-04 09:35:05 +1100216 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 if (!isec)
218 return -ENOMEM;
219
Eric Paris23970742006-09-25 23:32:01 -0700220 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 isec->inode = inode;
223 isec->sid = SECINITSID_UNLABELED;
224 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100225 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 inode->i_security = isec;
227
228 return 0;
229}
230
231static void inode_free_security(struct inode *inode)
232{
233 struct inode_security_struct *isec = inode->i_security;
234 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 spin_lock(&sbsec->isec_lock);
237 if (!list_empty(&isec->list))
238 list_del_init(&isec->list);
239 spin_unlock(&sbsec->isec_lock);
240
241 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800242 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245static int file_alloc_security(struct file *file)
246{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100248 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800250 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if (!fsec)
252 return -ENOMEM;
253
David Howells275bb412008-11-14 10:39:19 +1100254 fsec->sid = sid;
255 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 file->f_security = fsec;
257
258 return 0;
259}
260
261static void file_free_security(struct file *file)
262{
263 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 file->f_security = NULL;
265 kfree(fsec);
266}
267
268static int superblock_alloc_security(struct super_block *sb)
269{
270 struct superblock_security_struct *sbsec;
271
James Morris89d155e2005-10-30 14:59:21 -0800272 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 if (!sbsec)
274 return -ENOMEM;
275
Eric Parisbc7e9822006-09-25 23:32:02 -0700276 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 INIT_LIST_HEAD(&sbsec->list);
278 INIT_LIST_HEAD(&sbsec->isec_head);
279 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sbsec->sb = sb;
281 sbsec->sid = SECINITSID_UNLABELED;
282 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700283 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 sb->s_security = sbsec;
285
286 return 0;
287}
288
289static void superblock_free_security(struct super_block *sb)
290{
291 struct superblock_security_struct *sbsec = sb->s_security;
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 spin_lock(&sb_security_lock);
294 if (!list_empty(&sbsec->list))
295 list_del_init(&sbsec->list);
296 spin_unlock(&sb_security_lock);
297
298 sb->s_security = NULL;
299 kfree(sbsec);
300}
301
Al Viro7d877f32005-10-21 03:20:43 -0400302static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 struct sk_security_struct *ssec;
305
James Morris89d155e2005-10-30 14:59:21 -0800306 ssec = kzalloc(sizeof(*ssec), priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 if (!ssec)
308 return -ENOMEM;
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 ssec->peer_sid = SECINITSID_UNLABELED;
Venkat Yekkirala892c1412006-08-04 23:08:56 -0700311 ssec->sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 sk->sk_security = ssec;
313
Paul Mooref74af6e2008-02-25 11:40:33 -0500314 selinux_netlbl_sk_security_reset(ssec, family);
Paul Moore99f59ed2006-08-29 17:53:48 -0700315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return 0;
317}
318
319static void sk_free_security(struct sock *sk)
320{
321 struct sk_security_struct *ssec = sk->sk_security;
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 sk->sk_security = NULL;
Paul Moore6c5b3fc2008-10-10 10:16:33 -0400324 selinux_netlbl_sk_security_free(ssec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 kfree(ssec);
326}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328/* The security server must be initialized before
329 any labeling or access decisions can be provided. */
330extern int ss_initialized;
331
332/* The file system's label must be initialized prior to use. */
333
334static char *labeling_behaviors[6] = {
335 "uses xattr",
336 "uses transition SIDs",
337 "uses task SIDs",
338 "uses genfs_contexts",
339 "not configured for labeling",
340 "uses mountpoint labeling",
341};
342
343static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
344
345static inline int inode_doinit(struct inode *inode)
346{
347 return inode_doinit_with_dentry(inode, NULL);
348}
349
350enum {
Eric Paris31e87932007-09-19 17:19:12 -0400351 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 Opt_context = 1,
353 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500354 Opt_defcontext = 3,
355 Opt_rootcontext = 4,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356};
357
Steven Whitehousea447c092008-10-13 10:46:57 +0100358static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400359 {Opt_context, CONTEXT_STR "%s"},
360 {Opt_fscontext, FSCONTEXT_STR "%s"},
361 {Opt_defcontext, DEFCONTEXT_STR "%s"},
362 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
Eric Paris31e87932007-09-19 17:19:12 -0400363 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364};
365
366#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
367
Eric Parisc312feb2006-07-10 04:43:53 -0700368static int may_context_mount_sb_relabel(u32 sid,
369 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100370 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700371{
David Howells275bb412008-11-14 10:39:19 +1100372 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700373 int rc;
374
375 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
376 FILESYSTEM__RELABELFROM, NULL);
377 if (rc)
378 return rc;
379
380 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
381 FILESYSTEM__RELABELTO, NULL);
382 return rc;
383}
384
Eric Paris08089252006-07-10 04:43:55 -0700385static int may_context_mount_inode_relabel(u32 sid,
386 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100387 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700388{
David Howells275bb412008-11-14 10:39:19 +1100389 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700390 int rc;
391 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
392 FILESYSTEM__RELABELFROM, NULL);
393 if (rc)
394 return rc;
395
396 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
397 FILESYSTEM__ASSOCIATE, NULL);
398 return rc;
399}
400
Eric Parisc9180a52007-11-30 13:00:35 -0500401static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
403 struct superblock_security_struct *sbsec = sb->s_security;
404 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500405 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 int rc = 0;
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
409 /* Make sure that the xattr handler exists and that no
410 error other than -ENODATA is returned by getxattr on
411 the root directory. -ENODATA is ok, as this may be
412 the first boot of the SELinux kernel before we have
413 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500414 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
416 "xattr support\n", sb->s_id, sb->s_type->name);
417 rc = -EOPNOTSUPP;
418 goto out;
419 }
Eric Parisc9180a52007-11-30 13:00:35 -0500420 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 if (rc < 0 && rc != -ENODATA) {
422 if (rc == -EOPNOTSUPP)
423 printk(KERN_WARNING "SELinux: (dev %s, type "
424 "%s) has no security xattr handler\n",
425 sb->s_id, sb->s_type->name);
426 else
427 printk(KERN_WARNING "SELinux: (dev %s, type "
428 "%s) getxattr errno %d\n", sb->s_id,
429 sb->s_type->name, -rc);
430 goto out;
431 }
432 }
433
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 sbsec->initialized = 1;
435
Eric Parisc9180a52007-11-30 13:00:35 -0500436 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500437 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500439 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500440 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sb->s_id, sb->s_type->name,
442 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500445 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 /* Initialize any other inodes associated with the superblock, e.g.
448 inodes created prior to initial policy load or inodes created
449 during get_sb by a pseudo filesystem that directly
450 populates itself. */
451 spin_lock(&sbsec->isec_lock);
452next_inode:
453 if (!list_empty(&sbsec->isec_head)) {
454 struct inode_security_struct *isec =
455 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500456 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 struct inode *inode = isec->inode;
458 spin_unlock(&sbsec->isec_lock);
459 inode = igrab(inode);
460 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500461 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 inode_doinit(inode);
463 iput(inode);
464 }
465 spin_lock(&sbsec->isec_lock);
466 list_del_init(&isec->list);
467 goto next_inode;
468 }
469 spin_unlock(&sbsec->isec_lock);
470out:
Eric Parisc9180a52007-11-30 13:00:35 -0500471 return rc;
472}
473
474/*
475 * This function should allow an FS to ask what it's mount security
476 * options were so it can use those later for submounts, displaying
477 * mount options, or whatever.
478 */
479static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500480 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500481{
482 int rc = 0, i;
483 struct superblock_security_struct *sbsec = sb->s_security;
484 char *context = NULL;
485 u32 len;
486 char tmp;
487
Eric Parise0007522008-03-05 10:31:54 -0500488 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500489
490 if (!sbsec->initialized)
491 return -EINVAL;
492
493 if (!ss_initialized)
494 return -EINVAL;
495
496 /*
497 * if we ever use sbsec flags for anything other than tracking mount
498 * settings this is going to need a mask
499 */
500 tmp = sbsec->flags;
501 /* count the number of mount options for this sb */
502 for (i = 0; i < 8; i++) {
503 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500504 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500505 tmp >>= 1;
506 }
507
Eric Parise0007522008-03-05 10:31:54 -0500508 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
509 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500510 rc = -ENOMEM;
511 goto out_free;
512 }
513
Eric Parise0007522008-03-05 10:31:54 -0500514 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
515 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500516 rc = -ENOMEM;
517 goto out_free;
518 }
519
520 i = 0;
521 if (sbsec->flags & FSCONTEXT_MNT) {
522 rc = security_sid_to_context(sbsec->sid, &context, &len);
523 if (rc)
524 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500525 opts->mnt_opts[i] = context;
526 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500527 }
528 if (sbsec->flags & CONTEXT_MNT) {
529 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
530 if (rc)
531 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500532 opts->mnt_opts[i] = context;
533 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500534 }
535 if (sbsec->flags & DEFCONTEXT_MNT) {
536 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
537 if (rc)
538 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500539 opts->mnt_opts[i] = context;
540 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500541 }
542 if (sbsec->flags & ROOTCONTEXT_MNT) {
543 struct inode *root = sbsec->sb->s_root->d_inode;
544 struct inode_security_struct *isec = root->i_security;
545
546 rc = security_sid_to_context(isec->sid, &context, &len);
547 if (rc)
548 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500549 opts->mnt_opts[i] = context;
550 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500551 }
552
Eric Parise0007522008-03-05 10:31:54 -0500553 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500554
555 return 0;
556
557out_free:
Eric Parise0007522008-03-05 10:31:54 -0500558 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500559 return rc;
560}
561
562static int bad_option(struct superblock_security_struct *sbsec, char flag,
563 u32 old_sid, u32 new_sid)
564{
565 /* check if the old mount command had the same options */
566 if (sbsec->initialized)
567 if (!(sbsec->flags & flag) ||
568 (old_sid != new_sid))
569 return 1;
570
571 /* check if we were passed the same options twice,
572 * aka someone passed context=a,context=b
573 */
574 if (!sbsec->initialized)
575 if (sbsec->flags & flag)
576 return 1;
577 return 0;
578}
Eric Parise0007522008-03-05 10:31:54 -0500579
Eric Parisc9180a52007-11-30 13:00:35 -0500580/*
581 * Allow filesystems with binary mount data to explicitly set mount point
582 * labeling information.
583 */
Eric Parise0007522008-03-05 10:31:54 -0500584static int selinux_set_mnt_opts(struct super_block *sb,
585 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500586{
David Howells275bb412008-11-14 10:39:19 +1100587 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500588 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500589 struct superblock_security_struct *sbsec = sb->s_security;
590 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000591 struct inode *inode = sbsec->sb->s_root->d_inode;
592 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500593 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
594 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500595 char **mount_options = opts->mnt_opts;
596 int *flags = opts->mnt_opts_flags;
597 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500598
599 mutex_lock(&sbsec->lock);
600
601 if (!ss_initialized) {
602 if (!num_opts) {
603 /* Defer initialization until selinux_complete_init,
604 after the initial policy is loaded and the security
605 server is ready to handle calls. */
606 spin_lock(&sb_security_lock);
607 if (list_empty(&sbsec->list))
608 list_add(&sbsec->list, &superblock_security_head);
609 spin_unlock(&sb_security_lock);
610 goto out;
611 }
612 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400613 printk(KERN_WARNING "SELinux: Unable to set superblock options "
614 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500615 goto out;
616 }
617
618 /*
Eric Parise0007522008-03-05 10:31:54 -0500619 * Binary mount data FS will come through this function twice. Once
620 * from an explicit call and once from the generic calls from the vfs.
621 * Since the generic VFS calls will not contain any security mount data
622 * we need to skip the double mount verification.
623 *
624 * This does open a hole in which we will not notice if the first
625 * mount using this sb set explict options and a second mount using
626 * this sb does not set any security options. (The first options
627 * will be used for both mounts)
628 */
629 if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
630 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400631 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500632
633 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500634 * parse the mount options, check if they are valid sids.
635 * also check if someone is trying to mount the same sb more
636 * than once with different security options.
637 */
638 for (i = 0; i < num_opts; i++) {
639 u32 sid;
640 rc = security_context_to_sid(mount_options[i],
641 strlen(mount_options[i]), &sid);
642 if (rc) {
643 printk(KERN_WARNING "SELinux: security_context_to_sid"
644 "(%s) failed for (dev %s, type %s) errno=%d\n",
645 mount_options[i], sb->s_id, name, rc);
646 goto out;
647 }
648 switch (flags[i]) {
649 case FSCONTEXT_MNT:
650 fscontext_sid = sid;
651
652 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
653 fscontext_sid))
654 goto out_double_mount;
655
656 sbsec->flags |= FSCONTEXT_MNT;
657 break;
658 case CONTEXT_MNT:
659 context_sid = sid;
660
661 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
662 context_sid))
663 goto out_double_mount;
664
665 sbsec->flags |= CONTEXT_MNT;
666 break;
667 case ROOTCONTEXT_MNT:
668 rootcontext_sid = sid;
669
670 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
671 rootcontext_sid))
672 goto out_double_mount;
673
674 sbsec->flags |= ROOTCONTEXT_MNT;
675
676 break;
677 case DEFCONTEXT_MNT:
678 defcontext_sid = sid;
679
680 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
681 defcontext_sid))
682 goto out_double_mount;
683
684 sbsec->flags |= DEFCONTEXT_MNT;
685
686 break;
687 default:
688 rc = -EINVAL;
689 goto out;
690 }
691 }
692
693 if (sbsec->initialized) {
694 /* previously mounted with options, but not on this attempt? */
695 if (sbsec->flags && !num_opts)
696 goto out_double_mount;
697 rc = 0;
698 goto out;
699 }
700
James Morris089be432008-07-15 18:32:49 +1000701 if (strcmp(sb->s_type->name, "proc") == 0)
Eric Parisc9180a52007-11-30 13:00:35 -0500702 sbsec->proc = 1;
703
704 /* Determine the labeling behavior to use for this filesystem type. */
James Morris089be432008-07-15 18:32:49 +1000705 rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500706 if (rc) {
707 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000708 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500709 goto out;
710 }
711
712 /* sets the context of the superblock for the fs being mounted. */
713 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100714 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500715 if (rc)
716 goto out;
717
718 sbsec->sid = fscontext_sid;
719 }
720
721 /*
722 * Switch to using mount point labeling behavior.
723 * sets the label used on all file below the mountpoint, and will set
724 * the superblock context if not already set.
725 */
726 if (context_sid) {
727 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100728 rc = may_context_mount_sb_relabel(context_sid, sbsec,
729 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500730 if (rc)
731 goto out;
732 sbsec->sid = context_sid;
733 } else {
David Howells275bb412008-11-14 10:39:19 +1100734 rc = may_context_mount_inode_relabel(context_sid, sbsec,
735 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500736 if (rc)
737 goto out;
738 }
739 if (!rootcontext_sid)
740 rootcontext_sid = context_sid;
741
742 sbsec->mntpoint_sid = context_sid;
743 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
744 }
745
746 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100747 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
748 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500749 if (rc)
750 goto out;
751
752 root_isec->sid = rootcontext_sid;
753 root_isec->initialized = 1;
754 }
755
756 if (defcontext_sid) {
757 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
758 rc = -EINVAL;
759 printk(KERN_WARNING "SELinux: defcontext option is "
760 "invalid for this filesystem type\n");
761 goto out;
762 }
763
764 if (defcontext_sid != sbsec->def_sid) {
765 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100766 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500767 if (rc)
768 goto out;
769 }
770
771 sbsec->def_sid = defcontext_sid;
772 }
773
774 rc = sb_finish_set_opts(sb);
775out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700776 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500778out_double_mount:
779 rc = -EINVAL;
780 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
781 "security settings for (dev %s, type %s)\n", sb->s_id, name);
782 goto out;
783}
784
785static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
786 struct super_block *newsb)
787{
788 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
789 struct superblock_security_struct *newsbsec = newsb->s_security;
790
791 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
792 int set_context = (oldsbsec->flags & CONTEXT_MNT);
793 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
794
Eric Paris0f5e6422008-04-21 16:24:11 -0400795 /*
796 * if the parent was able to be mounted it clearly had no special lsm
797 * mount options. thus we can safely put this sb on the list and deal
798 * with it later
799 */
800 if (!ss_initialized) {
801 spin_lock(&sb_security_lock);
802 if (list_empty(&newsbsec->list))
803 list_add(&newsbsec->list, &superblock_security_head);
804 spin_unlock(&sb_security_lock);
805 return;
806 }
Eric Parisc9180a52007-11-30 13:00:35 -0500807
Eric Parisc9180a52007-11-30 13:00:35 -0500808 /* how can we clone if the old one wasn't set up?? */
809 BUG_ON(!oldsbsec->initialized);
810
Eric Paris5a552612008-04-09 14:08:35 -0400811 /* if fs is reusing a sb, just let its options stand... */
812 if (newsbsec->initialized)
813 return;
814
Eric Parisc9180a52007-11-30 13:00:35 -0500815 mutex_lock(&newsbsec->lock);
816
817 newsbsec->flags = oldsbsec->flags;
818
819 newsbsec->sid = oldsbsec->sid;
820 newsbsec->def_sid = oldsbsec->def_sid;
821 newsbsec->behavior = oldsbsec->behavior;
822
823 if (set_context) {
824 u32 sid = oldsbsec->mntpoint_sid;
825
826 if (!set_fscontext)
827 newsbsec->sid = sid;
828 if (!set_rootcontext) {
829 struct inode *newinode = newsb->s_root->d_inode;
830 struct inode_security_struct *newisec = newinode->i_security;
831 newisec->sid = sid;
832 }
833 newsbsec->mntpoint_sid = sid;
834 }
835 if (set_rootcontext) {
836 const struct inode *oldinode = oldsb->s_root->d_inode;
837 const struct inode_security_struct *oldisec = oldinode->i_security;
838 struct inode *newinode = newsb->s_root->d_inode;
839 struct inode_security_struct *newisec = newinode->i_security;
840
841 newisec->sid = oldisec->sid;
842 }
843
844 sb_finish_set_opts(newsb);
845 mutex_unlock(&newsbsec->lock);
846}
847
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200848static int selinux_parse_opts_str(char *options,
849 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500850{
Eric Parise0007522008-03-05 10:31:54 -0500851 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500852 char *context = NULL, *defcontext = NULL;
853 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500854 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500855
Eric Parise0007522008-03-05 10:31:54 -0500856 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500857
858 /* Standard string-based options. */
859 while ((p = strsep(&options, "|")) != NULL) {
860 int token;
861 substring_t args[MAX_OPT_ARGS];
862
863 if (!*p)
864 continue;
865
866 token = match_token(p, tokens, args);
867
868 switch (token) {
869 case Opt_context:
870 if (context || defcontext) {
871 rc = -EINVAL;
872 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
873 goto out_err;
874 }
875 context = match_strdup(&args[0]);
876 if (!context) {
877 rc = -ENOMEM;
878 goto out_err;
879 }
880 break;
881
882 case Opt_fscontext:
883 if (fscontext) {
884 rc = -EINVAL;
885 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
886 goto out_err;
887 }
888 fscontext = match_strdup(&args[0]);
889 if (!fscontext) {
890 rc = -ENOMEM;
891 goto out_err;
892 }
893 break;
894
895 case Opt_rootcontext:
896 if (rootcontext) {
897 rc = -EINVAL;
898 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
899 goto out_err;
900 }
901 rootcontext = match_strdup(&args[0]);
902 if (!rootcontext) {
903 rc = -ENOMEM;
904 goto out_err;
905 }
906 break;
907
908 case Opt_defcontext:
909 if (context || defcontext) {
910 rc = -EINVAL;
911 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
912 goto out_err;
913 }
914 defcontext = match_strdup(&args[0]);
915 if (!defcontext) {
916 rc = -ENOMEM;
917 goto out_err;
918 }
919 break;
920
921 default:
922 rc = -EINVAL;
923 printk(KERN_WARNING "SELinux: unknown mount option\n");
924 goto out_err;
925
926 }
927 }
928
Eric Parise0007522008-03-05 10:31:54 -0500929 rc = -ENOMEM;
930 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
931 if (!opts->mnt_opts)
932 goto out_err;
933
934 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
935 if (!opts->mnt_opts_flags) {
936 kfree(opts->mnt_opts);
937 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500938 }
939
Eric Parise0007522008-03-05 10:31:54 -0500940 if (fscontext) {
941 opts->mnt_opts[num_mnt_opts] = fscontext;
942 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
943 }
944 if (context) {
945 opts->mnt_opts[num_mnt_opts] = context;
946 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
947 }
948 if (rootcontext) {
949 opts->mnt_opts[num_mnt_opts] = rootcontext;
950 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
951 }
952 if (defcontext) {
953 opts->mnt_opts[num_mnt_opts] = defcontext;
954 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
955 }
956
957 opts->num_mnt_opts = num_mnt_opts;
958 return 0;
959
Eric Parisc9180a52007-11-30 13:00:35 -0500960out_err:
961 kfree(context);
962 kfree(defcontext);
963 kfree(fscontext);
964 kfree(rootcontext);
965 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
Eric Parise0007522008-03-05 10:31:54 -0500967/*
968 * string mount options parsing and call set the sbsec
969 */
970static int superblock_doinit(struct super_block *sb, void *data)
971{
972 int rc = 0;
973 char *options = data;
974 struct security_mnt_opts opts;
975
976 security_init_mnt_opts(&opts);
977
978 if (!data)
979 goto out;
980
981 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
982
983 rc = selinux_parse_opts_str(options, &opts);
984 if (rc)
985 goto out_err;
986
987out:
988 rc = selinux_set_mnt_opts(sb, &opts);
989
990out_err:
991 security_free_mnt_opts(&opts);
992 return rc;
993}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Adrian Bunk3583a712008-07-22 20:21:23 +0300995static void selinux_write_opts(struct seq_file *m,
996 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000997{
998 int i;
999 char *prefix;
1000
1001 for (i = 0; i < opts->num_mnt_opts; i++) {
1002 char *has_comma = strchr(opts->mnt_opts[i], ',');
1003
1004 switch (opts->mnt_opts_flags[i]) {
1005 case CONTEXT_MNT:
1006 prefix = CONTEXT_STR;
1007 break;
1008 case FSCONTEXT_MNT:
1009 prefix = FSCONTEXT_STR;
1010 break;
1011 case ROOTCONTEXT_MNT:
1012 prefix = ROOTCONTEXT_STR;
1013 break;
1014 case DEFCONTEXT_MNT:
1015 prefix = DEFCONTEXT_STR;
1016 break;
1017 default:
1018 BUG();
1019 };
1020 /* we need a comma before each option */
1021 seq_putc(m, ',');
1022 seq_puts(m, prefix);
1023 if (has_comma)
1024 seq_putc(m, '\"');
1025 seq_puts(m, opts->mnt_opts[i]);
1026 if (has_comma)
1027 seq_putc(m, '\"');
1028 }
1029}
1030
1031static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1032{
1033 struct security_mnt_opts opts;
1034 int rc;
1035
1036 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001037 if (rc) {
1038 /* before policy load we may get EINVAL, don't show anything */
1039 if (rc == -EINVAL)
1040 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001041 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001042 }
Eric Paris2069f452008-07-04 09:47:13 +10001043
1044 selinux_write_opts(m, &opts);
1045
1046 security_free_mnt_opts(&opts);
1047
1048 return rc;
1049}
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051static inline u16 inode_mode_to_security_class(umode_t mode)
1052{
1053 switch (mode & S_IFMT) {
1054 case S_IFSOCK:
1055 return SECCLASS_SOCK_FILE;
1056 case S_IFLNK:
1057 return SECCLASS_LNK_FILE;
1058 case S_IFREG:
1059 return SECCLASS_FILE;
1060 case S_IFBLK:
1061 return SECCLASS_BLK_FILE;
1062 case S_IFDIR:
1063 return SECCLASS_DIR;
1064 case S_IFCHR:
1065 return SECCLASS_CHR_FILE;
1066 case S_IFIFO:
1067 return SECCLASS_FIFO_FILE;
1068
1069 }
1070
1071 return SECCLASS_FILE;
1072}
1073
James Morris13402582005-09-30 14:24:34 -04001074static inline int default_protocol_stream(int protocol)
1075{
1076 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1077}
1078
1079static inline int default_protocol_dgram(int protocol)
1080{
1081 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1082}
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1085{
1086 switch (family) {
1087 case PF_UNIX:
1088 switch (type) {
1089 case SOCK_STREAM:
1090 case SOCK_SEQPACKET:
1091 return SECCLASS_UNIX_STREAM_SOCKET;
1092 case SOCK_DGRAM:
1093 return SECCLASS_UNIX_DGRAM_SOCKET;
1094 }
1095 break;
1096 case PF_INET:
1097 case PF_INET6:
1098 switch (type) {
1099 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001100 if (default_protocol_stream(protocol))
1101 return SECCLASS_TCP_SOCKET;
1102 else
1103 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001105 if (default_protocol_dgram(protocol))
1106 return SECCLASS_UDP_SOCKET;
1107 else
1108 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001109 case SOCK_DCCP:
1110 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001111 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return SECCLASS_RAWIP_SOCKET;
1113 }
1114 break;
1115 case PF_NETLINK:
1116 switch (protocol) {
1117 case NETLINK_ROUTE:
1118 return SECCLASS_NETLINK_ROUTE_SOCKET;
1119 case NETLINK_FIREWALL:
1120 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001121 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1123 case NETLINK_NFLOG:
1124 return SECCLASS_NETLINK_NFLOG_SOCKET;
1125 case NETLINK_XFRM:
1126 return SECCLASS_NETLINK_XFRM_SOCKET;
1127 case NETLINK_SELINUX:
1128 return SECCLASS_NETLINK_SELINUX_SOCKET;
1129 case NETLINK_AUDIT:
1130 return SECCLASS_NETLINK_AUDIT_SOCKET;
1131 case NETLINK_IP6_FW:
1132 return SECCLASS_NETLINK_IP6FW_SOCKET;
1133 case NETLINK_DNRTMSG:
1134 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001135 case NETLINK_KOBJECT_UEVENT:
1136 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 default:
1138 return SECCLASS_NETLINK_SOCKET;
1139 }
1140 case PF_PACKET:
1141 return SECCLASS_PACKET_SOCKET;
1142 case PF_KEY:
1143 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001144 case PF_APPLETALK:
1145 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 }
1147
1148 return SECCLASS_SOCKET;
1149}
1150
1151#ifdef CONFIG_PROC_FS
1152static int selinux_proc_get_sid(struct proc_dir_entry *de,
1153 u16 tclass,
1154 u32 *sid)
1155{
1156 int buflen, rc;
1157 char *buffer, *path, *end;
1158
Eric Paris828dfe12008-04-17 13:17:49 -04001159 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (!buffer)
1161 return -ENOMEM;
1162
1163 buflen = PAGE_SIZE;
1164 end = buffer+buflen;
1165 *--end = '\0';
1166 buflen--;
1167 path = end-1;
1168 *path = '/';
1169 while (de && de != de->parent) {
1170 buflen -= de->namelen + 1;
1171 if (buflen < 0)
1172 break;
1173 end -= de->namelen;
1174 memcpy(end, de->name, de->namelen);
1175 *--end = '/';
1176 path = end;
1177 de = de->parent;
1178 }
1179 rc = security_genfs_sid("proc", path, tclass, sid);
1180 free_page((unsigned long)buffer);
1181 return rc;
1182}
1183#else
1184static int selinux_proc_get_sid(struct proc_dir_entry *de,
1185 u16 tclass,
1186 u32 *sid)
1187{
1188 return -EINVAL;
1189}
1190#endif
1191
1192/* The inode's security attributes must be initialized before first use. */
1193static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1194{
1195 struct superblock_security_struct *sbsec = NULL;
1196 struct inode_security_struct *isec = inode->i_security;
1197 u32 sid;
1198 struct dentry *dentry;
1199#define INITCONTEXTLEN 255
1200 char *context = NULL;
1201 unsigned len = 0;
1202 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 if (isec->initialized)
1205 goto out;
1206
Eric Paris23970742006-09-25 23:32:01 -07001207 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001209 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 sbsec = inode->i_sb->s_security;
1212 if (!sbsec->initialized) {
1213 /* Defer initialization until selinux_complete_init,
1214 after the initial policy is loaded and the security
1215 server is ready to handle calls. */
1216 spin_lock(&sbsec->isec_lock);
1217 if (list_empty(&isec->list))
1218 list_add(&isec->list, &sbsec->isec_head);
1219 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001220 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
1222
1223 switch (sbsec->behavior) {
1224 case SECURITY_FS_USE_XATTR:
1225 if (!inode->i_op->getxattr) {
1226 isec->sid = sbsec->def_sid;
1227 break;
1228 }
1229
1230 /* Need a dentry, since the xattr API requires one.
1231 Life would be simpler if we could just pass the inode. */
1232 if (opt_dentry) {
1233 /* Called from d_instantiate or d_splice_alias. */
1234 dentry = dget(opt_dentry);
1235 } else {
1236 /* Called from selinux_complete_init, try to find a dentry. */
1237 dentry = d_find_alias(inode);
1238 }
1239 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001240 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001241 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001243 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245
1246 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001247 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (!context) {
1249 rc = -ENOMEM;
1250 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001251 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 }
1253 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1254 context, len);
1255 if (rc == -ERANGE) {
1256 /* Need a larger buffer. Query for the right size. */
1257 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1258 NULL, 0);
1259 if (rc < 0) {
1260 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001261 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 }
1263 kfree(context);
1264 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001265 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 if (!context) {
1267 rc = -ENOMEM;
1268 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001269 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
1271 rc = inode->i_op->getxattr(dentry,
1272 XATTR_NAME_SELINUX,
1273 context, len);
1274 }
1275 dput(dentry);
1276 if (rc < 0) {
1277 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001278 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001279 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 -rc, inode->i_sb->s_id, inode->i_ino);
1281 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001282 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 }
1284 /* Map ENODATA to the default file SID */
1285 sid = sbsec->def_sid;
1286 rc = 0;
1287 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001288 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001289 sbsec->def_sid,
1290 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001292 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001294 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 inode->i_sb->s_id, inode->i_ino);
1296 kfree(context);
1297 /* Leave with the unlabeled SID */
1298 rc = 0;
1299 break;
1300 }
1301 }
1302 kfree(context);
1303 isec->sid = sid;
1304 break;
1305 case SECURITY_FS_USE_TASK:
1306 isec->sid = isec->task_sid;
1307 break;
1308 case SECURITY_FS_USE_TRANS:
1309 /* Default to the fs SID. */
1310 isec->sid = sbsec->sid;
1311
1312 /* Try to obtain a transition SID. */
1313 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1314 rc = security_transition_sid(isec->task_sid,
1315 sbsec->sid,
1316 isec->sclass,
1317 &sid);
1318 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001319 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 isec->sid = sid;
1321 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001322 case SECURITY_FS_USE_MNTPOINT:
1323 isec->sid = sbsec->mntpoint_sid;
1324 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001326 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 isec->sid = sbsec->sid;
1328
Stephen Smalleyea6b1842008-09-22 15:41:19 -04001329 if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 struct proc_inode *proci = PROC_I(inode);
1331 if (proci->pde) {
1332 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1333 rc = selinux_proc_get_sid(proci->pde,
1334 isec->sclass,
1335 &sid);
1336 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001337 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 isec->sid = sid;
1339 }
1340 }
1341 break;
1342 }
1343
1344 isec->initialized = 1;
1345
Eric Paris23970742006-09-25 23:32:01 -07001346out_unlock:
1347 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348out:
1349 if (isec->sclass == SECCLASS_FILE)
1350 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return rc;
1352}
1353
1354/* Convert a Linux signal to an access vector. */
1355static inline u32 signal_to_av(int sig)
1356{
1357 u32 perm = 0;
1358
1359 switch (sig) {
1360 case SIGCHLD:
1361 /* Commonly granted from child to parent. */
1362 perm = PROCESS__SIGCHLD;
1363 break;
1364 case SIGKILL:
1365 /* Cannot be caught or ignored */
1366 perm = PROCESS__SIGKILL;
1367 break;
1368 case SIGSTOP:
1369 /* Cannot be caught or ignored */
1370 perm = PROCESS__SIGSTOP;
1371 break;
1372 default:
1373 /* All other signals. */
1374 perm = PROCESS__SIGNAL;
1375 break;
1376 }
1377
1378 return perm;
1379}
1380
David Howells275bb412008-11-14 10:39:19 +11001381/*
David Howells88e67f32008-11-14 10:39:21 +11001382 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001383 * fork check, ptrace check, etc.
1384 * tsk1 is the actor and tsk2 is the target
1385 */
1386static int task_has_perm(const struct task_struct *tsk1,
1387 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 u32 perms)
1389{
David Howells275bb412008-11-14 10:39:19 +11001390 const struct task_security_struct *__tsec1, *__tsec2;
1391 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
David Howells275bb412008-11-14 10:39:19 +11001393 rcu_read_lock();
1394 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1395 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1396 rcu_read_unlock();
1397 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398}
1399
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001400#if CAP_LAST_CAP > 63
1401#error Fix SELinux to handle capabilities > 63.
1402#endif
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404/* Check whether a task is allowed to use a capability. */
1405static int task_has_capability(struct task_struct *tsk,
Eric Paris06112162008-11-11 22:02:50 +11001406 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001409 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001410 u16 sclass;
David Howells275bb412008-11-14 10:39:19 +11001411 u32 sid = task_sid(tsk);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001412 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001413 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Eric Paris828dfe12008-04-17 13:17:49 -04001415 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 ad.tsk = tsk;
1417 ad.u.cap = cap;
1418
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001419 switch (CAP_TO_INDEX(cap)) {
1420 case 0:
1421 sclass = SECCLASS_CAPABILITY;
1422 break;
1423 case 1:
1424 sclass = SECCLASS_CAPABILITY2;
1425 break;
1426 default:
1427 printk(KERN_ERR
1428 "SELinux: out of range capability %d\n", cap);
1429 BUG();
1430 }
Eric Paris06112162008-11-11 22:02:50 +11001431
David Howells275bb412008-11-14 10:39:19 +11001432 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001433 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001434 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001435 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436}
1437
1438/* Check whether a task is allowed to use a system operation. */
1439static int task_has_system(struct task_struct *tsk,
1440 u32 perms)
1441{
David Howells275bb412008-11-14 10:39:19 +11001442 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
David Howells275bb412008-11-14 10:39:19 +11001444 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 SECCLASS_SYSTEM, perms, NULL);
1446}
1447
1448/* Check whether a task has a particular permission to an inode.
1449 The 'adp' parameter is optional and allows other audit
1450 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001451static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 struct inode *inode,
1453 u32 perms,
1454 struct avc_audit_data *adp)
1455{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 struct inode_security_struct *isec;
1457 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001458 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Eric Paris828dfe12008-04-17 13:17:49 -04001460 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001461 return 0;
1462
David Howells88e67f32008-11-14 10:39:21 +11001463 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 isec = inode->i_security;
1465
1466 if (!adp) {
1467 adp = &ad;
1468 AVC_AUDIT_DATA_INIT(&ad, FS);
1469 ad.u.fs.inode = inode;
1470 }
1471
David Howells275bb412008-11-14 10:39:19 +11001472 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473}
1474
1475/* Same as inode_has_perm, but pass explicit audit data containing
1476 the dentry to help the auditing code to more easily generate the
1477 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001478static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 struct vfsmount *mnt,
1480 struct dentry *dentry,
1481 u32 av)
1482{
1483 struct inode *inode = dentry->d_inode;
1484 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001485
Eric Paris828dfe12008-04-17 13:17:49 -04001486 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001487 ad.u.fs.path.mnt = mnt;
1488 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001489 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490}
1491
1492/* Check whether a task can use an open file descriptor to
1493 access an inode in a given way. Check access to the
1494 descriptor itself, and then use dentry_has_perm to
1495 check a particular permission to the file.
1496 Access to the descriptor is implicitly granted if it
1497 has the same SID as the process. If av is zero, then
1498 access to the file is not checked, e.g. for cases
1499 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001500static int file_has_perm(const struct cred *cred,
1501 struct file *file,
1502 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001505 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001507 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 int rc;
1509
1510 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001511 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
David Howells275bb412008-11-14 10:39:19 +11001513 if (sid != fsec->sid) {
1514 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 SECCLASS_FD,
1516 FD__USE,
1517 &ad);
1518 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001519 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 }
1521
1522 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001523 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001525 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
David Howells88e67f32008-11-14 10:39:21 +11001527out:
1528 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529}
1530
1531/* Check whether a task can create a file. */
1532static int may_create(struct inode *dir,
1533 struct dentry *dentry,
1534 u16 tclass)
1535{
David Howells275bb412008-11-14 10:39:19 +11001536 const struct cred *cred = current_cred();
1537 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 struct inode_security_struct *dsec;
1539 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001540 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 struct avc_audit_data ad;
1542 int rc;
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 dsec = dir->i_security;
1545 sbsec = dir->i_sb->s_security;
1546
David Howells275bb412008-11-14 10:39:19 +11001547 sid = tsec->sid;
1548 newsid = tsec->create_sid;
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001551 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
David Howells275bb412008-11-14 10:39:19 +11001553 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 DIR__ADD_NAME | DIR__SEARCH,
1555 &ad);
1556 if (rc)
1557 return rc;
1558
David Howells275bb412008-11-14 10:39:19 +11001559 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
1560 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 if (rc)
1562 return rc;
1563 }
1564
David Howells275bb412008-11-14 10:39:19 +11001565 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (rc)
1567 return rc;
1568
1569 return avc_has_perm(newsid, sbsec->sid,
1570 SECCLASS_FILESYSTEM,
1571 FILESYSTEM__ASSOCIATE, &ad);
1572}
1573
Michael LeMay4eb582c2006-06-26 00:24:57 -07001574/* Check whether a task can create a key. */
1575static int may_create_key(u32 ksid,
1576 struct task_struct *ctx)
1577{
David Howells275bb412008-11-14 10:39:19 +11001578 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001579
David Howells275bb412008-11-14 10:39:19 +11001580 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001581}
1582
Eric Paris828dfe12008-04-17 13:17:49 -04001583#define MAY_LINK 0
1584#define MAY_UNLINK 1
1585#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587/* Check whether a task can link, unlink, or rmdir a file/directory. */
1588static int may_link(struct inode *dir,
1589 struct dentry *dentry,
1590 int kind)
1591
1592{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 struct inode_security_struct *dsec, *isec;
1594 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001595 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 u32 av;
1597 int rc;
1598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 dsec = dir->i_security;
1600 isec = dentry->d_inode->i_security;
1601
1602 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001603 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 av = DIR__SEARCH;
1606 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001607 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (rc)
1609 return rc;
1610
1611 switch (kind) {
1612 case MAY_LINK:
1613 av = FILE__LINK;
1614 break;
1615 case MAY_UNLINK:
1616 av = FILE__UNLINK;
1617 break;
1618 case MAY_RMDIR:
1619 av = DIR__RMDIR;
1620 break;
1621 default:
Eric Paris744ba352008-04-17 11:52:44 -04001622 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1623 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 return 0;
1625 }
1626
David Howells275bb412008-11-14 10:39:19 +11001627 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 return rc;
1629}
1630
1631static inline int may_rename(struct inode *old_dir,
1632 struct dentry *old_dentry,
1633 struct inode *new_dir,
1634 struct dentry *new_dentry)
1635{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1637 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001638 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 u32 av;
1640 int old_is_dir, new_is_dir;
1641 int rc;
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 old_dsec = old_dir->i_security;
1644 old_isec = old_dentry->d_inode->i_security;
1645 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1646 new_dsec = new_dir->i_security;
1647
1648 AVC_AUDIT_DATA_INIT(&ad, FS);
1649
Jan Blunck44707fd2008-02-14 19:38:33 -08001650 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001651 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1653 if (rc)
1654 return rc;
David Howells275bb412008-11-14 10:39:19 +11001655 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 old_isec->sclass, FILE__RENAME, &ad);
1657 if (rc)
1658 return rc;
1659 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001660 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 old_isec->sclass, DIR__REPARENT, &ad);
1662 if (rc)
1663 return rc;
1664 }
1665
Jan Blunck44707fd2008-02-14 19:38:33 -08001666 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 av = DIR__ADD_NAME | DIR__SEARCH;
1668 if (new_dentry->d_inode)
1669 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001670 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (rc)
1672 return rc;
1673 if (new_dentry->d_inode) {
1674 new_isec = new_dentry->d_inode->i_security;
1675 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001676 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 new_isec->sclass,
1678 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1679 if (rc)
1680 return rc;
1681 }
1682
1683 return 0;
1684}
1685
1686/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001687static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 struct super_block *sb,
1689 u32 perms,
1690 struct avc_audit_data *ad)
1691{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001693 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001696 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697}
1698
1699/* Convert a Linux mode and permission mask to an access vector. */
1700static inline u32 file_mask_to_av(int mode, int mask)
1701{
1702 u32 av = 0;
1703
1704 if ((mode & S_IFMT) != S_IFDIR) {
1705 if (mask & MAY_EXEC)
1706 av |= FILE__EXECUTE;
1707 if (mask & MAY_READ)
1708 av |= FILE__READ;
1709
1710 if (mask & MAY_APPEND)
1711 av |= FILE__APPEND;
1712 else if (mask & MAY_WRITE)
1713 av |= FILE__WRITE;
1714
1715 } else {
1716 if (mask & MAY_EXEC)
1717 av |= DIR__SEARCH;
1718 if (mask & MAY_WRITE)
1719 av |= DIR__WRITE;
1720 if (mask & MAY_READ)
1721 av |= DIR__READ;
1722 }
1723
1724 return av;
1725}
1726
1727/* Convert a Linux file to an access vector. */
1728static inline u32 file_to_av(struct file *file)
1729{
1730 u32 av = 0;
1731
1732 if (file->f_mode & FMODE_READ)
1733 av |= FILE__READ;
1734 if (file->f_mode & FMODE_WRITE) {
1735 if (file->f_flags & O_APPEND)
1736 av |= FILE__APPEND;
1737 else
1738 av |= FILE__WRITE;
1739 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001740 if (!av) {
1741 /*
1742 * Special file opened with flags 3 for ioctl-only use.
1743 */
1744 av = FILE__IOCTL;
1745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 return av;
1748}
1749
Eric Paris8b6a5a32008-10-29 17:06:46 -04001750/*
1751 * Convert a file to an access vector and include the correct open
1752 * open permission.
1753 */
1754static inline u32 open_file_to_av(struct file *file)
1755{
1756 u32 av = file_to_av(file);
1757
1758 if (selinux_policycap_openperm) {
1759 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1760 /*
1761 * lnk files and socks do not really have an 'open'
1762 */
1763 if (S_ISREG(mode))
1764 av |= FILE__OPEN;
1765 else if (S_ISCHR(mode))
1766 av |= CHR_FILE__OPEN;
1767 else if (S_ISBLK(mode))
1768 av |= BLK_FILE__OPEN;
1769 else if (S_ISFIFO(mode))
1770 av |= FIFO_FILE__OPEN;
1771 else if (S_ISDIR(mode))
1772 av |= DIR__OPEN;
1773 else
1774 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1775 "unknown mode:%o\n", __func__, mode);
1776 }
1777 return av;
1778}
1779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780/* Hook functions begin here. */
1781
David Howells5cd9c582008-08-14 11:37:28 +01001782static int selinux_ptrace_may_access(struct task_struct *child,
1783 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 int rc;
1786
David Howells5cd9c582008-08-14 11:37:28 +01001787 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 if (rc)
1789 return rc;
1790
Stephen Smalley006ebb42008-05-19 08:32:49 -04001791 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001792 u32 sid = current_sid();
1793 u32 csid = task_sid(child);
1794 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001795 }
1796
David Howells5cd9c582008-08-14 11:37:28 +01001797 return task_has_perm(current, child, PROCESS__PTRACE);
1798}
1799
1800static int selinux_ptrace_traceme(struct task_struct *parent)
1801{
1802 int rc;
1803
1804 rc = secondary_ops->ptrace_traceme(parent);
1805 if (rc)
1806 return rc;
1807
1808 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809}
1810
1811static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001812 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813{
1814 int error;
1815
1816 error = task_has_perm(current, target, PROCESS__GETCAP);
1817 if (error)
1818 return error;
1819
1820 return secondary_ops->capget(target, effective, inheritable, permitted);
1821}
1822
David Howells15a24602008-11-14 10:39:15 +11001823static int selinux_capset_check(const kernel_cap_t *effective,
1824 const kernel_cap_t *inheritable,
1825 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826{
1827 int error;
1828
David Howells1cdcbec2008-11-14 10:39:14 +11001829 error = secondary_ops->capset_check(effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 if (error)
1831 return error;
1832
David Howells1cdcbec2008-11-14 10:39:14 +11001833 return task_has_perm(current, current, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834}
1835
David Howells15a24602008-11-14 10:39:15 +11001836static void selinux_capset_set(const kernel_cap_t *effective,
1837 const kernel_cap_t *inheritable,
1838 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839{
David Howells1cdcbec2008-11-14 10:39:14 +11001840 secondary_ops->capset_set(effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841}
1842
Eric Paris06112162008-11-11 22:02:50 +11001843static int selinux_capable(struct task_struct *tsk, int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844{
1845 int rc;
1846
Eric Paris06112162008-11-11 22:02:50 +11001847 rc = secondary_ops->capable(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 if (rc)
1849 return rc;
1850
Eric Paris06112162008-11-11 22:02:50 +11001851 return task_has_capability(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852}
1853
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001854static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1855{
1856 int buflen, rc;
1857 char *buffer, *path, *end;
1858
1859 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001860 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001861 if (!buffer)
1862 goto out;
1863
1864 buflen = PAGE_SIZE;
1865 end = buffer+buflen;
1866 *--end = '\0';
1867 buflen--;
1868 path = end-1;
1869 *path = '/';
1870 while (table) {
1871 const char *name = table->procname;
1872 size_t namelen = strlen(name);
1873 buflen -= namelen + 1;
1874 if (buflen < 0)
1875 goto out_free;
1876 end -= namelen;
1877 memcpy(end, name, namelen);
1878 *--end = '/';
1879 path = end;
1880 table = table->parent;
1881 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001882 buflen -= 4;
1883 if (buflen < 0)
1884 goto out_free;
1885 end -= 4;
1886 memcpy(end, "/sys", 4);
1887 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001888 rc = security_genfs_sid("proc", path, tclass, sid);
1889out_free:
1890 free_page((unsigned long)buffer);
1891out:
1892 return rc;
1893}
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895static int selinux_sysctl(ctl_table *table, int op)
1896{
1897 int error = 0;
1898 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001899 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 int rc;
1901
1902 rc = secondary_ops->sysctl(table, op);
1903 if (rc)
1904 return rc;
1905
David Howells275bb412008-11-14 10:39:19 +11001906 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001908 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1909 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (rc) {
1911 /* Default to the well-defined sysctl SID. */
1912 tsid = SECINITSID_SYSCTL;
1913 }
1914
1915 /* The op values are "defined" in sysctl.c, thereby creating
1916 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001917 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11001918 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 SECCLASS_DIR, DIR__SEARCH, NULL);
1920 } else {
1921 av = 0;
1922 if (op & 004)
1923 av |= FILE__READ;
1924 if (op & 002)
1925 av |= FILE__WRITE;
1926 if (av)
David Howells275bb412008-11-14 10:39:19 +11001927 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931 return error;
1932}
1933
1934static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1935{
David Howells88e67f32008-11-14 10:39:21 +11001936 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 int rc = 0;
1938
1939 if (!sb)
1940 return 0;
1941
1942 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001943 case Q_SYNC:
1944 case Q_QUOTAON:
1945 case Q_QUOTAOFF:
1946 case Q_SETINFO:
1947 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001948 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001949 break;
1950 case Q_GETFMT:
1951 case Q_GETINFO:
1952 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001953 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001954 break;
1955 default:
1956 rc = 0; /* let the kernel handle invalid cmds */
1957 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 }
1959 return rc;
1960}
1961
1962static int selinux_quota_on(struct dentry *dentry)
1963{
David Howells88e67f32008-11-14 10:39:21 +11001964 const struct cred *cred = current_cred();
1965
1966 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967}
1968
1969static int selinux_syslog(int type)
1970{
1971 int rc;
1972
1973 rc = secondary_ops->syslog(type);
1974 if (rc)
1975 return rc;
1976
1977 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04001978 case 3: /* Read last kernel messages */
1979 case 10: /* Return size of the log buffer */
1980 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1981 break;
1982 case 6: /* Disable logging to console */
1983 case 7: /* Enable logging to console */
1984 case 8: /* Set level of messages printed to console */
1985 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1986 break;
1987 case 0: /* Close log */
1988 case 1: /* Open log */
1989 case 2: /* Read from log */
1990 case 4: /* Read/clear last kernel messages */
1991 case 5: /* Clear ring buffer */
1992 default:
1993 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1994 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 }
1996 return rc;
1997}
1998
1999/*
2000 * Check that a process has enough memory to allocate a new virtual
2001 * mapping. 0 means there is enough memory for the allocation to
2002 * succeed and -ENOMEM implies there is not.
2003 *
2004 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
2005 * if the capability is granted, but __vm_enough_memory requires 1 if
2006 * the capability is granted.
2007 *
2008 * Do not audit the selinux permission check, as this is applied to all
2009 * processes that allocate mappings.
2010 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002011static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012{
2013 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Eric Paris06674672008-11-11 22:02:57 +11002015 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 if (rc == 0)
2017 cap_sys_admin = 1;
2018
Alan Cox34b4e4a2007-08-22 14:01:28 -07002019 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020}
2021
2022/* binprm security operations */
2023
2024static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
2025{
2026 struct bprm_security_struct *bsec;
2027
James Morris89d155e2005-10-30 14:59:21 -08002028 bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 if (!bsec)
2030 return -ENOMEM;
2031
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 bsec->sid = SECINITSID_UNLABELED;
2033 bsec->set = 0;
2034
2035 bprm->security = bsec;
2036 return 0;
2037}
2038
2039static int selinux_bprm_set_security(struct linux_binprm *bprm)
2040{
2041 struct task_security_struct *tsec;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002042 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 struct inode_security_struct *isec;
2044 struct bprm_security_struct *bsec;
2045 u32 newsid;
2046 struct avc_audit_data ad;
2047 int rc;
2048
2049 rc = secondary_ops->bprm_set_security(bprm);
2050 if (rc)
2051 return rc;
2052
2053 bsec = bprm->security;
2054
2055 if (bsec->set)
2056 return 0;
2057
David Howells275bb412008-11-14 10:39:19 +11002058 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 isec = inode->i_security;
2060
2061 /* Default to the current task SID. */
2062 bsec->sid = tsec->sid;
2063
Michael LeMay28eba5b2006-06-27 02:53:42 -07002064 /* Reset fs, key, and sock SIDs on execve. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 tsec->create_sid = 0;
Michael LeMay28eba5b2006-06-27 02:53:42 -07002066 tsec->keycreate_sid = 0;
Eric Paris42c3e032006-06-26 00:26:03 -07002067 tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 if (tsec->exec_sid) {
2070 newsid = tsec->exec_sid;
2071 /* Reset exec SID on execve. */
2072 tsec->exec_sid = 0;
2073 } else {
2074 /* Check for a default transition on this program. */
2075 rc = security_transition_sid(tsec->sid, isec->sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002076 SECCLASS_PROCESS, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 if (rc)
2078 return rc;
2079 }
2080
2081 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002082 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
Josef Sipek3d5ff522006-12-08 02:37:38 -08002084 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 newsid = tsec->sid;
2086
Eric Paris828dfe12008-04-17 13:17:49 -04002087 if (tsec->sid == newsid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 rc = avc_has_perm(tsec->sid, isec->sid,
2089 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2090 if (rc)
2091 return rc;
2092 } else {
2093 /* Check permissions for the transition. */
2094 rc = avc_has_perm(tsec->sid, newsid,
2095 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2096 if (rc)
2097 return rc;
2098
2099 rc = avc_has_perm(newsid, isec->sid,
2100 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2101 if (rc)
2102 return rc;
2103
2104 /* Clear any possibly unsafe personality bits on exec: */
2105 current->personality &= ~PER_CLEAR_ON_SETID;
2106
2107 /* Set the security field to the new SID. */
2108 bsec->sid = newsid;
2109 }
2110
2111 bsec->set = 1;
2112 return 0;
2113}
2114
Eric Paris828dfe12008-04-17 13:17:49 -04002115static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116{
2117 return secondary_ops->bprm_check_security(bprm);
2118}
2119
2120
Eric Paris828dfe12008-04-17 13:17:49 -04002121static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
David Howells275bb412008-11-14 10:39:19 +11002123 const struct cred *cred = current_cred();
2124 const struct task_security_struct *tsec = cred->security;
2125 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 int atsecure = 0;
2127
David Howells275bb412008-11-14 10:39:19 +11002128 sid = tsec->sid;
2129 osid = tsec->osid;
2130
2131 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 /* Enable secure mode for SIDs transitions unless
2133 the noatsecure permission is granted between
2134 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002135 atsecure = avc_has_perm(osid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 SECCLASS_PROCESS,
2137 PROCESS__NOATSECURE, NULL);
2138 }
2139
2140 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2141}
2142
2143static void selinux_bprm_free_security(struct linux_binprm *bprm)
2144{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07002145 kfree(bprm->security);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 bprm->security = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147}
2148
2149extern struct vfsmount *selinuxfs_mount;
2150extern struct dentry *selinux_null;
2151
2152/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002153static inline void flush_unauthorized_files(const struct cred *cred,
2154 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155{
2156 struct avc_audit_data ad;
2157 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002158 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002159 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002161 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002163 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (tty) {
2165 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002166 if (!list_empty(&tty->tty_files)) {
2167 struct inode *inode;
2168
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 /* Revalidate access to controlling tty.
2170 Use inode_has_perm on the tty inode directly rather
2171 than using file_has_perm, as this particular open
2172 file may belong to another process and we are only
2173 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002174 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2175 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002176 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002178 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 }
2180 }
2181 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002182 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002184 /* Reset controlling tty. */
2185 if (drop_tty)
2186 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
2188 /* Revalidate access to inherited open files. */
2189
Eric Paris828dfe12008-04-17 13:17:49 -04002190 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
2192 spin_lock(&files->file_lock);
2193 for (;;) {
2194 unsigned long set, i;
2195 int fd;
2196
2197 j++;
2198 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002199 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002200 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002202 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 if (!set)
2204 continue;
2205 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002206 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 if (set & 1) {
2208 file = fget(i);
2209 if (!file)
2210 continue;
David Howells88e67f32008-11-14 10:39:21 +11002211 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 file,
2213 file_to_av(file))) {
2214 sys_close(i);
2215 fd = get_unused_fd();
2216 if (fd != i) {
2217 if (fd >= 0)
2218 put_unused_fd(fd);
2219 fput(file);
2220 continue;
2221 }
2222 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002223 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 } else {
David Howells745ca242008-11-14 10:39:22 +11002225 devnull = dentry_open(
2226 dget(selinux_null),
2227 mntget(selinuxfs_mount),
2228 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002229 if (IS_ERR(devnull)) {
2230 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 put_unused_fd(fd);
2232 fput(file);
2233 continue;
2234 }
2235 }
2236 fd_install(fd, devnull);
2237 }
2238 fput(file);
2239 }
2240 }
2241 spin_lock(&files->file_lock);
2242
2243 }
2244 spin_unlock(&files->file_lock);
2245}
2246
2247static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
2248{
2249 struct task_security_struct *tsec;
2250 struct bprm_security_struct *bsec;
2251 u32 sid;
2252 int rc;
2253
2254 secondary_ops->bprm_apply_creds(bprm, unsafe);
2255
David Howells275bb412008-11-14 10:39:19 +11002256 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
2258 bsec = bprm->security;
2259 sid = bsec->sid;
2260
2261 tsec->osid = tsec->sid;
2262 bsec->unsafe = 0;
2263 if (tsec->sid != sid) {
2264 /* Check for shared state. If not ok, leave SID
2265 unchanged and kill. */
2266 if (unsafe & LSM_UNSAFE_SHARE) {
2267 rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
2268 PROCESS__SHARE, NULL);
2269 if (rc) {
2270 bsec->unsafe = 1;
2271 return;
2272 }
2273 }
2274
2275 /* Check for ptracing, and update the task SID if ok.
2276 Otherwise, leave SID unchanged and kill. */
2277 if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
Roland McGrath03563572008-03-26 15:46:39 -07002278 struct task_struct *tracer;
2279 struct task_security_struct *sec;
2280 u32 ptsid = 0;
2281
2282 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07002283 tracer = tracehook_tracer_task(current);
Roland McGrath03563572008-03-26 15:46:39 -07002284 if (likely(tracer != NULL)) {
David Howells275bb412008-11-14 10:39:19 +11002285 sec = __task_cred(tracer)->security;
Roland McGrath03563572008-03-26 15:46:39 -07002286 ptsid = sec->sid;
2287 }
2288 rcu_read_unlock();
2289
2290 if (ptsid != 0) {
2291 rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
2292 PROCESS__PTRACE, NULL);
2293 if (rc) {
2294 bsec->unsafe = 1;
2295 return;
2296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 }
2298 }
2299 tsec->sid = sid;
2300 }
2301}
2302
2303/*
2304 * called after apply_creds without the task lock held
2305 */
2306static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
2307{
David Howells745ca242008-11-14 10:39:22 +11002308 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 struct task_security_struct *tsec;
2310 struct rlimit *rlim, *initrlim;
2311 struct itimerval itimer;
2312 struct bprm_security_struct *bsec;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002313 struct sighand_struct *psig;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 int rc, i;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002315 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
David Howells275bb412008-11-14 10:39:19 +11002317 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 bsec = bprm->security;
2319
2320 if (bsec->unsafe) {
2321 force_sig_specific(SIGKILL, current);
2322 return;
2323 }
2324 if (tsec->osid == tsec->sid)
2325 return;
2326
2327 /* Close files for which the new task SID is not authorized. */
David Howells745ca242008-11-14 10:39:22 +11002328 flush_unauthorized_files(cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
2330 /* Check whether the new SID can inherit signal state
2331 from the old SID. If not, clear itimers to avoid
2332 subsequent signal generation and flush and unblock
2333 signals. This must occur _after_ the task SID has
2334 been updated so that any kill done after the flush
2335 will be checked against the new SID. */
2336 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2337 PROCESS__SIGINH, NULL);
2338 if (rc) {
2339 memset(&itimer, 0, sizeof itimer);
2340 for (i = 0; i < 3; i++)
2341 do_setitimer(i, &itimer, NULL);
2342 flush_signals(current);
2343 spin_lock_irq(&current->sighand->siglock);
2344 flush_signal_handlers(current, 1);
2345 sigemptyset(&current->blocked);
2346 recalc_sigpending();
2347 spin_unlock_irq(&current->sighand->siglock);
2348 }
2349
Stephen Smalley4ac212a2007-08-29 08:51:50 -04002350 /* Always clear parent death signal on SID transitions. */
2351 current->pdeath_signal = 0;
2352
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 /* Check whether the new SID can inherit resource limits
2354 from the old SID. If not, reset all soft limits to
2355 the lower of the current task's hard limit and the init
2356 task's soft limit. Note that the setting of hard limits
2357 (even to lower them) can be controlled by the setrlimit
2358 check. The inclusion of the init task's soft limit into
2359 the computation is to avoid resetting soft limits higher
2360 than the default soft limit for cases where the default
2361 is lower than the hard limit, e.g. RLIMIT_CORE or
2362 RLIMIT_STACK.*/
2363 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2364 PROCESS__RLIMITINH, NULL);
2365 if (rc) {
2366 for (i = 0; i < RLIM_NLIMITS; i++) {
2367 rlim = current->signal->rlim + i;
2368 initrlim = init_task.signal->rlim+i;
Eric Paris828dfe12008-04-17 13:17:49 -04002369 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 }
Frank Mayharf06febc2008-09-12 09:54:39 -07002371 update_rlimit_cpu(rlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 }
2373
2374 /* Wake up the parent if it is waiting so that it can
2375 recheck wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002376 read_lock_irq(&tasklist_lock);
2377 psig = current->parent->sighand;
2378 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002380 spin_unlock_irqrestore(&psig->siglock, flags);
2381 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382}
2383
2384/* superblock security operations */
2385
2386static int selinux_sb_alloc_security(struct super_block *sb)
2387{
2388 return superblock_alloc_security(sb);
2389}
2390
2391static void selinux_sb_free_security(struct super_block *sb)
2392{
2393 superblock_free_security(sb);
2394}
2395
2396static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2397{
2398 if (plen > olen)
2399 return 0;
2400
2401 return !memcmp(prefix, option, plen);
2402}
2403
2404static inline int selinux_option(char *option, int len)
2405{
Eric Paris832cbd92008-04-01 13:24:09 -04002406 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2407 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2408 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2409 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410}
2411
2412static inline void take_option(char **to, char *from, int *first, int len)
2413{
2414 if (!*first) {
2415 **to = ',';
2416 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002417 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 *first = 0;
2419 memcpy(*to, from, len);
2420 *to += len;
2421}
2422
Eric Paris828dfe12008-04-17 13:17:49 -04002423static inline void take_selinux_option(char **to, char *from, int *first,
2424 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002425{
2426 int current_size = 0;
2427
2428 if (!*first) {
2429 **to = '|';
2430 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002431 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002432 *first = 0;
2433
2434 while (current_size < len) {
2435 if (*from != '"') {
2436 **to = *from;
2437 *to += 1;
2438 }
2439 from += 1;
2440 current_size += 1;
2441 }
2442}
2443
Eric Parise0007522008-03-05 10:31:54 -05002444static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445{
2446 int fnosec, fsec, rc = 0;
2447 char *in_save, *in_curr, *in_end;
2448 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002449 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 in_curr = orig;
2452 sec_curr = copy;
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2455 if (!nosec) {
2456 rc = -ENOMEM;
2457 goto out;
2458 }
2459
2460 nosec_save = nosec;
2461 fnosec = fsec = 1;
2462 in_save = in_end = orig;
2463
2464 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002465 if (*in_end == '"')
2466 open_quote = !open_quote;
2467 if ((*in_end == ',' && open_quote == 0) ||
2468 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 int len = in_end - in_curr;
2470
2471 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002472 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 else
2474 take_option(&nosec, in_curr, &fnosec, len);
2475
2476 in_curr = in_end + 1;
2477 }
2478 } while (*in_end++);
2479
Eric Paris6931dfc2005-06-30 02:58:51 -07002480 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002481 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482out:
2483 return rc;
2484}
2485
2486static int selinux_sb_kern_mount(struct super_block *sb, void *data)
2487{
David Howells88e67f32008-11-14 10:39:21 +11002488 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 struct avc_audit_data ad;
2490 int rc;
2491
2492 rc = superblock_doinit(sb, data);
2493 if (rc)
2494 return rc;
2495
Eric Paris828dfe12008-04-17 13:17:49 -04002496 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002497 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002498 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499}
2500
David Howells726c3342006-06-23 02:02:58 -07002501static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502{
David Howells88e67f32008-11-14 10:39:21 +11002503 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 struct avc_audit_data ad;
2505
Eric Paris828dfe12008-04-17 13:17:49 -04002506 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002507 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002508 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509}
2510
Eric Paris828dfe12008-04-17 13:17:49 -04002511static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002512 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002513 char *type,
2514 unsigned long flags,
2515 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516{
David Howells88e67f32008-11-14 10:39:21 +11002517 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 int rc;
2519
Al Virob5266eb2008-03-22 17:48:24 -04002520 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (rc)
2522 return rc;
2523
2524 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002525 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002526 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 else
David Howells88e67f32008-11-14 10:39:21 +11002528 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002529 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530}
2531
2532static int selinux_umount(struct vfsmount *mnt, int flags)
2533{
David Howells88e67f32008-11-14 10:39:21 +11002534 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 int rc;
2536
2537 rc = secondary_ops->sb_umount(mnt, flags);
2538 if (rc)
2539 return rc;
2540
David Howells88e67f32008-11-14 10:39:21 +11002541 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002542 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543}
2544
2545/* inode security operations */
2546
2547static int selinux_inode_alloc_security(struct inode *inode)
2548{
2549 return inode_alloc_security(inode);
2550}
2551
2552static void selinux_inode_free_security(struct inode *inode)
2553{
2554 inode_free_security(inode);
2555}
2556
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002557static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2558 char **name, void **value,
2559 size_t *len)
2560{
David Howells275bb412008-11-14 10:39:19 +11002561 const struct cred *cred = current_cred();
2562 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002563 struct inode_security_struct *dsec;
2564 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002565 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002566 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002567 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002568
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002569 dsec = dir->i_security;
2570 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002571
David Howells275bb412008-11-14 10:39:19 +11002572 sid = tsec->sid;
2573 newsid = tsec->create_sid;
2574
2575 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
2576 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002577 inode_mode_to_security_class(inode->i_mode),
2578 &newsid);
2579 if (rc) {
2580 printk(KERN_WARNING "%s: "
2581 "security_transition_sid failed, rc=%d (dev=%s "
2582 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002583 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002584 -rc, inode->i_sb->s_id, inode->i_ino);
2585 return rc;
2586 }
2587 }
2588
Eric Paris296fddf2006-09-25 23:32:00 -07002589 /* Possibly defer initialization to selinux_complete_init. */
2590 if (sbsec->initialized) {
2591 struct inode_security_struct *isec = inode->i_security;
2592 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2593 isec->sid = newsid;
2594 isec->initialized = 1;
2595 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002596
Stephen Smalley8aad3872006-03-22 00:09:13 -08002597 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002598 return -EOPNOTSUPP;
2599
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002600 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002601 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002602 if (!namep)
2603 return -ENOMEM;
2604 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002605 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002606
2607 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002608 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002609 if (rc) {
2610 kfree(namep);
2611 return rc;
2612 }
2613 *value = context;
2614 *len = clen;
2615 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002616
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002617 return 0;
2618}
2619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2621{
2622 return may_create(dir, dentry, SECCLASS_FILE);
2623}
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2626{
2627 int rc;
2628
Eric Paris828dfe12008-04-17 13:17:49 -04002629 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 if (rc)
2631 return rc;
2632 return may_link(dir, old_dentry, MAY_LINK);
2633}
2634
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2636{
2637 int rc;
2638
2639 rc = secondary_ops->inode_unlink(dir, dentry);
2640 if (rc)
2641 return rc;
2642 return may_link(dir, dentry, MAY_UNLINK);
2643}
2644
2645static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2646{
2647 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2648}
2649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2651{
2652 return may_create(dir, dentry, SECCLASS_DIR);
2653}
2654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2656{
2657 return may_link(dir, dentry, MAY_RMDIR);
2658}
2659
2660static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2661{
2662 int rc;
2663
2664 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2665 if (rc)
2666 return rc;
2667
2668 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2669}
2670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002672 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673{
2674 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2675}
2676
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677static int selinux_inode_readlink(struct dentry *dentry)
2678{
David Howells88e67f32008-11-14 10:39:21 +11002679 const struct cred *cred = current_cred();
2680
2681 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682}
2683
2684static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2685{
David Howells88e67f32008-11-14 10:39:21 +11002686 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 int rc;
2688
Eric Paris828dfe12008-04-17 13:17:49 -04002689 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 if (rc)
2691 return rc;
David Howells88e67f32008-11-14 10:39:21 +11002692 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693}
2694
Al Virob77b0642008-07-17 09:37:02 -04002695static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696{
David Howells88e67f32008-11-14 10:39:21 +11002697 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 int rc;
2699
Al Virob77b0642008-07-17 09:37:02 -04002700 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 if (rc)
2702 return rc;
2703
2704 if (!mask) {
2705 /* No permission to check. Existence test. */
2706 return 0;
2707 }
2708
David Howells88e67f32008-11-14 10:39:21 +11002709 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002710 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711}
2712
2713static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2714{
David Howells88e67f32008-11-14 10:39:21 +11002715 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 int rc;
2717
2718 rc = secondary_ops->inode_setattr(dentry, iattr);
2719 if (rc)
2720 return rc;
2721
2722 if (iattr->ia_valid & ATTR_FORCE)
2723 return 0;
2724
2725 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2726 ATTR_ATIME_SET | ATTR_MTIME_SET))
David Howells88e67f32008-11-14 10:39:21 +11002727 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
David Howells88e67f32008-11-14 10:39:21 +11002729 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730}
2731
2732static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2733{
David Howells88e67f32008-11-14 10:39:21 +11002734 const struct cred *cred = current_cred();
2735
2736 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737}
2738
David Howells8f0cfa52008-04-29 00:59:41 -07002739static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002740{
David Howells88e67f32008-11-14 10:39:21 +11002741 const struct cred *cred = current_cred();
2742
Serge E. Hallynb5376772007-10-16 23:31:36 -07002743 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2744 sizeof XATTR_SECURITY_PREFIX - 1)) {
2745 if (!strcmp(name, XATTR_NAME_CAPS)) {
2746 if (!capable(CAP_SETFCAP))
2747 return -EPERM;
2748 } else if (!capable(CAP_SYS_ADMIN)) {
2749 /* A different attribute in the security namespace.
2750 Restrict to administrator. */
2751 return -EPERM;
2752 }
2753 }
2754
2755 /* Not an attribute we recognize, so just check the
2756 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002757 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002758}
2759
David Howells8f0cfa52008-04-29 00:59:41 -07002760static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2761 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 struct inode *inode = dentry->d_inode;
2764 struct inode_security_struct *isec = inode->i_security;
2765 struct superblock_security_struct *sbsec;
2766 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002767 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 int rc = 0;
2769
Serge E. Hallynb5376772007-10-16 23:31:36 -07002770 if (strcmp(name, XATTR_NAME_SELINUX))
2771 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
2773 sbsec = inode->i_sb->s_security;
2774 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2775 return -EOPNOTSUPP;
2776
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302777 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return -EPERM;
2779
Eric Paris828dfe12008-04-17 13:17:49 -04002780 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002781 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
David Howells275bb412008-11-14 10:39:19 +11002783 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 FILE__RELABELFROM, &ad);
2785 if (rc)
2786 return rc;
2787
2788 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002789 if (rc == -EINVAL) {
2790 if (!capable(CAP_MAC_ADMIN))
2791 return rc;
2792 rc = security_context_to_sid_force(value, size, &newsid);
2793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 if (rc)
2795 return rc;
2796
David Howells275bb412008-11-14 10:39:19 +11002797 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 FILE__RELABELTO, &ad);
2799 if (rc)
2800 return rc;
2801
David Howells275bb412008-11-14 10:39:19 +11002802 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002803 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 if (rc)
2805 return rc;
2806
2807 return avc_has_perm(newsid,
2808 sbsec->sid,
2809 SECCLASS_FILESYSTEM,
2810 FILESYSTEM__ASSOCIATE,
2811 &ad);
2812}
2813
David Howells8f0cfa52008-04-29 00:59:41 -07002814static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002815 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002816 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817{
2818 struct inode *inode = dentry->d_inode;
2819 struct inode_security_struct *isec = inode->i_security;
2820 u32 newsid;
2821 int rc;
2822
2823 if (strcmp(name, XATTR_NAME_SELINUX)) {
2824 /* Not an attribute we recognize, so nothing to do. */
2825 return;
2826 }
2827
Stephen Smalley12b29f32008-05-07 13:03:20 -04002828 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002830 printk(KERN_ERR "SELinux: unable to map context to SID"
2831 "for (%s, %lu), rc=%d\n",
2832 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 return;
2834 }
2835
2836 isec->sid = newsid;
2837 return;
2838}
2839
David Howells8f0cfa52008-04-29 00:59:41 -07002840static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841{
David Howells88e67f32008-11-14 10:39:21 +11002842 const struct cred *cred = current_cred();
2843
2844 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845}
2846
Eric Paris828dfe12008-04-17 13:17:49 -04002847static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
David Howells88e67f32008-11-14 10:39:21 +11002849 const struct cred *cred = current_cred();
2850
2851 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852}
2853
David Howells8f0cfa52008-04-29 00:59:41 -07002854static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002856 if (strcmp(name, XATTR_NAME_SELINUX))
2857 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859 /* No one is allowed to remove a SELinux security label.
2860 You can change the label, but all data must be labeled. */
2861 return -EACCES;
2862}
2863
James Morrisd381d8a2005-10-30 14:59:22 -08002864/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002865 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002866 *
2867 * Permission check is handled by selinux_inode_getxattr hook.
2868 */
David P. Quigley42492592008-02-04 22:29:39 -08002869static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870{
David P. Quigley42492592008-02-04 22:29:39 -08002871 u32 size;
2872 int error;
2873 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002876 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2877 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002879 /*
2880 * If the caller has CAP_MAC_ADMIN, then get the raw context
2881 * value even if it is not defined by current policy; otherwise,
2882 * use the in-core value under current policy.
2883 * Use the non-auditing forms of the permission checks since
2884 * getxattr may be called by unprivileged processes commonly
2885 * and lack of permission just means that we fall back to the
2886 * in-core context value, not a denial.
2887 */
Eric Paris06674672008-11-11 22:02:57 +11002888 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002889 if (!error)
2890 error = security_sid_to_context_force(isec->sid, &context,
2891 &size);
2892 else
2893 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002894 if (error)
2895 return error;
2896 error = size;
2897 if (alloc) {
2898 *buffer = context;
2899 goto out_nofree;
2900 }
2901 kfree(context);
2902out_nofree:
2903 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904}
2905
2906static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002907 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908{
2909 struct inode_security_struct *isec = inode->i_security;
2910 u32 newsid;
2911 int rc;
2912
2913 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2914 return -EOPNOTSUPP;
2915
2916 if (!value || !size)
2917 return -EACCES;
2918
Eric Paris828dfe12008-04-17 13:17:49 -04002919 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 if (rc)
2921 return rc;
2922
2923 isec->sid = newsid;
2924 return 0;
2925}
2926
2927static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2928{
2929 const int len = sizeof(XATTR_NAME_SELINUX);
2930 if (buffer && len <= buffer_size)
2931 memcpy(buffer, XATTR_NAME_SELINUX, len);
2932 return len;
2933}
2934
Serge E. Hallynb5376772007-10-16 23:31:36 -07002935static int selinux_inode_need_killpriv(struct dentry *dentry)
2936{
2937 return secondary_ops->inode_need_killpriv(dentry);
2938}
2939
2940static int selinux_inode_killpriv(struct dentry *dentry)
2941{
2942 return secondary_ops->inode_killpriv(dentry);
2943}
2944
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02002945static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2946{
2947 struct inode_security_struct *isec = inode->i_security;
2948 *secid = isec->sid;
2949}
2950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951/* file security operations */
2952
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002953static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954{
David Howells88e67f32008-11-14 10:39:21 +11002955 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002956 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002957 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
2959 if (!mask) {
2960 /* No permission to check. Existence test. */
2961 return 0;
2962 }
2963
2964 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2965 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2966 mask |= MAY_APPEND;
2967
David Howells88e67f32008-11-14 10:39:21 +11002968 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002969 file_mask_to_av(inode->i_mode, mask));
2970 if (rc)
2971 return rc;
2972
2973 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974}
2975
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002976static int selinux_file_permission(struct file *file, int mask)
2977{
2978 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002979 struct file_security_struct *fsec = file->f_security;
2980 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11002981 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002982
2983 if (!mask) {
2984 /* No permission to check. Existence test. */
2985 return 0;
2986 }
2987
David Howells275bb412008-11-14 10:39:19 +11002988 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002989 && fsec->pseqno == avc_policy_seqno())
2990 return selinux_netlbl_inode_permission(inode, mask);
2991
2992 return selinux_revalidate_file_permission(file, mask);
2993}
2994
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995static int selinux_file_alloc_security(struct file *file)
2996{
2997 return file_alloc_security(file);
2998}
2999
3000static void selinux_file_free_security(struct file *file)
3001{
3002 file_free_security(file);
3003}
3004
3005static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3006 unsigned long arg)
3007{
David Howells88e67f32008-11-14 10:39:21 +11003008 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04003009 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
Stephen Smalley242631c2008-06-05 09:21:28 -04003011 if (_IOC_DIR(cmd) & _IOC_WRITE)
3012 av |= FILE__WRITE;
3013 if (_IOC_DIR(cmd) & _IOC_READ)
3014 av |= FILE__READ;
3015 if (!av)
3016 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
David Howells88e67f32008-11-14 10:39:21 +11003018 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019}
3020
3021static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3022{
David Howells88e67f32008-11-14 10:39:21 +11003023 const struct cred *cred = current_cred();
3024
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025#ifndef CONFIG_PPC32
3026 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3027 /*
3028 * We are making executable an anonymous mapping or a
3029 * private file mapping that will also be writable.
3030 * This has an additional check.
3031 */
3032 int rc = task_has_perm(current, current, PROCESS__EXECMEM);
3033 if (rc)
3034 return rc;
3035 }
3036#endif
3037
3038 if (file) {
3039 /* read access is always possible with a mapping */
3040 u32 av = FILE__READ;
3041
3042 /* write access only matters if the mapping is shared */
3043 if (shared && (prot & PROT_WRITE))
3044 av |= FILE__WRITE;
3045
3046 if (prot & PROT_EXEC)
3047 av |= FILE__EXECUTE;
3048
David Howells88e67f32008-11-14 10:39:21 +11003049 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 }
3051 return 0;
3052}
3053
3054static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003055 unsigned long prot, unsigned long flags,
3056 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057{
Eric Parised032182007-06-28 15:55:21 -04003058 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003059 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
Eric Parised032182007-06-28 15:55:21 -04003061 if (addr < mmap_min_addr)
3062 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3063 MEMPROTECT__MMAP_ZERO, NULL);
3064 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 return rc;
3066
3067 if (selinux_checkreqprot)
3068 prot = reqprot;
3069
3070 return file_map_prot_check(file, prot,
3071 (flags & MAP_TYPE) == MAP_SHARED);
3072}
3073
3074static int selinux_file_mprotect(struct vm_area_struct *vma,
3075 unsigned long reqprot,
3076 unsigned long prot)
3077{
David Howells88e67f32008-11-14 10:39:21 +11003078 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 int rc;
3080
3081 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3082 if (rc)
3083 return rc;
3084
3085 if (selinux_checkreqprot)
3086 prot = reqprot;
3087
3088#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003089 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3090 rc = 0;
3091 if (vma->vm_start >= vma->vm_mm->start_brk &&
3092 vma->vm_end <= vma->vm_mm->brk) {
3093 rc = task_has_perm(current, current,
3094 PROCESS__EXECHEAP);
3095 } else if (!vma->vm_file &&
3096 vma->vm_start <= vma->vm_mm->start_stack &&
3097 vma->vm_end >= vma->vm_mm->start_stack) {
3098 rc = task_has_perm(current, current, PROCESS__EXECSTACK);
3099 } else if (vma->vm_file && vma->anon_vma) {
3100 /*
3101 * We are making executable a file mapping that has
3102 * had some COW done. Since pages might have been
3103 * written, check ability to execute the possibly
3104 * modified content. This typically should only
3105 * occur for text relocations.
3106 */
David Howells88e67f32008-11-14 10:39:21 +11003107 rc = file_has_perm(cred, vma->vm_file,
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003108 FILE__EXECMOD);
3109 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003110 if (rc)
3111 return rc;
3112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113#endif
3114
3115 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3116}
3117
3118static int selinux_file_lock(struct file *file, unsigned int cmd)
3119{
David Howells88e67f32008-11-14 10:39:21 +11003120 const struct cred *cred = current_cred();
3121
3122 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123}
3124
3125static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3126 unsigned long arg)
3127{
David Howells88e67f32008-11-14 10:39:21 +11003128 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 int err = 0;
3130
3131 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003132 case F_SETFL:
3133 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3134 err = -EINVAL;
3135 break;
3136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
Eric Paris828dfe12008-04-17 13:17:49 -04003138 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003139 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003141 }
3142 /* fall through */
3143 case F_SETOWN:
3144 case F_SETSIG:
3145 case F_GETFL:
3146 case F_GETOWN:
3147 case F_GETSIG:
3148 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003149 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003150 break;
3151 case F_GETLK:
3152 case F_SETLK:
3153 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003155 case F_GETLK64:
3156 case F_SETLK64:
3157 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003159 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3160 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003162 }
David Howells88e67f32008-11-14 10:39:21 +11003163 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003164 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 }
3166
3167 return err;
3168}
3169
3170static int selinux_file_set_fowner(struct file *file)
3171{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 struct file_security_struct *fsec;
3173
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003175 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
3177 return 0;
3178}
3179
3180static int selinux_file_send_sigiotask(struct task_struct *tsk,
3181 struct fown_struct *fown, int signum)
3182{
Eric Paris828dfe12008-04-17 13:17:49 -04003183 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003184 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 struct file_security_struct *fsec;
3187
3188 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003189 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 fsec = file->f_security;
3192
3193 if (!signum)
3194 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3195 else
3196 perm = signal_to_av(signum);
3197
David Howells275bb412008-11-14 10:39:19 +11003198 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 SECCLASS_PROCESS, perm, NULL);
3200}
3201
3202static int selinux_file_receive(struct file *file)
3203{
David Howells88e67f32008-11-14 10:39:21 +11003204 const struct cred *cred = current_cred();
3205
3206 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207}
3208
David Howells745ca242008-11-14 10:39:22 +11003209static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003210{
3211 struct file_security_struct *fsec;
3212 struct inode *inode;
3213 struct inode_security_struct *isec;
3214 inode = file->f_path.dentry->d_inode;
3215 fsec = file->f_security;
3216 isec = inode->i_security;
3217 /*
3218 * Save inode label and policy sequence number
3219 * at open-time so that selinux_file_permission
3220 * can determine whether revalidation is necessary.
3221 * Task label is already saved in the file security
3222 * struct as its SID.
3223 */
3224 fsec->isid = isec->sid;
3225 fsec->pseqno = avc_policy_seqno();
3226 /*
3227 * Since the inode label or policy seqno may have changed
3228 * between the selinux_inode_permission check and the saving
3229 * of state above, recheck that access is still permitted.
3230 * Otherwise, access might never be revalidated against the
3231 * new inode label or new policy.
3232 * This check is not redundant - do not remove.
3233 */
David Howells88e67f32008-11-14 10:39:21 +11003234 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003235}
3236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237/* task security operations */
3238
3239static int selinux_task_create(unsigned long clone_flags)
3240{
3241 int rc;
3242
3243 rc = secondary_ops->task_create(clone_flags);
3244 if (rc)
3245 return rc;
3246
3247 return task_has_perm(current, current, PROCESS__FORK);
3248}
3249
David Howellsf1752ee2008-11-14 10:39:17 +11003250static int selinux_cred_alloc_security(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251{
3252 struct task_security_struct *tsec1, *tsec2;
3253 int rc;
3254
David Howells275bb412008-11-14 10:39:19 +11003255 tsec1 = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256
David Howellsf1752ee2008-11-14 10:39:17 +11003257 rc = cred_alloc_security(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 if (rc)
3259 return rc;
David Howellsf1752ee2008-11-14 10:39:17 +11003260 tsec2 = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
3262 tsec2->osid = tsec1->osid;
3263 tsec2->sid = tsec1->sid;
3264
Michael LeMay28eba5b2006-06-27 02:53:42 -07003265 /* Retain the exec, fs, key, and sock SIDs across fork */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 tsec2->exec_sid = tsec1->exec_sid;
3267 tsec2->create_sid = tsec1->create_sid;
Michael LeMay28eba5b2006-06-27 02:53:42 -07003268 tsec2->keycreate_sid = tsec1->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07003269 tsec2->sockcreate_sid = tsec1->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 return 0;
3272}
3273
David Howellsf1752ee2008-11-14 10:39:17 +11003274/*
3275 * detach and free the LSM part of a set of credentials
3276 */
3277static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278{
David Howellsf1752ee2008-11-14 10:39:17 +11003279 struct task_security_struct *tsec = cred->security;
3280 cred->security = NULL;
3281 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282}
3283
3284static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3285{
3286 /* Since setuid only affects the current process, and
3287 since the SELinux controls are not based on the Linux
3288 identity attributes, SELinux does not need to control
3289 this operation. However, SELinux does control the use
3290 of the CAP_SETUID and CAP_SETGID capabilities using the
3291 capable hook. */
3292 return 0;
3293}
3294
3295static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3296{
Eric Paris828dfe12008-04-17 13:17:49 -04003297 return secondary_ops->task_post_setuid(id0, id1, id2, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298}
3299
3300static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3301{
3302 /* See the comment for setuid above. */
3303 return 0;
3304}
3305
3306static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3307{
3308 return task_has_perm(current, p, PROCESS__SETPGID);
3309}
3310
3311static int selinux_task_getpgid(struct task_struct *p)
3312{
3313 return task_has_perm(current, p, PROCESS__GETPGID);
3314}
3315
3316static int selinux_task_getsid(struct task_struct *p)
3317{
3318 return task_has_perm(current, p, PROCESS__GETSESSION);
3319}
3320
David Quigleyf9008e42006-06-30 01:55:46 -07003321static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3322{
David Howells275bb412008-11-14 10:39:19 +11003323 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003324}
3325
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326static int selinux_task_setgroups(struct group_info *group_info)
3327{
3328 /* See the comment for setuid above. */
3329 return 0;
3330}
3331
3332static int selinux_task_setnice(struct task_struct *p, int nice)
3333{
3334 int rc;
3335
3336 rc = secondary_ops->task_setnice(p, nice);
3337 if (rc)
3338 return rc;
3339
Eric Paris828dfe12008-04-17 13:17:49 -04003340 return task_has_perm(current, p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341}
3342
James Morris03e68062006-06-23 02:03:58 -07003343static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3344{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003345 int rc;
3346
3347 rc = secondary_ops->task_setioprio(p, ioprio);
3348 if (rc)
3349 return rc;
3350
James Morris03e68062006-06-23 02:03:58 -07003351 return task_has_perm(current, p, PROCESS__SETSCHED);
3352}
3353
David Quigleya1836a42006-06-30 01:55:49 -07003354static int selinux_task_getioprio(struct task_struct *p)
3355{
3356 return task_has_perm(current, p, PROCESS__GETSCHED);
3357}
3358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3360{
3361 struct rlimit *old_rlim = current->signal->rlim + resource;
3362 int rc;
3363
3364 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3365 if (rc)
3366 return rc;
3367
3368 /* Control the ability to change the hard limit (whether
3369 lowering or raising it), so that the hard limit can
3370 later be used as a safe reset point for the soft limit
3371 upon context transitions. See selinux_bprm_apply_creds. */
3372 if (old_rlim->rlim_max != new_rlim->rlim_max)
3373 return task_has_perm(current, current, PROCESS__SETRLIMIT);
3374
3375 return 0;
3376}
3377
3378static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3379{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003380 int rc;
3381
3382 rc = secondary_ops->task_setscheduler(p, policy, lp);
3383 if (rc)
3384 return rc;
3385
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return task_has_perm(current, p, PROCESS__SETSCHED);
3387}
3388
3389static int selinux_task_getscheduler(struct task_struct *p)
3390{
3391 return task_has_perm(current, p, PROCESS__GETSCHED);
3392}
3393
David Quigley35601542006-06-23 02:04:01 -07003394static int selinux_task_movememory(struct task_struct *p)
3395{
3396 return task_has_perm(current, p, PROCESS__SETSCHED);
3397}
3398
David Quigleyf9008e42006-06-30 01:55:46 -07003399static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3400 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401{
3402 u32 perm;
3403 int rc;
3404
David Quigleyf9008e42006-06-30 01:55:46 -07003405 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 if (rc)
3407 return rc;
3408
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 if (!sig)
3410 perm = PROCESS__SIGNULL; /* null signal; existence test */
3411 else
3412 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003413 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003414 rc = avc_has_perm(secid, task_sid(p),
3415 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003416 else
3417 rc = task_has_perm(current, p, perm);
3418 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419}
3420
3421static int selinux_task_prctl(int option,
3422 unsigned long arg2,
3423 unsigned long arg3,
3424 unsigned long arg4,
Andrew G. Morgan3898b1b2008-04-28 02:13:40 -07003425 unsigned long arg5,
3426 long *rc_p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427{
3428 /* The current prctl operations do not appear to require
3429 any SELinux controls since they merely observe or modify
3430 the state of the current process. */
Andrew G. Morgan3898b1b2008-04-28 02:13:40 -07003431 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432}
3433
3434static int selinux_task_wait(struct task_struct *p)
3435{
Eric Paris8a535142007-10-22 16:10:31 -04003436 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437}
3438
3439static void selinux_task_reparent_to_init(struct task_struct *p)
3440{
Eric Paris828dfe12008-04-17 13:17:49 -04003441 struct task_security_struct *tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
3443 secondary_ops->task_reparent_to_init(p);
3444
David Howellsb6dff3e2008-11-14 10:39:16 +11003445 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 tsec->osid = tsec->sid;
3447 tsec->sid = SECINITSID_KERNEL;
3448 return;
3449}
3450
3451static void selinux_task_to_inode(struct task_struct *p,
3452 struct inode *inode)
3453{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003455 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
David Howells275bb412008-11-14 10:39:19 +11003457 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459}
3460
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003462static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3463 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464{
3465 int offset, ihlen, ret = -EINVAL;
3466 struct iphdr _iph, *ih;
3467
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003468 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3470 if (ih == NULL)
3471 goto out;
3472
3473 ihlen = ih->ihl * 4;
3474 if (ihlen < sizeof(_iph))
3475 goto out;
3476
3477 ad->u.net.v4info.saddr = ih->saddr;
3478 ad->u.net.v4info.daddr = ih->daddr;
3479 ret = 0;
3480
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003481 if (proto)
3482 *proto = ih->protocol;
3483
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003485 case IPPROTO_TCP: {
3486 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487
Eric Paris828dfe12008-04-17 13:17:49 -04003488 if (ntohs(ih->frag_off) & IP_OFFSET)
3489 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
3491 offset += ihlen;
3492 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3493 if (th == NULL)
3494 break;
3495
3496 ad->u.net.sport = th->source;
3497 ad->u.net.dport = th->dest;
3498 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
Eric Paris828dfe12008-04-17 13:17:49 -04003501 case IPPROTO_UDP: {
3502 struct udphdr _udph, *uh;
3503
3504 if (ntohs(ih->frag_off) & IP_OFFSET)
3505 break;
3506
3507 offset += ihlen;
3508 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3509 if (uh == NULL)
3510 break;
3511
3512 ad->u.net.sport = uh->source;
3513 ad->u.net.dport = uh->dest;
3514 break;
3515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
James Morris2ee92d42006-11-13 16:09:01 -08003517 case IPPROTO_DCCP: {
3518 struct dccp_hdr _dccph, *dh;
3519
3520 if (ntohs(ih->frag_off) & IP_OFFSET)
3521 break;
3522
3523 offset += ihlen;
3524 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3525 if (dh == NULL)
3526 break;
3527
3528 ad->u.net.sport = dh->dccph_sport;
3529 ad->u.net.dport = dh->dccph_dport;
3530 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003531 }
James Morris2ee92d42006-11-13 16:09:01 -08003532
Eric Paris828dfe12008-04-17 13:17:49 -04003533 default:
3534 break;
3535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536out:
3537 return ret;
3538}
3539
3540#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3541
3542/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003543static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3544 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545{
3546 u8 nexthdr;
3547 int ret = -EINVAL, offset;
3548 struct ipv6hdr _ipv6h, *ip6;
3549
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003550 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3552 if (ip6 == NULL)
3553 goto out;
3554
3555 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3556 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3557 ret = 0;
3558
3559 nexthdr = ip6->nexthdr;
3560 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003561 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 if (offset < 0)
3563 goto out;
3564
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003565 if (proto)
3566 *proto = nexthdr;
3567
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 switch (nexthdr) {
3569 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003570 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571
3572 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3573 if (th == NULL)
3574 break;
3575
3576 ad->u.net.sport = th->source;
3577 ad->u.net.dport = th->dest;
3578 break;
3579 }
3580
3581 case IPPROTO_UDP: {
3582 struct udphdr _udph, *uh;
3583
3584 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3585 if (uh == NULL)
3586 break;
3587
3588 ad->u.net.sport = uh->source;
3589 ad->u.net.dport = uh->dest;
3590 break;
3591 }
3592
James Morris2ee92d42006-11-13 16:09:01 -08003593 case IPPROTO_DCCP: {
3594 struct dccp_hdr _dccph, *dh;
3595
3596 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3597 if (dh == NULL)
3598 break;
3599
3600 ad->u.net.sport = dh->dccph_sport;
3601 ad->u.net.dport = dh->dccph_dport;
3602 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003603 }
James Morris2ee92d42006-11-13 16:09:01 -08003604
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 /* includes fragments */
3606 default:
3607 break;
3608 }
3609out:
3610 return ret;
3611}
3612
3613#endif /* IPV6 */
3614
3615static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003616 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617{
David Howellscf9481e2008-07-27 21:31:07 +10003618 char *addrp;
3619 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620
3621 switch (ad->u.net.family) {
3622 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003623 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003624 if (ret)
3625 goto parse_error;
3626 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3627 &ad->u.net.v4info.daddr);
3628 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
3630#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3631 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003632 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003633 if (ret)
3634 goto parse_error;
3635 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3636 &ad->u.net.v6info.daddr);
3637 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638#endif /* IPV6 */
3639 default:
David Howellscf9481e2008-07-27 21:31:07 +10003640 addrp = NULL;
3641 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 }
3643
David Howellscf9481e2008-07-27 21:31:07 +10003644parse_error:
3645 printk(KERN_WARNING
3646 "SELinux: failure in selinux_parse_skb(),"
3647 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003649
3650okay:
3651 if (_addrp)
3652 *_addrp = addrp;
3653 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654}
3655
Paul Moore4f6a9932007-03-01 14:35:22 -05003656/**
Paul Moore220deb92008-01-29 08:38:23 -05003657 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003658 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003659 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003660 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003661 *
3662 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003663 * Check the various different forms of network peer labeling and determine
3664 * the peer label/SID for the packet; most of the magic actually occurs in
3665 * the security server function security_net_peersid_cmp(). The function
3666 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3667 * or -EACCES if @sid is invalid due to inconsistencies with the different
3668 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003669 *
3670 */
Paul Moore220deb92008-01-29 08:38:23 -05003671static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003672{
Paul Moore71f1cb02008-01-29 08:51:16 -05003673 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003674 u32 xfrm_sid;
3675 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003676 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003677
3678 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003679 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003680
Paul Moore71f1cb02008-01-29 08:51:16 -05003681 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3682 if (unlikely(err)) {
3683 printk(KERN_WARNING
3684 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3685 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003686 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003687 }
Paul Moore220deb92008-01-29 08:38:23 -05003688
3689 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003690}
3691
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692/* socket security operations */
3693static int socket_has_perm(struct task_struct *task, struct socket *sock,
3694 u32 perms)
3695{
3696 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003698 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 int err = 0;
3700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 isec = SOCK_INODE(sock)->i_security;
3702
3703 if (isec->sid == SECINITSID_KERNEL)
3704 goto out;
David Howells275bb412008-11-14 10:39:19 +11003705 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706
Eric Paris828dfe12008-04-17 13:17:49 -04003707 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003709 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710
3711out:
3712 return err;
3713}
3714
3715static int selinux_socket_create(int family, int type,
3716 int protocol, int kern)
3717{
David Howells275bb412008-11-14 10:39:19 +11003718 const struct cred *cred = current_cred();
3719 const struct task_security_struct *tsec = cred->security;
3720 u32 sid, newsid;
3721 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723
3724 if (kern)
3725 goto out;
3726
David Howells275bb412008-11-14 10:39:19 +11003727 sid = tsec->sid;
3728 newsid = tsec->sockcreate_sid ?: sid;
3729
3730 secclass = socket_type_to_security_class(family, type, protocol);
3731 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
3733out:
3734 return err;
3735}
3736
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003737static int selinux_socket_post_create(struct socket *sock, int family,
3738 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739{
David Howells275bb412008-11-14 10:39:19 +11003740 const struct cred *cred = current_cred();
3741 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003743 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003744 u32 sid, newsid;
3745 int err = 0;
3746
3747 sid = tsec->sid;
3748 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
3750 isec = SOCK_INODE(sock)->i_security;
3751
David Howells275bb412008-11-14 10:39:19 +11003752 if (kern)
3753 isec->sid = SECINITSID_KERNEL;
3754 else if (newsid)
3755 isec->sid = newsid;
3756 else
3757 isec->sid = sid;
3758
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 isec->initialized = 1;
3761
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003762 if (sock->sk) {
3763 sksec = sock->sk->sk_security;
3764 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003765 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003766 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003767 }
3768
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003769 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770}
3771
3772/* Range of port numbers used to automatically bind.
3773 Need to determine whether we should perform a name_bind
3774 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775
3776static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3777{
3778 u16 family;
3779 int err;
3780
3781 err = socket_has_perm(current, sock, SOCKET__BIND);
3782 if (err)
3783 goto out;
3784
3785 /*
3786 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003787 * Multiple address binding for SCTP is not supported yet: we just
3788 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 */
3790 family = sock->sk->sk_family;
3791 if (family == PF_INET || family == PF_INET6) {
3792 char *addrp;
3793 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 struct avc_audit_data ad;
3795 struct sockaddr_in *addr4 = NULL;
3796 struct sockaddr_in6 *addr6 = NULL;
3797 unsigned short snum;
3798 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003799 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 isec = SOCK_INODE(sock)->i_security;
3802
3803 if (family == PF_INET) {
3804 addr4 = (struct sockaddr_in *)address;
3805 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 addrp = (char *)&addr4->sin_addr.s_addr;
3807 } else {
3808 addr6 = (struct sockaddr_in6 *)address;
3809 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 addrp = (char *)&addr6->sin6_addr.s6_addr;
3811 }
3812
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003813 if (snum) {
3814 int low, high;
3815
3816 inet_get_local_port_range(&low, &high);
3817
3818 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003819 err = sel_netport_sid(sk->sk_protocol,
3820 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003821 if (err)
3822 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003823 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003824 ad.u.net.sport = htons(snum);
3825 ad.u.net.family = family;
3826 err = avc_has_perm(isec->sid, sid,
3827 isec->sclass,
3828 SOCKET__NAME_BIND, &ad);
3829 if (err)
3830 goto out;
3831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 }
Eric Paris828dfe12008-04-17 13:17:49 -04003833
3834 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003835 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 node_perm = TCP_SOCKET__NODE_BIND;
3837 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003838
James Morris13402582005-09-30 14:24:34 -04003839 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 node_perm = UDP_SOCKET__NODE_BIND;
3841 break;
James Morris2ee92d42006-11-13 16:09:01 -08003842
3843 case SECCLASS_DCCP_SOCKET:
3844 node_perm = DCCP_SOCKET__NODE_BIND;
3845 break;
3846
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 default:
3848 node_perm = RAWIP_SOCKET__NODE_BIND;
3849 break;
3850 }
Eric Paris828dfe12008-04-17 13:17:49 -04003851
Paul Moore224dfbd2008-01-29 08:38:13 -05003852 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 if (err)
3854 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003855
3856 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 ad.u.net.sport = htons(snum);
3858 ad.u.net.family = family;
3859
3860 if (family == PF_INET)
3861 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3862 else
3863 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3864
3865 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003866 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 if (err)
3868 goto out;
3869 }
3870out:
3871 return err;
3872}
3873
3874static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3875{
Paul Moore014ab192008-10-10 10:16:33 -04003876 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 struct inode_security_struct *isec;
3878 int err;
3879
3880 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3881 if (err)
3882 return err;
3883
3884 /*
James Morris2ee92d42006-11-13 16:09:01 -08003885 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 */
3887 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003888 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3889 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 struct avc_audit_data ad;
3891 struct sockaddr_in *addr4 = NULL;
3892 struct sockaddr_in6 *addr6 = NULL;
3893 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003894 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895
3896 if (sk->sk_family == PF_INET) {
3897 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003898 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 return -EINVAL;
3900 snum = ntohs(addr4->sin_port);
3901 } else {
3902 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003903 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 return -EINVAL;
3905 snum = ntohs(addr6->sin6_port);
3906 }
3907
Paul Moore3e112172008-04-10 10:48:14 -04003908 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 if (err)
3910 goto out;
3911
James Morris2ee92d42006-11-13 16:09:01 -08003912 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3913 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3914
Eric Paris828dfe12008-04-17 13:17:49 -04003915 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 ad.u.net.dport = htons(snum);
3917 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003918 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 if (err)
3920 goto out;
3921 }
3922
Paul Moore014ab192008-10-10 10:16:33 -04003923 err = selinux_netlbl_socket_connect(sk, address);
3924
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925out:
3926 return err;
3927}
3928
3929static int selinux_socket_listen(struct socket *sock, int backlog)
3930{
3931 return socket_has_perm(current, sock, SOCKET__LISTEN);
3932}
3933
3934static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3935{
3936 int err;
3937 struct inode_security_struct *isec;
3938 struct inode_security_struct *newisec;
3939
3940 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3941 if (err)
3942 return err;
3943
3944 newisec = SOCK_INODE(newsock)->i_security;
3945
3946 isec = SOCK_INODE(sock)->i_security;
3947 newisec->sclass = isec->sclass;
3948 newisec->sid = isec->sid;
3949 newisec->initialized = 1;
3950
3951 return 0;
3952}
3953
3954static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003955 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003957 int rc;
3958
3959 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3960 if (rc)
3961 return rc;
3962
3963 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964}
3965
3966static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3967 int size, int flags)
3968{
3969 return socket_has_perm(current, sock, SOCKET__READ);
3970}
3971
3972static int selinux_socket_getsockname(struct socket *sock)
3973{
3974 return socket_has_perm(current, sock, SOCKET__GETATTR);
3975}
3976
3977static int selinux_socket_getpeername(struct socket *sock)
3978{
3979 return socket_has_perm(current, sock, SOCKET__GETATTR);
3980}
3981
Eric Paris828dfe12008-04-17 13:17:49 -04003982static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983{
Paul Mooref8687af2006-10-30 15:22:15 -08003984 int err;
3985
3986 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3987 if (err)
3988 return err;
3989
3990 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991}
3992
3993static int selinux_socket_getsockopt(struct socket *sock, int level,
3994 int optname)
3995{
3996 return socket_has_perm(current, sock, SOCKET__GETOPT);
3997}
3998
3999static int selinux_socket_shutdown(struct socket *sock, int how)
4000{
4001 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
4002}
4003
4004static int selinux_socket_unix_stream_connect(struct socket *sock,
4005 struct socket *other,
4006 struct sock *newsk)
4007{
4008 struct sk_security_struct *ssec;
4009 struct inode_security_struct *isec;
4010 struct inode_security_struct *other_isec;
4011 struct avc_audit_data ad;
4012 int err;
4013
4014 err = secondary_ops->unix_stream_connect(sock, other, newsk);
4015 if (err)
4016 return err;
4017
4018 isec = SOCK_INODE(sock)->i_security;
4019 other_isec = SOCK_INODE(other)->i_security;
4020
Eric Paris828dfe12008-04-17 13:17:49 -04004021 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 ad.u.net.sk = other->sk;
4023
4024 err = avc_has_perm(isec->sid, other_isec->sid,
4025 isec->sclass,
4026 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4027 if (err)
4028 return err;
4029
4030 /* connecting socket */
4031 ssec = sock->sk->sk_security;
4032 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004033
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 /* server child socket */
4035 ssec = newsk->sk_security;
4036 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004037 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4038
4039 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040}
4041
4042static int selinux_socket_unix_may_send(struct socket *sock,
4043 struct socket *other)
4044{
4045 struct inode_security_struct *isec;
4046 struct inode_security_struct *other_isec;
4047 struct avc_audit_data ad;
4048 int err;
4049
4050 isec = SOCK_INODE(sock)->i_security;
4051 other_isec = SOCK_INODE(other)->i_security;
4052
Eric Paris828dfe12008-04-17 13:17:49 -04004053 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 ad.u.net.sk = other->sk;
4055
4056 err = avc_has_perm(isec->sid, other_isec->sid,
4057 isec->sclass, SOCKET__SENDTO, &ad);
4058 if (err)
4059 return err;
4060
4061 return 0;
4062}
4063
Paul Mooreeffad8d2008-01-29 08:49:27 -05004064static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4065 u32 peer_sid,
4066 struct avc_audit_data *ad)
4067{
4068 int err;
4069 u32 if_sid;
4070 u32 node_sid;
4071
4072 err = sel_netif_sid(ifindex, &if_sid);
4073 if (err)
4074 return err;
4075 err = avc_has_perm(peer_sid, if_sid,
4076 SECCLASS_NETIF, NETIF__INGRESS, ad);
4077 if (err)
4078 return err;
4079
4080 err = sel_netnode_sid(addrp, family, &node_sid);
4081 if (err)
4082 return err;
4083 return avc_has_perm(peer_sid, node_sid,
4084 SECCLASS_NODE, NODE__RECVFROM, ad);
4085}
4086
Paul Moore220deb92008-01-29 08:38:23 -05004087static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4088 struct sk_buff *skb,
4089 struct avc_audit_data *ad,
4090 u16 family,
4091 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092{
Paul Moore220deb92008-01-29 08:38:23 -05004093 int err;
4094 struct sk_security_struct *sksec = sk->sk_security;
4095 u16 sk_class;
4096 u32 netif_perm, node_perm, recv_perm;
4097 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004098
Paul Moore220deb92008-01-29 08:38:23 -05004099 sk_sid = sksec->sid;
4100 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
Paul Moore220deb92008-01-29 08:38:23 -05004102 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 case SECCLASS_UDP_SOCKET:
4104 netif_perm = NETIF__UDP_RECV;
4105 node_perm = NODE__UDP_RECV;
4106 recv_perm = UDP_SOCKET__RECV_MSG;
4107 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 case SECCLASS_TCP_SOCKET:
4109 netif_perm = NETIF__TCP_RECV;
4110 node_perm = NODE__TCP_RECV;
4111 recv_perm = TCP_SOCKET__RECV_MSG;
4112 break;
James Morris2ee92d42006-11-13 16:09:01 -08004113 case SECCLASS_DCCP_SOCKET:
4114 netif_perm = NETIF__DCCP_RECV;
4115 node_perm = NODE__DCCP_RECV;
4116 recv_perm = DCCP_SOCKET__RECV_MSG;
4117 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 default:
4119 netif_perm = NETIF__RAWIP_RECV;
4120 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004121 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 break;
4123 }
4124
Paul Moore220deb92008-01-29 08:38:23 -05004125 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004127 return err;
4128 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4129 if (err)
4130 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004131
Paul Moore224dfbd2008-01-29 08:38:13 -05004132 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004134 return err;
4135 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004137 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138
Paul Moore220deb92008-01-29 08:38:23 -05004139 if (!recv_perm)
4140 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004141 err = sel_netport_sid(sk->sk_protocol,
4142 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004143 if (unlikely(err)) {
4144 printk(KERN_WARNING
4145 "SELinux: failure in"
4146 " selinux_sock_rcv_skb_iptables_compat(),"
4147 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004148 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004149 }
Paul Moore220deb92008-01-29 08:38:23 -05004150 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4151}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
Paul Moore220deb92008-01-29 08:38:23 -05004153static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004154 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004155{
4156 int err;
4157 struct sk_security_struct *sksec = sk->sk_security;
4158 u32 peer_sid;
4159 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004160 struct avc_audit_data ad;
4161 char *addrp;
4162
4163 AVC_AUDIT_DATA_INIT(&ad, NET);
4164 ad.u.net.netif = skb->iif;
4165 ad.u.net.family = family;
4166 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4167 if (err)
4168 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004169
4170 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004171 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004172 family, addrp);
4173 else
4174 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004175 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004176 if (err)
4177 return err;
4178
4179 if (selinux_policycap_netpeer) {
4180 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004182 return err;
4183 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004184 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004185 if (err)
4186 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004187 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004188 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004189 if (err)
4190 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004191 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004193
James Morris4e5ab4c2006-06-09 00:33:33 -07004194 return err;
4195}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004196
James Morris4e5ab4c2006-06-09 00:33:33 -07004197static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4198{
Paul Moore220deb92008-01-29 08:38:23 -05004199 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004200 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004201 u16 family = sk->sk_family;
4202 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004203 struct avc_audit_data ad;
4204 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004205 u8 secmark_active;
4206 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004207
James Morris4e5ab4c2006-06-09 00:33:33 -07004208 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004209 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004210
4211 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004212 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004213 family = PF_INET;
4214
Paul Moored8395c82008-10-10 10:16:30 -04004215 /* If any sort of compatibility mode is enabled then handoff processing
4216 * to the selinux_sock_rcv_skb_compat() function to deal with the
4217 * special handling. We do this in an attempt to keep this function
4218 * as fast and as clean as possible. */
4219 if (selinux_compat_net || !selinux_policycap_netpeer)
4220 return selinux_sock_rcv_skb_compat(sk, skb, family);
4221
4222 secmark_active = selinux_secmark_enabled();
4223 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4224 if (!secmark_active && !peerlbl_active)
4225 return 0;
4226
James Morris4e5ab4c2006-06-09 00:33:33 -07004227 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004228 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004229 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004230 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004231 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004232 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004233
Paul Moored8395c82008-10-10 10:16:30 -04004234 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004235 u32 peer_sid;
4236
4237 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4238 if (err)
4239 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004240 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4241 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004242 if (err) {
4243 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004244 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004245 }
Paul Moored621d352008-01-29 08:43:36 -05004246 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4247 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004248 if (err)
4249 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004250 }
4251
Paul Moored8395c82008-10-10 10:16:30 -04004252 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004253 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4254 PACKET__RECV, &ad);
4255 if (err)
4256 return err;
4257 }
4258
Paul Moored621d352008-01-29 08:43:36 -05004259 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260}
4261
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004262static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4263 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264{
4265 int err = 0;
4266 char *scontext;
4267 u32 scontext_len;
4268 struct sk_security_struct *ssec;
4269 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004270 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
4272 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004273
Paul Moore3de4bab2006-11-17 17:38:54 -05004274 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4275 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004276 ssec = sock->sk->sk_security;
4277 peer_sid = ssec->peer_sid;
4278 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004279 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 err = -ENOPROTOOPT;
4281 goto out;
4282 }
4283
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004284 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4285
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 if (err)
4287 goto out;
4288
4289 if (scontext_len > len) {
4290 err = -ERANGE;
4291 goto out_len;
4292 }
4293
4294 if (copy_to_user(optval, scontext, scontext_len))
4295 err = -EFAULT;
4296
4297out_len:
4298 if (put_user(scontext_len, optlen))
4299 err = -EFAULT;
4300
4301 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004302out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 return err;
4304}
4305
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004306static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004307{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004308 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004309 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004310
Paul Mooreaa862902008-10-10 10:16:29 -04004311 if (skb && skb->protocol == htons(ETH_P_IP))
4312 family = PF_INET;
4313 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4314 family = PF_INET6;
4315 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004316 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004317 else
4318 goto out;
4319
4320 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02004321 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004322 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004323 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004324
Paul Moore75e22912008-01-29 08:38:04 -05004325out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004326 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004327 if (peer_secid == SECSID_NULL)
4328 return -EINVAL;
4329 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004330}
4331
Al Viro7d877f32005-10-21 03:20:43 -04004332static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333{
4334 return sk_alloc_security(sk, family, priority);
4335}
4336
4337static void selinux_sk_free_security(struct sock *sk)
4338{
4339 sk_free_security(sk);
4340}
4341
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004342static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4343{
4344 struct sk_security_struct *ssec = sk->sk_security;
4345 struct sk_security_struct *newssec = newsk->sk_security;
4346
4347 newssec->sid = ssec->sid;
4348 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004349 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004350
Paul Mooref74af6e2008-02-25 11:40:33 -05004351 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004352}
4353
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004354static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004355{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004356 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004357 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004358 else {
4359 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004360
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004361 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004362 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004363}
4364
Eric Paris828dfe12008-04-17 13:17:49 -04004365static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004366{
4367 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4368 struct sk_security_struct *sksec = sk->sk_security;
4369
David Woodhouse2148ccc2006-09-29 15:50:25 -07004370 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4371 sk->sk_family == PF_UNIX)
4372 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004373 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004374}
4375
Adrian Bunk9a673e52006-08-15 00:03:53 -07004376static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4377 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004378{
4379 struct sk_security_struct *sksec = sk->sk_security;
4380 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004381 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004382 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004383 u32 peersid;
4384
Paul Mooreaa862902008-10-10 10:16:29 -04004385 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4386 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4387 family = PF_INET;
4388
4389 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004390 if (err)
4391 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004392 if (peersid == SECSID_NULL) {
4393 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004394 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004395 return 0;
4396 }
4397
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004398 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4399 if (err)
4400 return err;
4401
4402 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004403 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004404 return 0;
4405}
4406
Adrian Bunk9a673e52006-08-15 00:03:53 -07004407static void selinux_inet_csk_clone(struct sock *newsk,
4408 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004409{
4410 struct sk_security_struct *newsksec = newsk->sk_security;
4411
4412 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004413 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004414 /* NOTE: Ideally, we should also get the isec->sid for the
4415 new socket in sync, but we don't have the isec available yet.
4416 So we will wait until sock_graft to do it, by which
4417 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004418
Paul Moore9f2ad662006-11-17 17:38:53 -05004419 /* We don't need to take any sort of lock here as we are the only
4420 * thread with access to newsksec */
4421 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004422}
4423
Paul Moore014ab192008-10-10 10:16:33 -04004424static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004425{
Paul Mooreaa862902008-10-10 10:16:29 -04004426 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004427 struct sk_security_struct *sksec = sk->sk_security;
4428
Paul Mooreaa862902008-10-10 10:16:29 -04004429 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4430 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4431 family = PF_INET;
4432
4433 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004434
4435 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004436}
4437
Adrian Bunk9a673e52006-08-15 00:03:53 -07004438static void selinux_req_classify_flow(const struct request_sock *req,
4439 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004440{
4441 fl->secid = req->secid;
4442}
4443
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4445{
4446 int err = 0;
4447 u32 perm;
4448 struct nlmsghdr *nlh;
4449 struct socket *sock = sk->sk_socket;
4450 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004451
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 if (skb->len < NLMSG_SPACE(0)) {
4453 err = -EINVAL;
4454 goto out;
4455 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004456 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4459 if (err) {
4460 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004461 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 "SELinux: unrecognized netlink message"
4463 " type=%hu for sclass=%hu\n",
4464 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004465 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 err = 0;
4467 }
4468
4469 /* Ignore */
4470 if (err == -ENOENT)
4471 err = 0;
4472 goto out;
4473 }
4474
4475 err = socket_has_perm(current, sock, perm);
4476out:
4477 return err;
4478}
4479
4480#ifdef CONFIG_NETFILTER
4481
Paul Mooreeffad8d2008-01-29 08:49:27 -05004482static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4483 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484{
Paul Mooredfaebe92008-10-10 10:16:31 -04004485 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004486 char *addrp;
4487 u32 peer_sid;
4488 struct avc_audit_data ad;
4489 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004490 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004491 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004492
Paul Mooreeffad8d2008-01-29 08:49:27 -05004493 if (!selinux_policycap_netpeer)
4494 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004495
Paul Mooreeffad8d2008-01-29 08:49:27 -05004496 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004497 netlbl_active = netlbl_enabled();
4498 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004499 if (!secmark_active && !peerlbl_active)
4500 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004501
Paul Moored8395c82008-10-10 10:16:30 -04004502 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4503 return NF_DROP;
4504
Paul Mooreeffad8d2008-01-29 08:49:27 -05004505 AVC_AUDIT_DATA_INIT(&ad, NET);
4506 ad.u.net.netif = ifindex;
4507 ad.u.net.family = family;
4508 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4509 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510
Paul Mooredfaebe92008-10-10 10:16:31 -04004511 if (peerlbl_active) {
4512 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4513 peer_sid, &ad);
4514 if (err) {
4515 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004516 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004517 }
4518 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004519
4520 if (secmark_active)
4521 if (avc_has_perm(peer_sid, skb->secmark,
4522 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4523 return NF_DROP;
4524
Paul Moore948bf852008-10-10 10:16:32 -04004525 if (netlbl_active)
4526 /* we do this in the FORWARD path and not the POST_ROUTING
4527 * path because we want to make sure we apply the necessary
4528 * labeling before IPsec is applied so we can leverage AH
4529 * protection */
4530 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4531 return NF_DROP;
4532
Paul Mooreeffad8d2008-01-29 08:49:27 -05004533 return NF_ACCEPT;
4534}
4535
4536static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4537 struct sk_buff *skb,
4538 const struct net_device *in,
4539 const struct net_device *out,
4540 int (*okfn)(struct sk_buff *))
4541{
4542 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4543}
4544
4545#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4546static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4547 struct sk_buff *skb,
4548 const struct net_device *in,
4549 const struct net_device *out,
4550 int (*okfn)(struct sk_buff *))
4551{
4552 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4553}
4554#endif /* IPV6 */
4555
Paul Moore948bf852008-10-10 10:16:32 -04004556static unsigned int selinux_ip_output(struct sk_buff *skb,
4557 u16 family)
4558{
4559 u32 sid;
4560
4561 if (!netlbl_enabled())
4562 return NF_ACCEPT;
4563
4564 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4565 * because we want to make sure we apply the necessary labeling
4566 * before IPsec is applied so we can leverage AH protection */
4567 if (skb->sk) {
4568 struct sk_security_struct *sksec = skb->sk->sk_security;
4569 sid = sksec->sid;
4570 } else
4571 sid = SECINITSID_KERNEL;
4572 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4573 return NF_DROP;
4574
4575 return NF_ACCEPT;
4576}
4577
4578static unsigned int selinux_ipv4_output(unsigned int hooknum,
4579 struct sk_buff *skb,
4580 const struct net_device *in,
4581 const struct net_device *out,
4582 int (*okfn)(struct sk_buff *))
4583{
4584 return selinux_ip_output(skb, PF_INET);
4585}
4586
Paul Mooreeffad8d2008-01-29 08:49:27 -05004587static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4588 int ifindex,
4589 struct avc_audit_data *ad,
4590 u16 family, char *addrp)
4591{
4592 int err;
4593 struct sk_security_struct *sksec = sk->sk_security;
4594 u16 sk_class;
4595 u32 netif_perm, node_perm, send_perm;
4596 u32 port_sid, node_sid, if_sid, sk_sid;
4597
4598 sk_sid = sksec->sid;
4599 sk_class = sksec->sclass;
4600
4601 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 case SECCLASS_UDP_SOCKET:
4603 netif_perm = NETIF__UDP_SEND;
4604 node_perm = NODE__UDP_SEND;
4605 send_perm = UDP_SOCKET__SEND_MSG;
4606 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 case SECCLASS_TCP_SOCKET:
4608 netif_perm = NETIF__TCP_SEND;
4609 node_perm = NODE__TCP_SEND;
4610 send_perm = TCP_SOCKET__SEND_MSG;
4611 break;
James Morris2ee92d42006-11-13 16:09:01 -08004612 case SECCLASS_DCCP_SOCKET:
4613 netif_perm = NETIF__DCCP_SEND;
4614 node_perm = NODE__DCCP_SEND;
4615 send_perm = DCCP_SOCKET__SEND_MSG;
4616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 default:
4618 netif_perm = NETIF__RAWIP_SEND;
4619 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004620 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 break;
4622 }
4623
Paul Mooreeffad8d2008-01-29 08:49:27 -05004624 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004625 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004626 return err;
4627 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4628 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004629
Paul Moore224dfbd2008-01-29 08:38:13 -05004630 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004631 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004632 return err;
4633 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004634 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004635 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
Paul Mooreeffad8d2008-01-29 08:49:27 -05004637 if (send_perm != 0)
4638 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639
Paul Moore3e112172008-04-10 10:48:14 -04004640 err = sel_netport_sid(sk->sk_protocol,
4641 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004642 if (unlikely(err)) {
4643 printk(KERN_WARNING
4644 "SELinux: failure in"
4645 " selinux_ip_postroute_iptables_compat(),"
4646 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004647 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004648 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004649 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004650}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Paul Mooreeffad8d2008-01-29 08:49:27 -05004652static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4653 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004654 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004655{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004656 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004657 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004658 struct avc_audit_data ad;
4659 char *addrp;
4660 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004661
Paul Mooreeffad8d2008-01-29 08:49:27 -05004662 if (sk == NULL)
4663 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004664 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004665
Paul Moored8395c82008-10-10 10:16:30 -04004666 AVC_AUDIT_DATA_INIT(&ad, NET);
4667 ad.u.net.netif = ifindex;
4668 ad.u.net.family = family;
4669 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4670 return NF_DROP;
4671
Paul Mooreeffad8d2008-01-29 08:49:27 -05004672 if (selinux_compat_net) {
4673 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004674 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004675 return NF_DROP;
4676 } else {
4677 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004678 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004679 return NF_DROP;
4680 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004681
Paul Mooreeffad8d2008-01-29 08:49:27 -05004682 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004683 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004684 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004685
Paul Mooreeffad8d2008-01-29 08:49:27 -05004686 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687}
4688
Paul Mooreeffad8d2008-01-29 08:49:27 -05004689static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4690 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004692 u32 secmark_perm;
4693 u32 peer_sid;
4694 struct sock *sk;
4695 struct avc_audit_data ad;
4696 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004697 u8 secmark_active;
4698 u8 peerlbl_active;
4699
Paul Mooreeffad8d2008-01-29 08:49:27 -05004700 /* If any sort of compatibility mode is enabled then handoff processing
4701 * to the selinux_ip_postroute_compat() function to deal with the
4702 * special handling. We do this in an attempt to keep this function
4703 * as fast and as clean as possible. */
4704 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004705 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706
4707 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4708 * packet transformation so allow the packet to pass without any checks
4709 * since we'll have another chance to perform access control checks
4710 * when the packet is on it's final way out.
4711 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4712 * is NULL, in this case go ahead and apply access control. */
4713 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4714 return NF_ACCEPT;
4715
4716 secmark_active = selinux_secmark_enabled();
4717 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4718 if (!secmark_active && !peerlbl_active)
4719 return NF_ACCEPT;
4720
Paul Moored8395c82008-10-10 10:16:30 -04004721 /* if the packet is being forwarded then get the peer label from the
4722 * packet itself; otherwise check to see if it is from a local
4723 * application or the kernel, if from an application get the peer label
4724 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004725 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004726 if (sk == NULL) {
4727 switch (family) {
4728 case PF_INET:
4729 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4730 secmark_perm = PACKET__FORWARD_OUT;
4731 else
4732 secmark_perm = PACKET__SEND;
4733 break;
4734 case PF_INET6:
4735 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4736 secmark_perm = PACKET__FORWARD_OUT;
4737 else
4738 secmark_perm = PACKET__SEND;
4739 break;
4740 default:
4741 return NF_DROP;
4742 }
4743 if (secmark_perm == PACKET__FORWARD_OUT) {
4744 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4745 return NF_DROP;
4746 } else
4747 peer_sid = SECINITSID_KERNEL;
4748 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004749 struct sk_security_struct *sksec = sk->sk_security;
4750 peer_sid = sksec->sid;
4751 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004752 }
4753
Paul Moored8395c82008-10-10 10:16:30 -04004754 AVC_AUDIT_DATA_INIT(&ad, NET);
4755 ad.u.net.netif = ifindex;
4756 ad.u.net.family = family;
4757 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4758 return NF_DROP;
4759
Paul Mooreeffad8d2008-01-29 08:49:27 -05004760 if (secmark_active)
4761 if (avc_has_perm(peer_sid, skb->secmark,
4762 SECCLASS_PACKET, secmark_perm, &ad))
4763 return NF_DROP;
4764
4765 if (peerlbl_active) {
4766 u32 if_sid;
4767 u32 node_sid;
4768
4769 if (sel_netif_sid(ifindex, &if_sid))
4770 return NF_DROP;
4771 if (avc_has_perm(peer_sid, if_sid,
4772 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4773 return NF_DROP;
4774
4775 if (sel_netnode_sid(addrp, family, &node_sid))
4776 return NF_DROP;
4777 if (avc_has_perm(peer_sid, node_sid,
4778 SECCLASS_NODE, NODE__SENDTO, &ad))
4779 return NF_DROP;
4780 }
4781
4782 return NF_ACCEPT;
4783}
4784
4785static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4786 struct sk_buff *skb,
4787 const struct net_device *in,
4788 const struct net_device *out,
4789 int (*okfn)(struct sk_buff *))
4790{
4791 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792}
4793
4794#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004795static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4796 struct sk_buff *skb,
4797 const struct net_device *in,
4798 const struct net_device *out,
4799 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004801 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803#endif /* IPV6 */
4804
4805#endif /* CONFIG_NETFILTER */
4806
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4808{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 int err;
4810
4811 err = secondary_ops->netlink_send(sk, skb);
4812 if (err)
4813 return err;
4814
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4816 err = selinux_nlmsg_perm(sk, skb);
4817
4818 return err;
4819}
4820
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004821static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004823 int err;
4824 struct avc_audit_data ad;
4825
4826 err = secondary_ops->netlink_recv(skb, capability);
4827 if (err)
4828 return err;
4829
4830 AVC_AUDIT_DATA_INIT(&ad, CAP);
4831 ad.u.cap = capability;
4832
4833 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004834 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835}
4836
4837static int ipc_alloc_security(struct task_struct *task,
4838 struct kern_ipc_perm *perm,
4839 u16 sclass)
4840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004842 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843
James Morris89d155e2005-10-30 14:59:21 -08004844 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 if (!isec)
4846 return -ENOMEM;
4847
David Howells275bb412008-11-14 10:39:19 +11004848 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004850 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 perm->security = isec;
4852
4853 return 0;
4854}
4855
4856static void ipc_free_security(struct kern_ipc_perm *perm)
4857{
4858 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 perm->security = NULL;
4860 kfree(isec);
4861}
4862
4863static int msg_msg_alloc_security(struct msg_msg *msg)
4864{
4865 struct msg_security_struct *msec;
4866
James Morris89d155e2005-10-30 14:59:21 -08004867 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 if (!msec)
4869 return -ENOMEM;
4870
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 msec->sid = SECINITSID_UNLABELED;
4872 msg->security = msec;
4873
4874 return 0;
4875}
4876
4877static void msg_msg_free_security(struct msg_msg *msg)
4878{
4879 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880
4881 msg->security = NULL;
4882 kfree(msec);
4883}
4884
4885static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004886 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 struct ipc_security_struct *isec;
4889 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004890 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 isec = ipc_perms->security;
4893
4894 AVC_AUDIT_DATA_INIT(&ad, IPC);
4895 ad.u.ipc_id = ipc_perms->key;
4896
David Howells275bb412008-11-14 10:39:19 +11004897 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898}
4899
4900static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4901{
4902 return msg_msg_alloc_security(msg);
4903}
4904
4905static void selinux_msg_msg_free_security(struct msg_msg *msg)
4906{
4907 msg_msg_free_security(msg);
4908}
4909
4910/* message queue security operations */
4911static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4912{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 struct ipc_security_struct *isec;
4914 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004915 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 int rc;
4917
4918 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4919 if (rc)
4920 return rc;
4921
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 isec = msq->q_perm.security;
4923
4924 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004925 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926
David Howells275bb412008-11-14 10:39:19 +11004927 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 MSGQ__CREATE, &ad);
4929 if (rc) {
4930 ipc_free_security(&msq->q_perm);
4931 return rc;
4932 }
4933 return 0;
4934}
4935
4936static void selinux_msg_queue_free_security(struct msg_queue *msq)
4937{
4938 ipc_free_security(&msq->q_perm);
4939}
4940
4941static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4942{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 struct ipc_security_struct *isec;
4944 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004945 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 isec = msq->q_perm.security;
4948
4949 AVC_AUDIT_DATA_INIT(&ad, IPC);
4950 ad.u.ipc_id = msq->q_perm.key;
4951
David Howells275bb412008-11-14 10:39:19 +11004952 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 MSGQ__ASSOCIATE, &ad);
4954}
4955
4956static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4957{
4958 int err;
4959 int perms;
4960
Eric Paris828dfe12008-04-17 13:17:49 -04004961 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 case IPC_INFO:
4963 case MSG_INFO:
4964 /* No specific object, just general system-wide information. */
4965 return task_has_system(current, SYSTEM__IPC_INFO);
4966 case IPC_STAT:
4967 case MSG_STAT:
4968 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4969 break;
4970 case IPC_SET:
4971 perms = MSGQ__SETATTR;
4972 break;
4973 case IPC_RMID:
4974 perms = MSGQ__DESTROY;
4975 break;
4976 default:
4977 return 0;
4978 }
4979
Stephen Smalley6af963f2005-05-01 08:58:39 -07004980 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 return err;
4982}
4983
4984static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4985{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 struct ipc_security_struct *isec;
4987 struct msg_security_struct *msec;
4988 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004989 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 int rc;
4991
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 isec = msq->q_perm.security;
4993 msec = msg->security;
4994
4995 /*
4996 * First time through, need to assign label to the message
4997 */
4998 if (msec->sid == SECINITSID_UNLABELED) {
4999 /*
5000 * Compute new sid based on current process and
5001 * message queue this message will be stored in
5002 */
David Howells275bb412008-11-14 10:39:19 +11005003 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 &msec->sid);
5005 if (rc)
5006 return rc;
5007 }
5008
5009 AVC_AUDIT_DATA_INIT(&ad, IPC);
5010 ad.u.ipc_id = msq->q_perm.key;
5011
5012 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005013 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 MSGQ__WRITE, &ad);
5015 if (!rc)
5016 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005017 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5018 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 if (!rc)
5020 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005021 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5022 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
5024 return rc;
5025}
5026
5027static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5028 struct task_struct *target,
5029 long type, int mode)
5030{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 struct ipc_security_struct *isec;
5032 struct msg_security_struct *msec;
5033 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005034 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 int rc;
5036
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 isec = msq->q_perm.security;
5038 msec = msg->security;
5039
5040 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005041 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042
David Howells275bb412008-11-14 10:39:19 +11005043 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 SECCLASS_MSGQ, MSGQ__READ, &ad);
5045 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005046 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 SECCLASS_MSG, MSG__RECEIVE, &ad);
5048 return rc;
5049}
5050
5051/* Shared Memory security operations */
5052static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5053{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 struct ipc_security_struct *isec;
5055 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005056 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 int rc;
5058
5059 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5060 if (rc)
5061 return rc;
5062
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 isec = shp->shm_perm.security;
5064
5065 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005066 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067
David Howells275bb412008-11-14 10:39:19 +11005068 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 SHM__CREATE, &ad);
5070 if (rc) {
5071 ipc_free_security(&shp->shm_perm);
5072 return rc;
5073 }
5074 return 0;
5075}
5076
5077static void selinux_shm_free_security(struct shmid_kernel *shp)
5078{
5079 ipc_free_security(&shp->shm_perm);
5080}
5081
5082static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5083{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 struct ipc_security_struct *isec;
5085 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005086 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 isec = shp->shm_perm.security;
5089
5090 AVC_AUDIT_DATA_INIT(&ad, IPC);
5091 ad.u.ipc_id = shp->shm_perm.key;
5092
David Howells275bb412008-11-14 10:39:19 +11005093 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 SHM__ASSOCIATE, &ad);
5095}
5096
5097/* Note, at this point, shp is locked down */
5098static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5099{
5100 int perms;
5101 int err;
5102
Eric Paris828dfe12008-04-17 13:17:49 -04005103 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 case IPC_INFO:
5105 case SHM_INFO:
5106 /* No specific object, just general system-wide information. */
5107 return task_has_system(current, SYSTEM__IPC_INFO);
5108 case IPC_STAT:
5109 case SHM_STAT:
5110 perms = SHM__GETATTR | SHM__ASSOCIATE;
5111 break;
5112 case IPC_SET:
5113 perms = SHM__SETATTR;
5114 break;
5115 case SHM_LOCK:
5116 case SHM_UNLOCK:
5117 perms = SHM__LOCK;
5118 break;
5119 case IPC_RMID:
5120 perms = SHM__DESTROY;
5121 break;
5122 default:
5123 return 0;
5124 }
5125
Stephen Smalley6af963f2005-05-01 08:58:39 -07005126 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 return err;
5128}
5129
5130static int selinux_shm_shmat(struct shmid_kernel *shp,
5131 char __user *shmaddr, int shmflg)
5132{
5133 u32 perms;
5134 int rc;
5135
5136 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5137 if (rc)
5138 return rc;
5139
5140 if (shmflg & SHM_RDONLY)
5141 perms = SHM__READ;
5142 else
5143 perms = SHM__READ | SHM__WRITE;
5144
Stephen Smalley6af963f2005-05-01 08:58:39 -07005145 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146}
5147
5148/* Semaphore security operations */
5149static int selinux_sem_alloc_security(struct sem_array *sma)
5150{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 struct ipc_security_struct *isec;
5152 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005153 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 int rc;
5155
5156 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5157 if (rc)
5158 return rc;
5159
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 isec = sma->sem_perm.security;
5161
5162 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005163 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164
David Howells275bb412008-11-14 10:39:19 +11005165 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 SEM__CREATE, &ad);
5167 if (rc) {
5168 ipc_free_security(&sma->sem_perm);
5169 return rc;
5170 }
5171 return 0;
5172}
5173
5174static void selinux_sem_free_security(struct sem_array *sma)
5175{
5176 ipc_free_security(&sma->sem_perm);
5177}
5178
5179static int selinux_sem_associate(struct sem_array *sma, int semflg)
5180{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 struct ipc_security_struct *isec;
5182 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005183 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 isec = sma->sem_perm.security;
5186
5187 AVC_AUDIT_DATA_INIT(&ad, IPC);
5188 ad.u.ipc_id = sma->sem_perm.key;
5189
David Howells275bb412008-11-14 10:39:19 +11005190 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 SEM__ASSOCIATE, &ad);
5192}
5193
5194/* Note, at this point, sma is locked down */
5195static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5196{
5197 int err;
5198 u32 perms;
5199
Eric Paris828dfe12008-04-17 13:17:49 -04005200 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 case IPC_INFO:
5202 case SEM_INFO:
5203 /* No specific object, just general system-wide information. */
5204 return task_has_system(current, SYSTEM__IPC_INFO);
5205 case GETPID:
5206 case GETNCNT:
5207 case GETZCNT:
5208 perms = SEM__GETATTR;
5209 break;
5210 case GETVAL:
5211 case GETALL:
5212 perms = SEM__READ;
5213 break;
5214 case SETVAL:
5215 case SETALL:
5216 perms = SEM__WRITE;
5217 break;
5218 case IPC_RMID:
5219 perms = SEM__DESTROY;
5220 break;
5221 case IPC_SET:
5222 perms = SEM__SETATTR;
5223 break;
5224 case IPC_STAT:
5225 case SEM_STAT:
5226 perms = SEM__GETATTR | SEM__ASSOCIATE;
5227 break;
5228 default:
5229 return 0;
5230 }
5231
Stephen Smalley6af963f2005-05-01 08:58:39 -07005232 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 return err;
5234}
5235
5236static int selinux_sem_semop(struct sem_array *sma,
5237 struct sembuf *sops, unsigned nsops, int alter)
5238{
5239 u32 perms;
5240
5241 if (alter)
5242 perms = SEM__READ | SEM__WRITE;
5243 else
5244 perms = SEM__READ;
5245
Stephen Smalley6af963f2005-05-01 08:58:39 -07005246 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247}
5248
5249static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5250{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 u32 av = 0;
5252
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 av = 0;
5254 if (flag & S_IRUGO)
5255 av |= IPC__UNIX_READ;
5256 if (flag & S_IWUGO)
5257 av |= IPC__UNIX_WRITE;
5258
5259 if (av == 0)
5260 return 0;
5261
Stephen Smalley6af963f2005-05-01 08:58:39 -07005262 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263}
5264
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02005265static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5266{
5267 struct ipc_security_struct *isec = ipcp->security;
5268 *secid = isec->sid;
5269}
5270
Eric Paris828dfe12008-04-17 13:17:49 -04005271static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272{
5273 if (inode)
5274 inode_doinit_with_dentry(inode, dentry);
5275}
5276
5277static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005278 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279{
David Howells275bb412008-11-14 10:39:19 +11005280 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005281 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005283 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284
5285 if (current != p) {
5286 error = task_has_perm(current, p, PROCESS__GETATTR);
5287 if (error)
5288 return error;
5289 }
5290
David Howells275bb412008-11-14 10:39:19 +11005291 rcu_read_lock();
5292 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293
5294 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005295 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005297 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005299 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005301 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005302 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005303 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005304 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005305 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 else
David Howells275bb412008-11-14 10:39:19 +11005307 goto invalid;
5308 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
5310 if (!sid)
5311 return 0;
5312
Al Viro04ff9702007-03-12 16:17:58 +00005313 error = security_sid_to_context(sid, value, &len);
5314 if (error)
5315 return error;
5316 return len;
David Howells275bb412008-11-14 10:39:19 +11005317
5318invalid:
5319 rcu_read_unlock();
5320 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321}
5322
5323static int selinux_setprocattr(struct task_struct *p,
5324 char *name, void *value, size_t size)
5325{
5326 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005327 struct task_struct *tracer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 u32 sid = 0;
5329 int error;
5330 char *str = value;
5331
5332 if (current != p) {
5333 /* SELinux only allows a process to change its own
5334 security attributes. */
5335 return -EACCES;
5336 }
5337
5338 /*
5339 * Basic control over ability to set these attributes at all.
5340 * current == p, but we'll pass them separately in case the
5341 * above restriction is ever removed.
5342 */
5343 if (!strcmp(name, "exec"))
5344 error = task_has_perm(current, p, PROCESS__SETEXEC);
5345 else if (!strcmp(name, "fscreate"))
5346 error = task_has_perm(current, p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005347 else if (!strcmp(name, "keycreate"))
5348 error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005349 else if (!strcmp(name, "sockcreate"))
5350 error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 else if (!strcmp(name, "current"))
5352 error = task_has_perm(current, p, PROCESS__SETCURRENT);
5353 else
5354 error = -EINVAL;
5355 if (error)
5356 return error;
5357
5358 /* Obtain a SID for the context, if one was specified. */
5359 if (size && str[1] && str[1] != '\n') {
5360 if (str[size-1] == '\n') {
5361 str[size-1] = 0;
5362 size--;
5363 }
5364 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005365 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5366 if (!capable(CAP_MAC_ADMIN))
5367 return error;
5368 error = security_context_to_sid_force(value, size,
5369 &sid);
5370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 if (error)
5372 return error;
5373 }
5374
5375 /* Permission checking based on the specified context is
5376 performed during the actual operation (execve,
5377 open/mkdir/...), when we know the full context of the
5378 operation. See selinux_bprm_set_security for the execve
5379 checks and may_create for the file creation checks. The
5380 operation will then fail if the context is not permitted. */
David Howellsb6dff3e2008-11-14 10:39:16 +11005381 tsec = p->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 if (!strcmp(name, "exec"))
5383 tsec->exec_sid = sid;
5384 else if (!strcmp(name, "fscreate"))
5385 tsec->create_sid = sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005386 else if (!strcmp(name, "keycreate")) {
5387 error = may_create_key(sid, p);
5388 if (error)
5389 return error;
5390 tsec->keycreate_sid = sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005391 } else if (!strcmp(name, "sockcreate"))
5392 tsec->sockcreate_sid = sid;
5393 else if (!strcmp(name, "current")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 struct av_decision avd;
5395
5396 if (sid == 0)
5397 return -EINVAL;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005398 /*
5399 * SELinux allows to change context in the following case only.
5400 * - Single threaded processes.
5401 * - Multi threaded processes intend to change its context into
5402 * more restricted domain (defined by TYPEBOUNDS statement).
5403 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 if (atomic_read(&p->mm->mm_users) != 1) {
5405 struct task_struct *g, *t;
5406 struct mm_struct *mm = p->mm;
5407 read_lock(&tasklist_lock);
James Morris2baf06d2008-06-12 01:42:35 +10005408 do_each_thread(g, t) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 if (t->mm == mm && t != p) {
5410 read_unlock(&tasklist_lock);
KaiGai Koheid9250de2008-08-28 16:35:57 +09005411 error = security_bounded_transition(tsec->sid, sid);
5412 if (!error)
5413 goto boundary_ok;
5414
5415 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 }
James Morris2baf06d2008-06-12 01:42:35 +10005417 } while_each_thread(g, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 read_unlock(&tasklist_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04005419 }
KaiGai Koheid9250de2008-08-28 16:35:57 +09005420boundary_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421
5422 /* Check permissions for the transition. */
5423 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005424 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 if (error)
5426 return error;
5427
5428 /* Check for ptracing, and update the task SID if ok.
5429 Otherwise, leave SID unchanged and fail. */
5430 task_lock(p);
Roland McGrath03563572008-03-26 15:46:39 -07005431 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07005432 tracer = tracehook_tracer_task(p);
Roland McGrath03563572008-03-26 15:46:39 -07005433 if (tracer != NULL) {
David Howells275bb412008-11-14 10:39:19 +11005434 u32 ptsid = task_sid(tracer);
Roland McGrath03563572008-03-26 15:46:39 -07005435 rcu_read_unlock();
5436 error = avc_has_perm_noaudit(ptsid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 SECCLASS_PROCESS,
Stephen Smalley2c3c05d2007-06-07 15:34:10 -04005438 PROCESS__PTRACE, 0, &avd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 if (!error)
5440 tsec->sid = sid;
5441 task_unlock(p);
Roland McGrath03563572008-03-26 15:46:39 -07005442 avc_audit(ptsid, sid, SECCLASS_PROCESS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 PROCESS__PTRACE, &avd, error, NULL);
5444 if (error)
5445 return error;
5446 } else {
Roland McGrath03563572008-03-26 15:46:39 -07005447 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 tsec->sid = sid;
5449 task_unlock(p);
5450 }
Eric Paris828dfe12008-04-17 13:17:49 -04005451 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 return -EINVAL;
5453
5454 return size;
5455}
5456
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005457static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5458{
5459 return security_sid_to_context(secid, secdata, seclen);
5460}
5461
David Howells7bf570d2008-04-29 20:52:51 +01005462static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005463{
5464 return security_context_to_sid(secdata, seclen, secid);
5465}
5466
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005467static void selinux_release_secctx(char *secdata, u32 seclen)
5468{
Paul Moore088999e2007-08-01 11:12:58 -04005469 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005470}
5471
Michael LeMayd7200242006-06-22 14:47:17 -07005472#ifdef CONFIG_KEYS
5473
David Howells7e047ef2006-06-26 00:24:50 -07005474static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
5475 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005476{
David Howells275bb412008-11-14 10:39:19 +11005477 const struct task_security_struct *__tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005478 struct key_security_struct *ksec;
5479
5480 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5481 if (!ksec)
5482 return -ENOMEM;
5483
David Howells275bb412008-11-14 10:39:19 +11005484 rcu_read_lock();
5485 __tsec = __task_cred(tsk)->security;
5486 if (__tsec->keycreate_sid)
5487 ksec->sid = __tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005488 else
David Howells275bb412008-11-14 10:39:19 +11005489 ksec->sid = __tsec->sid;
5490 rcu_read_unlock();
Michael LeMayd7200242006-06-22 14:47:17 -07005491
David Howells275bb412008-11-14 10:39:19 +11005492 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005493 return 0;
5494}
5495
5496static void selinux_key_free(struct key *k)
5497{
5498 struct key_security_struct *ksec = k->security;
5499
5500 k->security = NULL;
5501 kfree(ksec);
5502}
5503
5504static int selinux_key_permission(key_ref_t key_ref,
5505 struct task_struct *ctx,
5506 key_perm_t perm)
5507{
5508 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005509 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005510 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005511
5512 /* if no specific permissions are requested, we skip the
5513 permission check. No serious, additional covert channels
5514 appear to be created. */
5515 if (perm == 0)
5516 return 0;
5517
David Howells275bb412008-11-14 10:39:19 +11005518 sid = task_sid(ctx);
5519
5520 key = key_ref_to_ptr(key_ref);
5521 ksec = key->security;
5522
5523 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005524}
5525
David Howells70a5bb72008-04-29 01:01:26 -07005526static int selinux_key_getsecurity(struct key *key, char **_buffer)
5527{
5528 struct key_security_struct *ksec = key->security;
5529 char *context = NULL;
5530 unsigned len;
5531 int rc;
5532
5533 rc = security_sid_to_context(ksec->sid, &context, &len);
5534 if (!rc)
5535 rc = len;
5536 *_buffer = context;
5537 return rc;
5538}
5539
Michael LeMayd7200242006-06-22 14:47:17 -07005540#endif
5541
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005543 .name = "selinux",
5544
David Howells5cd9c582008-08-14 11:37:28 +01005545 .ptrace_may_access = selinux_ptrace_may_access,
5546 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 .capget = selinux_capget,
5548 .capset_check = selinux_capset_check,
5549 .capset_set = selinux_capset_set,
5550 .sysctl = selinux_sysctl,
5551 .capable = selinux_capable,
5552 .quotactl = selinux_quotactl,
5553 .quota_on = selinux_quota_on,
5554 .syslog = selinux_syslog,
5555 .vm_enough_memory = selinux_vm_enough_memory,
5556
5557 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005558 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559
5560 .bprm_alloc_security = selinux_bprm_alloc_security,
5561 .bprm_free_security = selinux_bprm_free_security,
5562 .bprm_apply_creds = selinux_bprm_apply_creds,
5563 .bprm_post_apply_creds = selinux_bprm_post_apply_creds,
5564 .bprm_set_security = selinux_bprm_set_security,
5565 .bprm_check_security = selinux_bprm_check_security,
5566 .bprm_secureexec = selinux_bprm_secureexec,
5567
5568 .sb_alloc_security = selinux_sb_alloc_security,
5569 .sb_free_security = selinux_sb_free_security,
5570 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005571 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005572 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 .sb_statfs = selinux_sb_statfs,
5574 .sb_mount = selinux_mount,
5575 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005576 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005577 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005578 .sb_parse_opts_str = selinux_parse_opts_str,
5579
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
5581 .inode_alloc_security = selinux_inode_alloc_security,
5582 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005583 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 .inode_unlink = selinux_inode_unlink,
5587 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 .inode_rmdir = selinux_inode_rmdir,
5590 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 .inode_readlink = selinux_inode_readlink,
5593 .inode_follow_link = selinux_inode_follow_link,
5594 .inode_permission = selinux_inode_permission,
5595 .inode_setattr = selinux_inode_setattr,
5596 .inode_getattr = selinux_inode_getattr,
5597 .inode_setxattr = selinux_inode_setxattr,
5598 .inode_post_setxattr = selinux_inode_post_setxattr,
5599 .inode_getxattr = selinux_inode_getxattr,
5600 .inode_listxattr = selinux_inode_listxattr,
5601 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005602 .inode_getsecurity = selinux_inode_getsecurity,
5603 .inode_setsecurity = selinux_inode_setsecurity,
5604 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005605 .inode_need_killpriv = selinux_inode_need_killpriv,
5606 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005607 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608
5609 .file_permission = selinux_file_permission,
5610 .file_alloc_security = selinux_file_alloc_security,
5611 .file_free_security = selinux_file_free_security,
5612 .file_ioctl = selinux_file_ioctl,
5613 .file_mmap = selinux_file_mmap,
5614 .file_mprotect = selinux_file_mprotect,
5615 .file_lock = selinux_file_lock,
5616 .file_fcntl = selinux_file_fcntl,
5617 .file_set_fowner = selinux_file_set_fowner,
5618 .file_send_sigiotask = selinux_file_send_sigiotask,
5619 .file_receive = selinux_file_receive,
5620
Eric Paris828dfe12008-04-17 13:17:49 -04005621 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005622
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005624 .cred_alloc_security = selinux_cred_alloc_security,
5625 .cred_free = selinux_cred_free,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 .task_setuid = selinux_task_setuid,
5627 .task_post_setuid = selinux_task_post_setuid,
5628 .task_setgid = selinux_task_setgid,
5629 .task_setpgid = selinux_task_setpgid,
5630 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005631 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005632 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 .task_setgroups = selinux_task_setgroups,
5634 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005635 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005636 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .task_setrlimit = selinux_task_setrlimit,
5638 .task_setscheduler = selinux_task_setscheduler,
5639 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005640 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 .task_kill = selinux_task_kill,
5642 .task_wait = selinux_task_wait,
5643 .task_prctl = selinux_task_prctl,
5644 .task_reparent_to_init = selinux_task_reparent_to_init,
Eric Paris828dfe12008-04-17 13:17:49 -04005645 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646
5647 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005648 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649
5650 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5651 .msg_msg_free_security = selinux_msg_msg_free_security,
5652
5653 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5654 .msg_queue_free_security = selinux_msg_queue_free_security,
5655 .msg_queue_associate = selinux_msg_queue_associate,
5656 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5657 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5658 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5659
5660 .shm_alloc_security = selinux_shm_alloc_security,
5661 .shm_free_security = selinux_shm_free_security,
5662 .shm_associate = selinux_shm_associate,
5663 .shm_shmctl = selinux_shm_shmctl,
5664 .shm_shmat = selinux_shm_shmat,
5665
Eric Paris828dfe12008-04-17 13:17:49 -04005666 .sem_alloc_security = selinux_sem_alloc_security,
5667 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 .sem_associate = selinux_sem_associate,
5669 .sem_semctl = selinux_sem_semctl,
5670 .sem_semop = selinux_sem_semop,
5671
Eric Paris828dfe12008-04-17 13:17:49 -04005672 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673
Eric Paris828dfe12008-04-17 13:17:49 -04005674 .getprocattr = selinux_getprocattr,
5675 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005677 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005678 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005679 .release_secctx = selinux_release_secctx,
5680
Eric Paris828dfe12008-04-17 13:17:49 -04005681 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 .unix_may_send = selinux_socket_unix_may_send,
5683
5684 .socket_create = selinux_socket_create,
5685 .socket_post_create = selinux_socket_post_create,
5686 .socket_bind = selinux_socket_bind,
5687 .socket_connect = selinux_socket_connect,
5688 .socket_listen = selinux_socket_listen,
5689 .socket_accept = selinux_socket_accept,
5690 .socket_sendmsg = selinux_socket_sendmsg,
5691 .socket_recvmsg = selinux_socket_recvmsg,
5692 .socket_getsockname = selinux_socket_getsockname,
5693 .socket_getpeername = selinux_socket_getpeername,
5694 .socket_getsockopt = selinux_socket_getsockopt,
5695 .socket_setsockopt = selinux_socket_setsockopt,
5696 .socket_shutdown = selinux_socket_shutdown,
5697 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005698 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5699 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 .sk_alloc_security = selinux_sk_alloc_security,
5701 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005702 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005703 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005704 .sock_graft = selinux_sock_graft,
5705 .inet_conn_request = selinux_inet_conn_request,
5706 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005707 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005708 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005709
5710#ifdef CONFIG_SECURITY_NETWORK_XFRM
5711 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5712 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5713 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005714 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005715 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5716 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005717 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005718 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005719 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005720 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005722
5723#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005724 .key_alloc = selinux_key_alloc,
5725 .key_free = selinux_key_free,
5726 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005727 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005728#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005729
5730#ifdef CONFIG_AUDIT
5731 .audit_rule_init = selinux_audit_rule_init,
5732 .audit_rule_known = selinux_audit_rule_known,
5733 .audit_rule_match = selinux_audit_rule_match,
5734 .audit_rule_free = selinux_audit_rule_free,
5735#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736};
5737
5738static __init int selinux_init(void)
5739{
5740 struct task_security_struct *tsec;
5741
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005742 if (!security_module_enable(&selinux_ops)) {
5743 selinux_enabled = 0;
5744 return 0;
5745 }
5746
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 if (!selinux_enabled) {
5748 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5749 return 0;
5750 }
5751
5752 printk(KERN_INFO "SELinux: Initializing.\n");
5753
5754 /* Set the security state for the initial task. */
David Howellsf1752ee2008-11-14 10:39:17 +11005755 if (cred_alloc_security(current->cred))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 panic("SELinux: Failed to initialize initial task.\n");
David Howellsb6dff3e2008-11-14 10:39:16 +11005757 tsec = current->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 tsec->osid = tsec->sid = SECINITSID_KERNEL;
5759
James Morris7cae7e22006-03-22 00:09:22 -08005760 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5761 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005762 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 avc_init();
5764
James Morris6f0f0fd2008-07-10 17:02:07 +09005765 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005767 panic("SELinux: No initial security operations\n");
5768 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 panic("SELinux: Unable to register with kernel.\n");
5770
Eric Paris828dfe12008-04-17 13:17:49 -04005771 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005772 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005773 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005774 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005775
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 return 0;
5777}
5778
5779void selinux_complete_init(void)
5780{
Eric Parisfadcdb42007-02-22 18:11:31 -05005781 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782
5783 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005784 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005785 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786 spin_lock(&sb_security_lock);
5787next_sb:
5788 if (!list_empty(&superblock_security_head)) {
5789 struct superblock_security_struct *sbsec =
5790 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005791 struct superblock_security_struct,
5792 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005796 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 down_read(&sb->s_umount);
5798 if (sb->s_root)
5799 superblock_doinit(sb, NULL);
5800 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005801 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 spin_lock(&sb_security_lock);
5803 list_del_init(&sbsec->list);
5804 goto next_sb;
5805 }
5806 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005807 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808}
5809
5810/* SELinux requires early initialization in order to label
5811 all processes and objects when they are created. */
5812security_initcall(selinux_init);
5813
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005814#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815
Paul Mooreeffad8d2008-01-29 08:49:27 -05005816static struct nf_hook_ops selinux_ipv4_ops[] = {
5817 {
5818 .hook = selinux_ipv4_postroute,
5819 .owner = THIS_MODULE,
5820 .pf = PF_INET,
5821 .hooknum = NF_INET_POST_ROUTING,
5822 .priority = NF_IP_PRI_SELINUX_LAST,
5823 },
5824 {
5825 .hook = selinux_ipv4_forward,
5826 .owner = THIS_MODULE,
5827 .pf = PF_INET,
5828 .hooknum = NF_INET_FORWARD,
5829 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005830 },
5831 {
5832 .hook = selinux_ipv4_output,
5833 .owner = THIS_MODULE,
5834 .pf = PF_INET,
5835 .hooknum = NF_INET_LOCAL_OUT,
5836 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838};
5839
5840#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5841
Paul Mooreeffad8d2008-01-29 08:49:27 -05005842static struct nf_hook_ops selinux_ipv6_ops[] = {
5843 {
5844 .hook = selinux_ipv6_postroute,
5845 .owner = THIS_MODULE,
5846 .pf = PF_INET6,
5847 .hooknum = NF_INET_POST_ROUTING,
5848 .priority = NF_IP6_PRI_SELINUX_LAST,
5849 },
5850 {
5851 .hook = selinux_ipv6_forward,
5852 .owner = THIS_MODULE,
5853 .pf = PF_INET6,
5854 .hooknum = NF_INET_FORWARD,
5855 .priority = NF_IP6_PRI_SELINUX_FIRST,
5856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857};
5858
5859#endif /* IPV6 */
5860
5861static int __init selinux_nf_ip_init(void)
5862{
5863 int err = 0;
5864
5865 if (!selinux_enabled)
5866 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005867
5868 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5869
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005870 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5871 if (err)
5872 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873
5874#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005875 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5876 if (err)
5877 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005879
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880out:
5881 return err;
5882}
5883
5884__initcall(selinux_nf_ip_init);
5885
5886#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5887static void selinux_nf_ip_exit(void)
5888{
Eric Parisfadcdb42007-02-22 18:11:31 -05005889 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005891 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005893 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894#endif /* IPV6 */
5895}
5896#endif
5897
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005898#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899
5900#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5901#define selinux_nf_ip_exit()
5902#endif
5903
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005904#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905
5906#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005907static int selinux_disabled;
5908
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909int selinux_disable(void)
5910{
5911 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912
5913 if (ss_initialized) {
5914 /* Not permitted after initial policy load. */
5915 return -EINVAL;
5916 }
5917
5918 if (selinux_disabled) {
5919 /* Only do this once. */
5920 return -EINVAL;
5921 }
5922
5923 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5924
5925 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005926 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927
5928 /* Reset security_ops to the secondary module, dummy or capability. */
5929 security_ops = secondary_ops;
5930
5931 /* Unregister netfilter hooks. */
5932 selinux_nf_ip_exit();
5933
5934 /* Unregister selinuxfs. */
5935 exit_sel_fs();
5936
5937 return 0;
5938}
5939#endif