blob: c71bba78872f2a05db4cf51b85a0e3f04e07bc3b [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
David Howellsd84f4f92008-11-14 10:39:23 +1100159/*
160 * initialise the security for the init task
161 */
162static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163{
David Howellsd84f4f92008-11-14 10:39:23 +1100164 struct cred *cred = (struct cred *) current->cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct task_security_struct *tsec;
166
James Morris89d155e2005-10-30 14:59:21 -0800167 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100169 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
David Howellsd84f4f92008-11-14 10:39:23 +1100171 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100172 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
David Howells275bb412008-11-14 10:39:19 +1100175/*
David Howells88e67f32008-11-14 10:39:21 +1100176 * get the security ID of a set of credentials
177 */
178static inline u32 cred_sid(const struct cred *cred)
179{
180 const struct task_security_struct *tsec;
181
182 tsec = cred->security;
183 return tsec->sid;
184}
185
186/*
David 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 Howellsd84f4f92008-11-14 10:39:23 +11001382 * Check permission between a pair of credentials
1383 * fork check, ptrace check, etc.
1384 */
1385static int cred_has_perm(const struct cred *actor,
1386 const struct cred *target,
1387 u32 perms)
1388{
1389 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1390
1391 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1392}
1393
1394/*
David Howells88e67f32008-11-14 10:39:21 +11001395 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001396 * fork check, ptrace check, etc.
1397 * tsk1 is the actor and tsk2 is the target
1398 */
1399static int task_has_perm(const struct task_struct *tsk1,
1400 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 u32 perms)
1402{
David Howells275bb412008-11-14 10:39:19 +11001403 const struct task_security_struct *__tsec1, *__tsec2;
1404 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
David Howells275bb412008-11-14 10:39:19 +11001406 rcu_read_lock();
1407 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1408 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1409 rcu_read_unlock();
1410 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411}
1412
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001413#if CAP_LAST_CAP > 63
1414#error Fix SELinux to handle capabilities > 63.
1415#endif
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417/* Check whether a task is allowed to use a capability. */
1418static int task_has_capability(struct task_struct *tsk,
Eric Paris06112162008-11-11 22:02:50 +11001419 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001422 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001423 u16 sclass;
David Howells275bb412008-11-14 10:39:19 +11001424 u32 sid = task_sid(tsk);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001425 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001426 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Eric Paris828dfe12008-04-17 13:17:49 -04001428 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 ad.tsk = tsk;
1430 ad.u.cap = cap;
1431
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001432 switch (CAP_TO_INDEX(cap)) {
1433 case 0:
1434 sclass = SECCLASS_CAPABILITY;
1435 break;
1436 case 1:
1437 sclass = SECCLASS_CAPABILITY2;
1438 break;
1439 default:
1440 printk(KERN_ERR
1441 "SELinux: out of range capability %d\n", cap);
1442 BUG();
1443 }
Eric Paris06112162008-11-11 22:02:50 +11001444
David Howells275bb412008-11-14 10:39:19 +11001445 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001446 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001447 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001448 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449}
1450
1451/* Check whether a task is allowed to use a system operation. */
1452static int task_has_system(struct task_struct *tsk,
1453 u32 perms)
1454{
David Howells275bb412008-11-14 10:39:19 +11001455 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
David Howells275bb412008-11-14 10:39:19 +11001457 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 SECCLASS_SYSTEM, perms, NULL);
1459}
1460
1461/* Check whether a task has a particular permission to an inode.
1462 The 'adp' parameter is optional and allows other audit
1463 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001464static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 struct inode *inode,
1466 u32 perms,
1467 struct avc_audit_data *adp)
1468{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 struct inode_security_struct *isec;
1470 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001471 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Eric Paris828dfe12008-04-17 13:17:49 -04001473 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001474 return 0;
1475
David Howells88e67f32008-11-14 10:39:21 +11001476 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 isec = inode->i_security;
1478
1479 if (!adp) {
1480 adp = &ad;
1481 AVC_AUDIT_DATA_INIT(&ad, FS);
1482 ad.u.fs.inode = inode;
1483 }
1484
David Howells275bb412008-11-14 10:39:19 +11001485 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486}
1487
1488/* Same as inode_has_perm, but pass explicit audit data containing
1489 the dentry to help the auditing code to more easily generate the
1490 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001491static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 struct vfsmount *mnt,
1493 struct dentry *dentry,
1494 u32 av)
1495{
1496 struct inode *inode = dentry->d_inode;
1497 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001498
Eric Paris828dfe12008-04-17 13:17:49 -04001499 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001500 ad.u.fs.path.mnt = mnt;
1501 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001502 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503}
1504
1505/* Check whether a task can use an open file descriptor to
1506 access an inode in a given way. Check access to the
1507 descriptor itself, and then use dentry_has_perm to
1508 check a particular permission to the file.
1509 Access to the descriptor is implicitly granted if it
1510 has the same SID as the process. If av is zero, then
1511 access to the file is not checked, e.g. for cases
1512 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001513static int file_has_perm(const struct cred *cred,
1514 struct file *file,
1515 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001518 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001520 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 int rc;
1522
1523 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001524 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
David Howells275bb412008-11-14 10:39:19 +11001526 if (sid != fsec->sid) {
1527 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 SECCLASS_FD,
1529 FD__USE,
1530 &ad);
1531 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001532 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 }
1534
1535 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001536 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001538 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
David Howells88e67f32008-11-14 10:39:21 +11001540out:
1541 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542}
1543
1544/* Check whether a task can create a file. */
1545static int may_create(struct inode *dir,
1546 struct dentry *dentry,
1547 u16 tclass)
1548{
David Howells275bb412008-11-14 10:39:19 +11001549 const struct cred *cred = current_cred();
1550 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 struct inode_security_struct *dsec;
1552 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001553 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 struct avc_audit_data ad;
1555 int rc;
1556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 dsec = dir->i_security;
1558 sbsec = dir->i_sb->s_security;
1559
David Howells275bb412008-11-14 10:39:19 +11001560 sid = tsec->sid;
1561 newsid = tsec->create_sid;
1562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001564 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
David Howells275bb412008-11-14 10:39:19 +11001566 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 DIR__ADD_NAME | DIR__SEARCH,
1568 &ad);
1569 if (rc)
1570 return rc;
1571
David Howells275bb412008-11-14 10:39:19 +11001572 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
1573 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 if (rc)
1575 return rc;
1576 }
1577
David Howells275bb412008-11-14 10:39:19 +11001578 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 if (rc)
1580 return rc;
1581
1582 return avc_has_perm(newsid, sbsec->sid,
1583 SECCLASS_FILESYSTEM,
1584 FILESYSTEM__ASSOCIATE, &ad);
1585}
1586
Michael LeMay4eb582c2006-06-26 00:24:57 -07001587/* Check whether a task can create a key. */
1588static int may_create_key(u32 ksid,
1589 struct task_struct *ctx)
1590{
David Howells275bb412008-11-14 10:39:19 +11001591 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001592
David Howells275bb412008-11-14 10:39:19 +11001593 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001594}
1595
Eric Paris828dfe12008-04-17 13:17:49 -04001596#define MAY_LINK 0
1597#define MAY_UNLINK 1
1598#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
1600/* Check whether a task can link, unlink, or rmdir a file/directory. */
1601static int may_link(struct inode *dir,
1602 struct dentry *dentry,
1603 int kind)
1604
1605{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 struct inode_security_struct *dsec, *isec;
1607 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001608 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 u32 av;
1610 int rc;
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 dsec = dir->i_security;
1613 isec = dentry->d_inode->i_security;
1614
1615 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001616 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
1618 av = DIR__SEARCH;
1619 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001620 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (rc)
1622 return rc;
1623
1624 switch (kind) {
1625 case MAY_LINK:
1626 av = FILE__LINK;
1627 break;
1628 case MAY_UNLINK:
1629 av = FILE__UNLINK;
1630 break;
1631 case MAY_RMDIR:
1632 av = DIR__RMDIR;
1633 break;
1634 default:
Eric Paris744ba352008-04-17 11:52:44 -04001635 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1636 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 return 0;
1638 }
1639
David Howells275bb412008-11-14 10:39:19 +11001640 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 return rc;
1642}
1643
1644static inline int may_rename(struct inode *old_dir,
1645 struct dentry *old_dentry,
1646 struct inode *new_dir,
1647 struct dentry *new_dentry)
1648{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1650 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001651 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 u32 av;
1653 int old_is_dir, new_is_dir;
1654 int rc;
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 old_dsec = old_dir->i_security;
1657 old_isec = old_dentry->d_inode->i_security;
1658 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1659 new_dsec = new_dir->i_security;
1660
1661 AVC_AUDIT_DATA_INIT(&ad, FS);
1662
Jan Blunck44707fd2008-02-14 19:38:33 -08001663 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001664 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1666 if (rc)
1667 return rc;
David Howells275bb412008-11-14 10:39:19 +11001668 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 old_isec->sclass, FILE__RENAME, &ad);
1670 if (rc)
1671 return rc;
1672 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001673 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 old_isec->sclass, DIR__REPARENT, &ad);
1675 if (rc)
1676 return rc;
1677 }
1678
Jan Blunck44707fd2008-02-14 19:38:33 -08001679 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 av = DIR__ADD_NAME | DIR__SEARCH;
1681 if (new_dentry->d_inode)
1682 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001683 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 if (rc)
1685 return rc;
1686 if (new_dentry->d_inode) {
1687 new_isec = new_dentry->d_inode->i_security;
1688 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001689 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 new_isec->sclass,
1691 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1692 if (rc)
1693 return rc;
1694 }
1695
1696 return 0;
1697}
1698
1699/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001700static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 struct super_block *sb,
1702 u32 perms,
1703 struct avc_audit_data *ad)
1704{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001706 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001709 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710}
1711
1712/* Convert a Linux mode and permission mask to an access vector. */
1713static inline u32 file_mask_to_av(int mode, int mask)
1714{
1715 u32 av = 0;
1716
1717 if ((mode & S_IFMT) != S_IFDIR) {
1718 if (mask & MAY_EXEC)
1719 av |= FILE__EXECUTE;
1720 if (mask & MAY_READ)
1721 av |= FILE__READ;
1722
1723 if (mask & MAY_APPEND)
1724 av |= FILE__APPEND;
1725 else if (mask & MAY_WRITE)
1726 av |= FILE__WRITE;
1727
1728 } else {
1729 if (mask & MAY_EXEC)
1730 av |= DIR__SEARCH;
1731 if (mask & MAY_WRITE)
1732 av |= DIR__WRITE;
1733 if (mask & MAY_READ)
1734 av |= DIR__READ;
1735 }
1736
1737 return av;
1738}
1739
1740/* Convert a Linux file to an access vector. */
1741static inline u32 file_to_av(struct file *file)
1742{
1743 u32 av = 0;
1744
1745 if (file->f_mode & FMODE_READ)
1746 av |= FILE__READ;
1747 if (file->f_mode & FMODE_WRITE) {
1748 if (file->f_flags & O_APPEND)
1749 av |= FILE__APPEND;
1750 else
1751 av |= FILE__WRITE;
1752 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001753 if (!av) {
1754 /*
1755 * Special file opened with flags 3 for ioctl-only use.
1756 */
1757 av = FILE__IOCTL;
1758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 return av;
1761}
1762
Eric Paris8b6a5a32008-10-29 17:06:46 -04001763/*
1764 * Convert a file to an access vector and include the correct open
1765 * open permission.
1766 */
1767static inline u32 open_file_to_av(struct file *file)
1768{
1769 u32 av = file_to_av(file);
1770
1771 if (selinux_policycap_openperm) {
1772 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1773 /*
1774 * lnk files and socks do not really have an 'open'
1775 */
1776 if (S_ISREG(mode))
1777 av |= FILE__OPEN;
1778 else if (S_ISCHR(mode))
1779 av |= CHR_FILE__OPEN;
1780 else if (S_ISBLK(mode))
1781 av |= BLK_FILE__OPEN;
1782 else if (S_ISFIFO(mode))
1783 av |= FIFO_FILE__OPEN;
1784 else if (S_ISDIR(mode))
1785 av |= DIR__OPEN;
1786 else
1787 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1788 "unknown mode:%o\n", __func__, mode);
1789 }
1790 return av;
1791}
1792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793/* Hook functions begin here. */
1794
David Howells5cd9c582008-08-14 11:37:28 +01001795static int selinux_ptrace_may_access(struct task_struct *child,
1796 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 int rc;
1799
David Howells5cd9c582008-08-14 11:37:28 +01001800 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 if (rc)
1802 return rc;
1803
Stephen Smalley006ebb42008-05-19 08:32:49 -04001804 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001805 u32 sid = current_sid();
1806 u32 csid = task_sid(child);
1807 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001808 }
1809
David Howells5cd9c582008-08-14 11:37:28 +01001810 return task_has_perm(current, child, PROCESS__PTRACE);
1811}
1812
1813static int selinux_ptrace_traceme(struct task_struct *parent)
1814{
1815 int rc;
1816
1817 rc = secondary_ops->ptrace_traceme(parent);
1818 if (rc)
1819 return rc;
1820
1821 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822}
1823
1824static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001825 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826{
1827 int error;
1828
1829 error = task_has_perm(current, target, PROCESS__GETCAP);
1830 if (error)
1831 return error;
1832
1833 return secondary_ops->capget(target, effective, inheritable, permitted);
1834}
1835
David Howellsd84f4f92008-11-14 10:39:23 +11001836static int selinux_capset(struct cred *new, const struct cred *old,
1837 const kernel_cap_t *effective,
1838 const kernel_cap_t *inheritable,
1839 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840{
1841 int error;
1842
David Howellsd84f4f92008-11-14 10:39:23 +11001843 error = secondary_ops->capset(new, old,
1844 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if (error)
1846 return error;
1847
David Howellsd84f4f92008-11-14 10:39:23 +11001848 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849}
1850
Eric Paris06112162008-11-11 22:02:50 +11001851static int selinux_capable(struct task_struct *tsk, int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852{
1853 int rc;
1854
Eric Paris06112162008-11-11 22:02:50 +11001855 rc = secondary_ops->capable(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 if (rc)
1857 return rc;
1858
Eric Paris06112162008-11-11 22:02:50 +11001859 return task_has_capability(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860}
1861
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001862static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1863{
1864 int buflen, rc;
1865 char *buffer, *path, *end;
1866
1867 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001868 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001869 if (!buffer)
1870 goto out;
1871
1872 buflen = PAGE_SIZE;
1873 end = buffer+buflen;
1874 *--end = '\0';
1875 buflen--;
1876 path = end-1;
1877 *path = '/';
1878 while (table) {
1879 const char *name = table->procname;
1880 size_t namelen = strlen(name);
1881 buflen -= namelen + 1;
1882 if (buflen < 0)
1883 goto out_free;
1884 end -= namelen;
1885 memcpy(end, name, namelen);
1886 *--end = '/';
1887 path = end;
1888 table = table->parent;
1889 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001890 buflen -= 4;
1891 if (buflen < 0)
1892 goto out_free;
1893 end -= 4;
1894 memcpy(end, "/sys", 4);
1895 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001896 rc = security_genfs_sid("proc", path, tclass, sid);
1897out_free:
1898 free_page((unsigned long)buffer);
1899out:
1900 return rc;
1901}
1902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903static int selinux_sysctl(ctl_table *table, int op)
1904{
1905 int error = 0;
1906 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001907 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 int rc;
1909
1910 rc = secondary_ops->sysctl(table, op);
1911 if (rc)
1912 return rc;
1913
David Howells275bb412008-11-14 10:39:19 +11001914 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001916 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1917 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 if (rc) {
1919 /* Default to the well-defined sysctl SID. */
1920 tsid = SECINITSID_SYSCTL;
1921 }
1922
1923 /* The op values are "defined" in sysctl.c, thereby creating
1924 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001925 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11001926 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 SECCLASS_DIR, DIR__SEARCH, NULL);
1928 } else {
1929 av = 0;
1930 if (op & 004)
1931 av |= FILE__READ;
1932 if (op & 002)
1933 av |= FILE__WRITE;
1934 if (av)
David Howells275bb412008-11-14 10:39:19 +11001935 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
1939 return error;
1940}
1941
1942static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1943{
David Howells88e67f32008-11-14 10:39:21 +11001944 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 int rc = 0;
1946
1947 if (!sb)
1948 return 0;
1949
1950 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001951 case Q_SYNC:
1952 case Q_QUOTAON:
1953 case Q_QUOTAOFF:
1954 case Q_SETINFO:
1955 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001956 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001957 break;
1958 case Q_GETFMT:
1959 case Q_GETINFO:
1960 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001961 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001962 break;
1963 default:
1964 rc = 0; /* let the kernel handle invalid cmds */
1965 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 }
1967 return rc;
1968}
1969
1970static int selinux_quota_on(struct dentry *dentry)
1971{
David Howells88e67f32008-11-14 10:39:21 +11001972 const struct cred *cred = current_cred();
1973
1974 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975}
1976
1977static int selinux_syslog(int type)
1978{
1979 int rc;
1980
1981 rc = secondary_ops->syslog(type);
1982 if (rc)
1983 return rc;
1984
1985 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04001986 case 3: /* Read last kernel messages */
1987 case 10: /* Return size of the log buffer */
1988 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1989 break;
1990 case 6: /* Disable logging to console */
1991 case 7: /* Enable logging to console */
1992 case 8: /* Set level of messages printed to console */
1993 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1994 break;
1995 case 0: /* Close log */
1996 case 1: /* Open log */
1997 case 2: /* Read from log */
1998 case 4: /* Read/clear last kernel messages */
1999 case 5: /* Clear ring buffer */
2000 default:
2001 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2002 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 }
2004 return rc;
2005}
2006
2007/*
2008 * Check that a process has enough memory to allocate a new virtual
2009 * mapping. 0 means there is enough memory for the allocation to
2010 * succeed and -ENOMEM implies there is not.
2011 *
2012 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
2013 * if the capability is granted, but __vm_enough_memory requires 1 if
2014 * the capability is granted.
2015 *
2016 * Do not audit the selinux permission check, as this is applied to all
2017 * processes that allocate mappings.
2018 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002019static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020{
2021 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
Eric Paris06674672008-11-11 22:02:57 +11002023 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 if (rc == 0)
2025 cap_sys_admin = 1;
2026
Alan Cox34b4e4a2007-08-22 14:01:28 -07002027 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028}
2029
2030/* binprm security operations */
2031
2032static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
2033{
2034 struct bprm_security_struct *bsec;
2035
James Morris89d155e2005-10-30 14:59:21 -08002036 bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 if (!bsec)
2038 return -ENOMEM;
2039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 bsec->sid = SECINITSID_UNLABELED;
2041 bsec->set = 0;
2042
2043 bprm->security = bsec;
2044 return 0;
2045}
2046
2047static int selinux_bprm_set_security(struct linux_binprm *bprm)
2048{
2049 struct task_security_struct *tsec;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002050 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 struct inode_security_struct *isec;
2052 struct bprm_security_struct *bsec;
2053 u32 newsid;
2054 struct avc_audit_data ad;
2055 int rc;
2056
2057 rc = secondary_ops->bprm_set_security(bprm);
2058 if (rc)
2059 return rc;
2060
2061 bsec = bprm->security;
2062
2063 if (bsec->set)
2064 return 0;
2065
David Howells275bb412008-11-14 10:39:19 +11002066 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 isec = inode->i_security;
2068
2069 /* Default to the current task SID. */
2070 bsec->sid = tsec->sid;
2071
Michael LeMay28eba5b2006-06-27 02:53:42 -07002072 /* Reset fs, key, and sock SIDs on execve. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 tsec->create_sid = 0;
Michael LeMay28eba5b2006-06-27 02:53:42 -07002074 tsec->keycreate_sid = 0;
Eric Paris42c3e032006-06-26 00:26:03 -07002075 tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
2077 if (tsec->exec_sid) {
2078 newsid = tsec->exec_sid;
2079 /* Reset exec SID on execve. */
2080 tsec->exec_sid = 0;
2081 } else {
2082 /* Check for a default transition on this program. */
2083 rc = security_transition_sid(tsec->sid, isec->sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002084 SECCLASS_PROCESS, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 if (rc)
2086 return rc;
2087 }
2088
2089 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002090 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
Josef Sipek3d5ff522006-12-08 02:37:38 -08002092 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 newsid = tsec->sid;
2094
Eric Paris828dfe12008-04-17 13:17:49 -04002095 if (tsec->sid == newsid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 rc = avc_has_perm(tsec->sid, isec->sid,
2097 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2098 if (rc)
2099 return rc;
2100 } else {
2101 /* Check permissions for the transition. */
2102 rc = avc_has_perm(tsec->sid, newsid,
2103 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2104 if (rc)
2105 return rc;
2106
2107 rc = avc_has_perm(newsid, isec->sid,
2108 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2109 if (rc)
2110 return rc;
2111
2112 /* Clear any possibly unsafe personality bits on exec: */
2113 current->personality &= ~PER_CLEAR_ON_SETID;
2114
2115 /* Set the security field to the new SID. */
2116 bsec->sid = newsid;
2117 }
2118
2119 bsec->set = 1;
2120 return 0;
2121}
2122
Eric Paris828dfe12008-04-17 13:17:49 -04002123static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124{
2125 return secondary_ops->bprm_check_security(bprm);
2126}
2127
2128
Eric Paris828dfe12008-04-17 13:17:49 -04002129static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130{
David Howells275bb412008-11-14 10:39:19 +11002131 const struct cred *cred = current_cred();
2132 const struct task_security_struct *tsec = cred->security;
2133 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 int atsecure = 0;
2135
David Howells275bb412008-11-14 10:39:19 +11002136 sid = tsec->sid;
2137 osid = tsec->osid;
2138
2139 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 /* Enable secure mode for SIDs transitions unless
2141 the noatsecure permission is granted between
2142 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002143 atsecure = avc_has_perm(osid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 SECCLASS_PROCESS,
2145 PROCESS__NOATSECURE, NULL);
2146 }
2147
2148 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2149}
2150
2151static void selinux_bprm_free_security(struct linux_binprm *bprm)
2152{
Jesper Juhl9a5f04b2005-06-25 14:58:51 -07002153 kfree(bprm->security);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 bprm->security = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155}
2156
2157extern struct vfsmount *selinuxfs_mount;
2158extern struct dentry *selinux_null;
2159
2160/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002161static inline void flush_unauthorized_files(const struct cred *cred,
2162 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
2164 struct avc_audit_data ad;
2165 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002166 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002167 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002169 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002171 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if (tty) {
2173 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002174 if (!list_empty(&tty->tty_files)) {
2175 struct inode *inode;
2176
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 /* Revalidate access to controlling tty.
2178 Use inode_has_perm on the tty inode directly rather
2179 than using file_has_perm, as this particular open
2180 file may belong to another process and we are only
2181 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002182 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2183 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002184 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002186 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 }
2188 }
2189 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002190 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002192 /* Reset controlling tty. */
2193 if (drop_tty)
2194 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
2196 /* Revalidate access to inherited open files. */
2197
Eric Paris828dfe12008-04-17 13:17:49 -04002198 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
2200 spin_lock(&files->file_lock);
2201 for (;;) {
2202 unsigned long set, i;
2203 int fd;
2204
2205 j++;
2206 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002207 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002208 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002210 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 if (!set)
2212 continue;
2213 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002214 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 if (set & 1) {
2216 file = fget(i);
2217 if (!file)
2218 continue;
David Howells88e67f32008-11-14 10:39:21 +11002219 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 file,
2221 file_to_av(file))) {
2222 sys_close(i);
2223 fd = get_unused_fd();
2224 if (fd != i) {
2225 if (fd >= 0)
2226 put_unused_fd(fd);
2227 fput(file);
2228 continue;
2229 }
2230 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002231 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 } else {
David Howells745ca242008-11-14 10:39:22 +11002233 devnull = dentry_open(
2234 dget(selinux_null),
2235 mntget(selinuxfs_mount),
2236 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002237 if (IS_ERR(devnull)) {
2238 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 put_unused_fd(fd);
2240 fput(file);
2241 continue;
2242 }
2243 }
2244 fd_install(fd, devnull);
2245 }
2246 fput(file);
2247 }
2248 }
2249 spin_lock(&files->file_lock);
2250
2251 }
2252 spin_unlock(&files->file_lock);
2253}
2254
David Howellsd84f4f92008-11-14 10:39:23 +11002255static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256{
2257 struct task_security_struct *tsec;
2258 struct bprm_security_struct *bsec;
David Howellsd84f4f92008-11-14 10:39:23 +11002259 struct cred *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 u32 sid;
2261 int rc;
2262
David Howellsd84f4f92008-11-14 10:39:23 +11002263 rc = secondary_ops->bprm_apply_creds(bprm, unsafe);
2264 if (rc < 0)
2265 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
David Howellsd84f4f92008-11-14 10:39:23 +11002267 new = prepare_creds();
2268 if (!new)
2269 return -ENOMEM;
2270
2271 tsec = new->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
2273 bsec = bprm->security;
2274 sid = bsec->sid;
2275
2276 tsec->osid = tsec->sid;
2277 bsec->unsafe = 0;
2278 if (tsec->sid != sid) {
2279 /* Check for shared state. If not ok, leave SID
2280 unchanged and kill. */
2281 if (unsafe & LSM_UNSAFE_SHARE) {
2282 rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
2283 PROCESS__SHARE, NULL);
2284 if (rc) {
2285 bsec->unsafe = 1;
David Howellsd84f4f92008-11-14 10:39:23 +11002286 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 }
2288 }
2289
2290 /* Check for ptracing, and update the task SID if ok.
2291 Otherwise, leave SID unchanged and kill. */
2292 if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
Roland McGrath03563572008-03-26 15:46:39 -07002293 struct task_struct *tracer;
2294 struct task_security_struct *sec;
2295 u32 ptsid = 0;
2296
2297 rcu_read_lock();
Roland McGrath0d094ef2008-07-25 19:45:49 -07002298 tracer = tracehook_tracer_task(current);
Roland McGrath03563572008-03-26 15:46:39 -07002299 if (likely(tracer != NULL)) {
David Howells275bb412008-11-14 10:39:19 +11002300 sec = __task_cred(tracer)->security;
Roland McGrath03563572008-03-26 15:46:39 -07002301 ptsid = sec->sid;
2302 }
2303 rcu_read_unlock();
2304
2305 if (ptsid != 0) {
2306 rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
2307 PROCESS__PTRACE, NULL);
2308 if (rc) {
2309 bsec->unsafe = 1;
David Howellsd84f4f92008-11-14 10:39:23 +11002310 goto out;
Roland McGrath03563572008-03-26 15:46:39 -07002311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 }
2313 }
2314 tsec->sid = sid;
2315 }
David Howellsd84f4f92008-11-14 10:39:23 +11002316
2317out:
2318 commit_creds(new);
2319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320}
2321
2322/*
2323 * called after apply_creds without the task lock held
2324 */
2325static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
2326{
David Howells745ca242008-11-14 10:39:22 +11002327 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 struct task_security_struct *tsec;
2329 struct rlimit *rlim, *initrlim;
2330 struct itimerval itimer;
2331 struct bprm_security_struct *bsec;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002332 struct sighand_struct *psig;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 int rc, i;
Eric Paris41d9f9c2008-11-04 15:18:26 -05002334 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335
David Howells275bb412008-11-14 10:39:19 +11002336 tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 bsec = bprm->security;
2338
2339 if (bsec->unsafe) {
2340 force_sig_specific(SIGKILL, current);
2341 return;
2342 }
2343 if (tsec->osid == tsec->sid)
2344 return;
2345
2346 /* Close files for which the new task SID is not authorized. */
David Howells745ca242008-11-14 10:39:22 +11002347 flush_unauthorized_files(cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349 /* Check whether the new SID can inherit signal state
2350 from the old SID. If not, clear itimers to avoid
2351 subsequent signal generation and flush and unblock
2352 signals. This must occur _after_ the task SID has
2353 been updated so that any kill done after the flush
2354 will be checked against the new SID. */
2355 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2356 PROCESS__SIGINH, NULL);
2357 if (rc) {
2358 memset(&itimer, 0, sizeof itimer);
2359 for (i = 0; i < 3; i++)
2360 do_setitimer(i, &itimer, NULL);
2361 flush_signals(current);
2362 spin_lock_irq(&current->sighand->siglock);
2363 flush_signal_handlers(current, 1);
2364 sigemptyset(&current->blocked);
2365 recalc_sigpending();
2366 spin_unlock_irq(&current->sighand->siglock);
2367 }
2368
Stephen Smalley4ac212a2007-08-29 08:51:50 -04002369 /* Always clear parent death signal on SID transitions. */
2370 current->pdeath_signal = 0;
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 /* Check whether the new SID can inherit resource limits
2373 from the old SID. If not, reset all soft limits to
2374 the lower of the current task's hard limit and the init
2375 task's soft limit. Note that the setting of hard limits
2376 (even to lower them) can be controlled by the setrlimit
2377 check. The inclusion of the init task's soft limit into
2378 the computation is to avoid resetting soft limits higher
2379 than the default soft limit for cases where the default
2380 is lower than the hard limit, e.g. RLIMIT_CORE or
2381 RLIMIT_STACK.*/
2382 rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
2383 PROCESS__RLIMITINH, NULL);
2384 if (rc) {
2385 for (i = 0; i < RLIM_NLIMITS; i++) {
2386 rlim = current->signal->rlim + i;
2387 initrlim = init_task.signal->rlim+i;
Eric Paris828dfe12008-04-17 13:17:49 -04002388 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 }
Frank Mayharf06febc2008-09-12 09:54:39 -07002390 update_rlimit_cpu(rlim->rlim_cur);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 }
2392
2393 /* Wake up the parent if it is waiting so that it can
2394 recheck wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002395 read_lock_irq(&tasklist_lock);
2396 psig = current->parent->sighand;
2397 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002399 spin_unlock_irqrestore(&psig->siglock, flags);
2400 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401}
2402
2403/* superblock security operations */
2404
2405static int selinux_sb_alloc_security(struct super_block *sb)
2406{
2407 return superblock_alloc_security(sb);
2408}
2409
2410static void selinux_sb_free_security(struct super_block *sb)
2411{
2412 superblock_free_security(sb);
2413}
2414
2415static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2416{
2417 if (plen > olen)
2418 return 0;
2419
2420 return !memcmp(prefix, option, plen);
2421}
2422
2423static inline int selinux_option(char *option, int len)
2424{
Eric Paris832cbd92008-04-01 13:24:09 -04002425 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2426 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2427 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2428 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429}
2430
2431static inline void take_option(char **to, char *from, int *first, int len)
2432{
2433 if (!*first) {
2434 **to = ',';
2435 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002436 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 *first = 0;
2438 memcpy(*to, from, len);
2439 *to += len;
2440}
2441
Eric Paris828dfe12008-04-17 13:17:49 -04002442static inline void take_selinux_option(char **to, char *from, int *first,
2443 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002444{
2445 int current_size = 0;
2446
2447 if (!*first) {
2448 **to = '|';
2449 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002450 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002451 *first = 0;
2452
2453 while (current_size < len) {
2454 if (*from != '"') {
2455 **to = *from;
2456 *to += 1;
2457 }
2458 from += 1;
2459 current_size += 1;
2460 }
2461}
2462
Eric Parise0007522008-03-05 10:31:54 -05002463static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464{
2465 int fnosec, fsec, rc = 0;
2466 char *in_save, *in_curr, *in_end;
2467 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002468 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
2470 in_curr = orig;
2471 sec_curr = copy;
2472
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2474 if (!nosec) {
2475 rc = -ENOMEM;
2476 goto out;
2477 }
2478
2479 nosec_save = nosec;
2480 fnosec = fsec = 1;
2481 in_save = in_end = orig;
2482
2483 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002484 if (*in_end == '"')
2485 open_quote = !open_quote;
2486 if ((*in_end == ',' && open_quote == 0) ||
2487 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 int len = in_end - in_curr;
2489
2490 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002491 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 else
2493 take_option(&nosec, in_curr, &fnosec, len);
2494
2495 in_curr = in_end + 1;
2496 }
2497 } while (*in_end++);
2498
Eric Paris6931dfc2005-06-30 02:58:51 -07002499 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002500 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501out:
2502 return rc;
2503}
2504
2505static int selinux_sb_kern_mount(struct super_block *sb, void *data)
2506{
David Howells88e67f32008-11-14 10:39:21 +11002507 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 struct avc_audit_data ad;
2509 int rc;
2510
2511 rc = superblock_doinit(sb, data);
2512 if (rc)
2513 return rc;
2514
Eric Paris828dfe12008-04-17 13:17:49 -04002515 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002516 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002517 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518}
2519
David Howells726c3342006-06-23 02:02:58 -07002520static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521{
David Howells88e67f32008-11-14 10:39:21 +11002522 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 struct avc_audit_data ad;
2524
Eric Paris828dfe12008-04-17 13:17:49 -04002525 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002526 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002527 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528}
2529
Eric Paris828dfe12008-04-17 13:17:49 -04002530static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002531 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002532 char *type,
2533 unsigned long flags,
2534 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
David Howells88e67f32008-11-14 10:39:21 +11002536 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 int rc;
2538
Al Virob5266eb2008-03-22 17:48:24 -04002539 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 if (rc)
2541 return rc;
2542
2543 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002544 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002545 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 else
David Howells88e67f32008-11-14 10:39:21 +11002547 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002548 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549}
2550
2551static int selinux_umount(struct vfsmount *mnt, int flags)
2552{
David Howells88e67f32008-11-14 10:39:21 +11002553 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 int rc;
2555
2556 rc = secondary_ops->sb_umount(mnt, flags);
2557 if (rc)
2558 return rc;
2559
David Howells88e67f32008-11-14 10:39:21 +11002560 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002561 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562}
2563
2564/* inode security operations */
2565
2566static int selinux_inode_alloc_security(struct inode *inode)
2567{
2568 return inode_alloc_security(inode);
2569}
2570
2571static void selinux_inode_free_security(struct inode *inode)
2572{
2573 inode_free_security(inode);
2574}
2575
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002576static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2577 char **name, void **value,
2578 size_t *len)
2579{
David Howells275bb412008-11-14 10:39:19 +11002580 const struct cred *cred = current_cred();
2581 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002582 struct inode_security_struct *dsec;
2583 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002584 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002585 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002586 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002587
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002588 dsec = dir->i_security;
2589 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002590
David Howells275bb412008-11-14 10:39:19 +11002591 sid = tsec->sid;
2592 newsid = tsec->create_sid;
2593
2594 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
2595 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002596 inode_mode_to_security_class(inode->i_mode),
2597 &newsid);
2598 if (rc) {
2599 printk(KERN_WARNING "%s: "
2600 "security_transition_sid failed, rc=%d (dev=%s "
2601 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002602 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002603 -rc, inode->i_sb->s_id, inode->i_ino);
2604 return rc;
2605 }
2606 }
2607
Eric Paris296fddf2006-09-25 23:32:00 -07002608 /* Possibly defer initialization to selinux_complete_init. */
2609 if (sbsec->initialized) {
2610 struct inode_security_struct *isec = inode->i_security;
2611 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2612 isec->sid = newsid;
2613 isec->initialized = 1;
2614 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002615
Stephen Smalley8aad3872006-03-22 00:09:13 -08002616 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002617 return -EOPNOTSUPP;
2618
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002619 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002620 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002621 if (!namep)
2622 return -ENOMEM;
2623 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002624 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002625
2626 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002627 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002628 if (rc) {
2629 kfree(namep);
2630 return rc;
2631 }
2632 *value = context;
2633 *len = clen;
2634 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002635
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002636 return 0;
2637}
2638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2640{
2641 return may_create(dir, dentry, SECCLASS_FILE);
2642}
2643
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2645{
2646 int rc;
2647
Eric Paris828dfe12008-04-17 13:17:49 -04002648 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 if (rc)
2650 return rc;
2651 return may_link(dir, old_dentry, MAY_LINK);
2652}
2653
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2655{
2656 int rc;
2657
2658 rc = secondary_ops->inode_unlink(dir, dentry);
2659 if (rc)
2660 return rc;
2661 return may_link(dir, dentry, MAY_UNLINK);
2662}
2663
2664static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2665{
2666 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2667}
2668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2670{
2671 return may_create(dir, dentry, SECCLASS_DIR);
2672}
2673
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2675{
2676 return may_link(dir, dentry, MAY_RMDIR);
2677}
2678
2679static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2680{
2681 int rc;
2682
2683 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2684 if (rc)
2685 return rc;
2686
2687 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2688}
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002691 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692{
2693 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2694}
2695
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696static int selinux_inode_readlink(struct dentry *dentry)
2697{
David Howells88e67f32008-11-14 10:39:21 +11002698 const struct cred *cred = current_cred();
2699
2700 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701}
2702
2703static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2704{
David Howells88e67f32008-11-14 10:39:21 +11002705 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 int rc;
2707
Eric Paris828dfe12008-04-17 13:17:49 -04002708 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 if (rc)
2710 return rc;
David Howells88e67f32008-11-14 10:39:21 +11002711 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712}
2713
Al Virob77b0642008-07-17 09:37:02 -04002714static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715{
David Howells88e67f32008-11-14 10:39:21 +11002716 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 int rc;
2718
Al Virob77b0642008-07-17 09:37:02 -04002719 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 if (rc)
2721 return rc;
2722
2723 if (!mask) {
2724 /* No permission to check. Existence test. */
2725 return 0;
2726 }
2727
David Howells88e67f32008-11-14 10:39:21 +11002728 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002729 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730}
2731
2732static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2733{
David Howells88e67f32008-11-14 10:39:21 +11002734 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 int rc;
2736
2737 rc = secondary_ops->inode_setattr(dentry, iattr);
2738 if (rc)
2739 return rc;
2740
2741 if (iattr->ia_valid & ATTR_FORCE)
2742 return 0;
2743
2744 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2745 ATTR_ATIME_SET | ATTR_MTIME_SET))
David Howells88e67f32008-11-14 10:39:21 +11002746 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
David Howells88e67f32008-11-14 10:39:21 +11002748 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749}
2750
2751static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2752{
David Howells88e67f32008-11-14 10:39:21 +11002753 const struct cred *cred = current_cred();
2754
2755 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756}
2757
David Howells8f0cfa52008-04-29 00:59:41 -07002758static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002759{
David Howells88e67f32008-11-14 10:39:21 +11002760 const struct cred *cred = current_cred();
2761
Serge E. Hallynb5376772007-10-16 23:31:36 -07002762 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2763 sizeof XATTR_SECURITY_PREFIX - 1)) {
2764 if (!strcmp(name, XATTR_NAME_CAPS)) {
2765 if (!capable(CAP_SETFCAP))
2766 return -EPERM;
2767 } else if (!capable(CAP_SYS_ADMIN)) {
2768 /* A different attribute in the security namespace.
2769 Restrict to administrator. */
2770 return -EPERM;
2771 }
2772 }
2773
2774 /* Not an attribute we recognize, so just check the
2775 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002776 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002777}
2778
David Howells8f0cfa52008-04-29 00:59:41 -07002779static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2780 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 struct inode *inode = dentry->d_inode;
2783 struct inode_security_struct *isec = inode->i_security;
2784 struct superblock_security_struct *sbsec;
2785 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002786 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 int rc = 0;
2788
Serge E. Hallynb5376772007-10-16 23:31:36 -07002789 if (strcmp(name, XATTR_NAME_SELINUX))
2790 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791
2792 sbsec = inode->i_sb->s_security;
2793 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2794 return -EOPNOTSUPP;
2795
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302796 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 return -EPERM;
2798
Eric Paris828dfe12008-04-17 13:17:49 -04002799 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002800 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
David Howells275bb412008-11-14 10:39:19 +11002802 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 FILE__RELABELFROM, &ad);
2804 if (rc)
2805 return rc;
2806
2807 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002808 if (rc == -EINVAL) {
2809 if (!capable(CAP_MAC_ADMIN))
2810 return rc;
2811 rc = security_context_to_sid_force(value, size, &newsid);
2812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 if (rc)
2814 return rc;
2815
David Howells275bb412008-11-14 10:39:19 +11002816 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 FILE__RELABELTO, &ad);
2818 if (rc)
2819 return rc;
2820
David Howells275bb412008-11-14 10:39:19 +11002821 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002822 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 if (rc)
2824 return rc;
2825
2826 return avc_has_perm(newsid,
2827 sbsec->sid,
2828 SECCLASS_FILESYSTEM,
2829 FILESYSTEM__ASSOCIATE,
2830 &ad);
2831}
2832
David Howells8f0cfa52008-04-29 00:59:41 -07002833static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002834 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002835 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836{
2837 struct inode *inode = dentry->d_inode;
2838 struct inode_security_struct *isec = inode->i_security;
2839 u32 newsid;
2840 int rc;
2841
2842 if (strcmp(name, XATTR_NAME_SELINUX)) {
2843 /* Not an attribute we recognize, so nothing to do. */
2844 return;
2845 }
2846
Stephen Smalley12b29f32008-05-07 13:03:20 -04002847 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002849 printk(KERN_ERR "SELinux: unable to map context to SID"
2850 "for (%s, %lu), rc=%d\n",
2851 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 return;
2853 }
2854
2855 isec->sid = newsid;
2856 return;
2857}
2858
David Howells8f0cfa52008-04-29 00:59:41 -07002859static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860{
David Howells88e67f32008-11-14 10:39:21 +11002861 const struct cred *cred = current_cred();
2862
2863 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864}
2865
Eric Paris828dfe12008-04-17 13:17:49 -04002866static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867{
David Howells88e67f32008-11-14 10:39:21 +11002868 const struct cred *cred = current_cred();
2869
2870 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871}
2872
David Howells8f0cfa52008-04-29 00:59:41 -07002873static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002875 if (strcmp(name, XATTR_NAME_SELINUX))
2876 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
2878 /* No one is allowed to remove a SELinux security label.
2879 You can change the label, but all data must be labeled. */
2880 return -EACCES;
2881}
2882
James Morrisd381d8a2005-10-30 14:59:22 -08002883/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002884 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002885 *
2886 * Permission check is handled by selinux_inode_getxattr hook.
2887 */
David P. Quigley42492592008-02-04 22:29:39 -08002888static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
David P. Quigley42492592008-02-04 22:29:39 -08002890 u32 size;
2891 int error;
2892 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002895 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2896 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002898 /*
2899 * If the caller has CAP_MAC_ADMIN, then get the raw context
2900 * value even if it is not defined by current policy; otherwise,
2901 * use the in-core value under current policy.
2902 * Use the non-auditing forms of the permission checks since
2903 * getxattr may be called by unprivileged processes commonly
2904 * and lack of permission just means that we fall back to the
2905 * in-core context value, not a denial.
2906 */
Eric Paris06674672008-11-11 22:02:57 +11002907 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002908 if (!error)
2909 error = security_sid_to_context_force(isec->sid, &context,
2910 &size);
2911 else
2912 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002913 if (error)
2914 return error;
2915 error = size;
2916 if (alloc) {
2917 *buffer = context;
2918 goto out_nofree;
2919 }
2920 kfree(context);
2921out_nofree:
2922 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923}
2924
2925static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002926 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927{
2928 struct inode_security_struct *isec = inode->i_security;
2929 u32 newsid;
2930 int rc;
2931
2932 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2933 return -EOPNOTSUPP;
2934
2935 if (!value || !size)
2936 return -EACCES;
2937
Eric Paris828dfe12008-04-17 13:17:49 -04002938 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 if (rc)
2940 return rc;
2941
2942 isec->sid = newsid;
2943 return 0;
2944}
2945
2946static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2947{
2948 const int len = sizeof(XATTR_NAME_SELINUX);
2949 if (buffer && len <= buffer_size)
2950 memcpy(buffer, XATTR_NAME_SELINUX, len);
2951 return len;
2952}
2953
Serge E. Hallynb5376772007-10-16 23:31:36 -07002954static int selinux_inode_need_killpriv(struct dentry *dentry)
2955{
2956 return secondary_ops->inode_need_killpriv(dentry);
2957}
2958
2959static int selinux_inode_killpriv(struct dentry *dentry)
2960{
2961 return secondary_ops->inode_killpriv(dentry);
2962}
2963
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002964static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2965{
2966 struct inode_security_struct *isec = inode->i_security;
2967 *secid = isec->sid;
2968}
2969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970/* file security operations */
2971
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002972static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973{
David Howells88e67f32008-11-14 10:39:21 +11002974 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002975 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002976 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
2978 if (!mask) {
2979 /* No permission to check. Existence test. */
2980 return 0;
2981 }
2982
2983 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2984 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2985 mask |= MAY_APPEND;
2986
David Howells88e67f32008-11-14 10:39:21 +11002987 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002988 file_mask_to_av(inode->i_mode, mask));
2989 if (rc)
2990 return rc;
2991
2992 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993}
2994
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002995static int selinux_file_permission(struct file *file, int mask)
2996{
2997 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002998 struct file_security_struct *fsec = file->f_security;
2999 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003000 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003001
3002 if (!mask) {
3003 /* No permission to check. Existence test. */
3004 return 0;
3005 }
3006
David Howells275bb412008-11-14 10:39:19 +11003007 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003008 && fsec->pseqno == avc_policy_seqno())
3009 return selinux_netlbl_inode_permission(inode, mask);
3010
3011 return selinux_revalidate_file_permission(file, mask);
3012}
3013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014static int selinux_file_alloc_security(struct file *file)
3015{
3016 return file_alloc_security(file);
3017}
3018
3019static void selinux_file_free_security(struct file *file)
3020{
3021 file_free_security(file);
3022}
3023
3024static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3025 unsigned long arg)
3026{
David Howells88e67f32008-11-14 10:39:21 +11003027 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04003028 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Stephen Smalley242631c2008-06-05 09:21:28 -04003030 if (_IOC_DIR(cmd) & _IOC_WRITE)
3031 av |= FILE__WRITE;
3032 if (_IOC_DIR(cmd) & _IOC_READ)
3033 av |= FILE__READ;
3034 if (!av)
3035 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
David Howells88e67f32008-11-14 10:39:21 +11003037 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038}
3039
3040static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3041{
David Howells88e67f32008-11-14 10:39:21 +11003042 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003043 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003044
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045#ifndef CONFIG_PPC32
3046 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3047 /*
3048 * We are making executable an anonymous mapping or a
3049 * private file mapping that will also be writable.
3050 * This has an additional check.
3051 */
David Howellsd84f4f92008-11-14 10:39:23 +11003052 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003054 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 }
3056#endif
3057
3058 if (file) {
3059 /* read access is always possible with a mapping */
3060 u32 av = FILE__READ;
3061
3062 /* write access only matters if the mapping is shared */
3063 if (shared && (prot & PROT_WRITE))
3064 av |= FILE__WRITE;
3065
3066 if (prot & PROT_EXEC)
3067 av |= FILE__EXECUTE;
3068
David Howells88e67f32008-11-14 10:39:21 +11003069 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 }
David Howellsd84f4f92008-11-14 10:39:23 +11003071
3072error:
3073 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074}
3075
3076static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003077 unsigned long prot, unsigned long flags,
3078 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079{
Eric Parised032182007-06-28 15:55:21 -04003080 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003081 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
Eric Parised032182007-06-28 15:55:21 -04003083 if (addr < mmap_min_addr)
3084 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3085 MEMPROTECT__MMAP_ZERO, NULL);
3086 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 return rc;
3088
3089 if (selinux_checkreqprot)
3090 prot = reqprot;
3091
3092 return file_map_prot_check(file, prot,
3093 (flags & MAP_TYPE) == MAP_SHARED);
3094}
3095
3096static int selinux_file_mprotect(struct vm_area_struct *vma,
3097 unsigned long reqprot,
3098 unsigned long prot)
3099{
David Howells88e67f32008-11-14 10:39:21 +11003100 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 int rc;
3102
3103 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3104 if (rc)
3105 return rc;
3106
3107 if (selinux_checkreqprot)
3108 prot = reqprot;
3109
3110#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003111 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3112 rc = 0;
3113 if (vma->vm_start >= vma->vm_mm->start_brk &&
3114 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003115 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003116 } else if (!vma->vm_file &&
3117 vma->vm_start <= vma->vm_mm->start_stack &&
3118 vma->vm_end >= vma->vm_mm->start_stack) {
3119 rc = task_has_perm(current, current, PROCESS__EXECSTACK);
3120 } else if (vma->vm_file && vma->anon_vma) {
3121 /*
3122 * We are making executable a file mapping that has
3123 * had some COW done. Since pages might have been
3124 * written, check ability to execute the possibly
3125 * modified content. This typically should only
3126 * occur for text relocations.
3127 */
David Howellsd84f4f92008-11-14 10:39:23 +11003128 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003129 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003130 if (rc)
3131 return rc;
3132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133#endif
3134
3135 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3136}
3137
3138static int selinux_file_lock(struct file *file, unsigned int cmd)
3139{
David Howells88e67f32008-11-14 10:39:21 +11003140 const struct cred *cred = current_cred();
3141
3142 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143}
3144
3145static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3146 unsigned long arg)
3147{
David Howells88e67f32008-11-14 10:39:21 +11003148 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 int err = 0;
3150
3151 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003152 case F_SETFL:
3153 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3154 err = -EINVAL;
3155 break;
3156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157
Eric Paris828dfe12008-04-17 13:17:49 -04003158 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003159 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003161 }
3162 /* fall through */
3163 case F_SETOWN:
3164 case F_SETSIG:
3165 case F_GETFL:
3166 case F_GETOWN:
3167 case F_GETSIG:
3168 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003169 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003170 break;
3171 case F_GETLK:
3172 case F_SETLK:
3173 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003175 case F_GETLK64:
3176 case F_SETLK64:
3177 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003179 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3180 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003182 }
David Howells88e67f32008-11-14 10:39:21 +11003183 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003184 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 }
3186
3187 return err;
3188}
3189
3190static int selinux_file_set_fowner(struct file *file)
3191{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 struct file_security_struct *fsec;
3193
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003195 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197 return 0;
3198}
3199
3200static int selinux_file_send_sigiotask(struct task_struct *tsk,
3201 struct fown_struct *fown, int signum)
3202{
Eric Paris828dfe12008-04-17 13:17:49 -04003203 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003204 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 struct file_security_struct *fsec;
3207
3208 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003209 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 fsec = file->f_security;
3212
3213 if (!signum)
3214 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3215 else
3216 perm = signal_to_av(signum);
3217
David Howells275bb412008-11-14 10:39:19 +11003218 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 SECCLASS_PROCESS, perm, NULL);
3220}
3221
3222static int selinux_file_receive(struct file *file)
3223{
David Howells88e67f32008-11-14 10:39:21 +11003224 const struct cred *cred = current_cred();
3225
3226 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227}
3228
David Howells745ca242008-11-14 10:39:22 +11003229static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003230{
3231 struct file_security_struct *fsec;
3232 struct inode *inode;
3233 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003234
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003235 inode = file->f_path.dentry->d_inode;
3236 fsec = file->f_security;
3237 isec = inode->i_security;
3238 /*
3239 * Save inode label and policy sequence number
3240 * at open-time so that selinux_file_permission
3241 * can determine whether revalidation is necessary.
3242 * Task label is already saved in the file security
3243 * struct as its SID.
3244 */
3245 fsec->isid = isec->sid;
3246 fsec->pseqno = avc_policy_seqno();
3247 /*
3248 * Since the inode label or policy seqno may have changed
3249 * between the selinux_inode_permission check and the saving
3250 * of state above, recheck that access is still permitted.
3251 * Otherwise, access might never be revalidated against the
3252 * new inode label or new policy.
3253 * This check is not redundant - do not remove.
3254 */
David Howells88e67f32008-11-14 10:39:21 +11003255 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003256}
3257
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258/* task security operations */
3259
3260static int selinux_task_create(unsigned long clone_flags)
3261{
3262 int rc;
3263
3264 rc = secondary_ops->task_create(clone_flags);
3265 if (rc)
3266 return rc;
3267
3268 return task_has_perm(current, current, PROCESS__FORK);
3269}
3270
David Howellsf1752ee2008-11-14 10:39:17 +11003271/*
3272 * detach and free the LSM part of a set of credentials
3273 */
3274static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275{
David Howellsf1752ee2008-11-14 10:39:17 +11003276 struct task_security_struct *tsec = cred->security;
3277 cred->security = NULL;
3278 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279}
3280
David Howellsd84f4f92008-11-14 10:39:23 +11003281/*
3282 * prepare a new set of credentials for modification
3283 */
3284static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3285 gfp_t gfp)
3286{
3287 const struct task_security_struct *old_tsec;
3288 struct task_security_struct *tsec;
3289
3290 old_tsec = old->security;
3291
3292 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3293 if (!tsec)
3294 return -ENOMEM;
3295
3296 new->security = tsec;
3297 return 0;
3298}
3299
3300/*
3301 * commit new credentials
3302 */
3303static void selinux_cred_commit(struct cred *new, const struct cred *old)
3304{
3305 secondary_ops->cred_commit(new, old);
3306}
3307
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3309{
3310 /* Since setuid only affects the current process, and
3311 since the SELinux controls are not based on the Linux
3312 identity attributes, SELinux does not need to control
3313 this operation. However, SELinux does control the use
3314 of the CAP_SETUID and CAP_SETGID capabilities using the
3315 capable hook. */
3316 return 0;
3317}
3318
David Howellsd84f4f92008-11-14 10:39:23 +11003319static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3320 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321{
David Howellsd84f4f92008-11-14 10:39:23 +11003322 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323}
3324
3325static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3326{
3327 /* See the comment for setuid above. */
3328 return 0;
3329}
3330
3331static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3332{
3333 return task_has_perm(current, p, PROCESS__SETPGID);
3334}
3335
3336static int selinux_task_getpgid(struct task_struct *p)
3337{
3338 return task_has_perm(current, p, PROCESS__GETPGID);
3339}
3340
3341static int selinux_task_getsid(struct task_struct *p)
3342{
3343 return task_has_perm(current, p, PROCESS__GETSESSION);
3344}
3345
David Quigleyf9008e42006-06-30 01:55:46 -07003346static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3347{
David Howells275bb412008-11-14 10:39:19 +11003348 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003349}
3350
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351static int selinux_task_setgroups(struct group_info *group_info)
3352{
3353 /* See the comment for setuid above. */
3354 return 0;
3355}
3356
3357static int selinux_task_setnice(struct task_struct *p, int nice)
3358{
3359 int rc;
3360
3361 rc = secondary_ops->task_setnice(p, nice);
3362 if (rc)
3363 return rc;
3364
Eric Paris828dfe12008-04-17 13:17:49 -04003365 return task_has_perm(current, p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366}
3367
James Morris03e68062006-06-23 02:03:58 -07003368static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3369{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003370 int rc;
3371
3372 rc = secondary_ops->task_setioprio(p, ioprio);
3373 if (rc)
3374 return rc;
3375
James Morris03e68062006-06-23 02:03:58 -07003376 return task_has_perm(current, p, PROCESS__SETSCHED);
3377}
3378
David Quigleya1836a42006-06-30 01:55:49 -07003379static int selinux_task_getioprio(struct task_struct *p)
3380{
3381 return task_has_perm(current, p, PROCESS__GETSCHED);
3382}
3383
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3385{
3386 struct rlimit *old_rlim = current->signal->rlim + resource;
3387 int rc;
3388
3389 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3390 if (rc)
3391 return rc;
3392
3393 /* Control the ability to change the hard limit (whether
3394 lowering or raising it), so that the hard limit can
3395 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003396 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 if (old_rlim->rlim_max != new_rlim->rlim_max)
3398 return task_has_perm(current, current, PROCESS__SETRLIMIT);
3399
3400 return 0;
3401}
3402
3403static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3404{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003405 int rc;
3406
3407 rc = secondary_ops->task_setscheduler(p, policy, lp);
3408 if (rc)
3409 return rc;
3410
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 return task_has_perm(current, p, PROCESS__SETSCHED);
3412}
3413
3414static int selinux_task_getscheduler(struct task_struct *p)
3415{
3416 return task_has_perm(current, p, PROCESS__GETSCHED);
3417}
3418
David Quigley35601542006-06-23 02:04:01 -07003419static int selinux_task_movememory(struct task_struct *p)
3420{
3421 return task_has_perm(current, p, PROCESS__SETSCHED);
3422}
3423
David Quigleyf9008e42006-06-30 01:55:46 -07003424static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3425 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
3427 u32 perm;
3428 int rc;
3429
David Quigleyf9008e42006-06-30 01:55:46 -07003430 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 if (rc)
3432 return rc;
3433
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 if (!sig)
3435 perm = PROCESS__SIGNULL; /* null signal; existence test */
3436 else
3437 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003438 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003439 rc = avc_has_perm(secid, task_sid(p),
3440 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003441 else
3442 rc = task_has_perm(current, p, perm);
3443 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444}
3445
3446static int selinux_task_prctl(int option,
3447 unsigned long arg2,
3448 unsigned long arg3,
3449 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003450 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451{
3452 /* The current prctl operations do not appear to require
3453 any SELinux controls since they merely observe or modify
3454 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003455 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456}
3457
3458static int selinux_task_wait(struct task_struct *p)
3459{
Eric Paris8a535142007-10-22 16:10:31 -04003460 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461}
3462
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463static void selinux_task_to_inode(struct task_struct *p,
3464 struct inode *inode)
3465{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003467 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468
David Howells275bb412008-11-14 10:39:19 +11003469 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471}
3472
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003474static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3475 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476{
3477 int offset, ihlen, ret = -EINVAL;
3478 struct iphdr _iph, *ih;
3479
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003480 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3482 if (ih == NULL)
3483 goto out;
3484
3485 ihlen = ih->ihl * 4;
3486 if (ihlen < sizeof(_iph))
3487 goto out;
3488
3489 ad->u.net.v4info.saddr = ih->saddr;
3490 ad->u.net.v4info.daddr = ih->daddr;
3491 ret = 0;
3492
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003493 if (proto)
3494 *proto = ih->protocol;
3495
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003497 case IPPROTO_TCP: {
3498 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
Eric Paris828dfe12008-04-17 13:17:49 -04003500 if (ntohs(ih->frag_off) & IP_OFFSET)
3501 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
3503 offset += ihlen;
3504 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3505 if (th == NULL)
3506 break;
3507
3508 ad->u.net.sport = th->source;
3509 ad->u.net.dport = th->dest;
3510 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Eric Paris828dfe12008-04-17 13:17:49 -04003513 case IPPROTO_UDP: {
3514 struct udphdr _udph, *uh;
3515
3516 if (ntohs(ih->frag_off) & IP_OFFSET)
3517 break;
3518
3519 offset += ihlen;
3520 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3521 if (uh == NULL)
3522 break;
3523
3524 ad->u.net.sport = uh->source;
3525 ad->u.net.dport = uh->dest;
3526 break;
3527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
James Morris2ee92d42006-11-13 16:09:01 -08003529 case IPPROTO_DCCP: {
3530 struct dccp_hdr _dccph, *dh;
3531
3532 if (ntohs(ih->frag_off) & IP_OFFSET)
3533 break;
3534
3535 offset += ihlen;
3536 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3537 if (dh == NULL)
3538 break;
3539
3540 ad->u.net.sport = dh->dccph_sport;
3541 ad->u.net.dport = dh->dccph_dport;
3542 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003543 }
James Morris2ee92d42006-11-13 16:09:01 -08003544
Eric Paris828dfe12008-04-17 13:17:49 -04003545 default:
3546 break;
3547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548out:
3549 return ret;
3550}
3551
3552#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3553
3554/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003555static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3556 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557{
3558 u8 nexthdr;
3559 int ret = -EINVAL, offset;
3560 struct ipv6hdr _ipv6h, *ip6;
3561
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003562 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3564 if (ip6 == NULL)
3565 goto out;
3566
3567 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3568 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3569 ret = 0;
3570
3571 nexthdr = ip6->nexthdr;
3572 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003573 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 if (offset < 0)
3575 goto out;
3576
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003577 if (proto)
3578 *proto = nexthdr;
3579
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 switch (nexthdr) {
3581 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003582 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583
3584 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3585 if (th == NULL)
3586 break;
3587
3588 ad->u.net.sport = th->source;
3589 ad->u.net.dport = th->dest;
3590 break;
3591 }
3592
3593 case IPPROTO_UDP: {
3594 struct udphdr _udph, *uh;
3595
3596 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3597 if (uh == NULL)
3598 break;
3599
3600 ad->u.net.sport = uh->source;
3601 ad->u.net.dport = uh->dest;
3602 break;
3603 }
3604
James Morris2ee92d42006-11-13 16:09:01 -08003605 case IPPROTO_DCCP: {
3606 struct dccp_hdr _dccph, *dh;
3607
3608 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3609 if (dh == NULL)
3610 break;
3611
3612 ad->u.net.sport = dh->dccph_sport;
3613 ad->u.net.dport = dh->dccph_dport;
3614 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003615 }
James Morris2ee92d42006-11-13 16:09:01 -08003616
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 /* includes fragments */
3618 default:
3619 break;
3620 }
3621out:
3622 return ret;
3623}
3624
3625#endif /* IPV6 */
3626
3627static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003628 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629{
David Howellscf9481e2008-07-27 21:31:07 +10003630 char *addrp;
3631 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
3633 switch (ad->u.net.family) {
3634 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003635 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003636 if (ret)
3637 goto parse_error;
3638 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3639 &ad->u.net.v4info.daddr);
3640 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
3642#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3643 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003644 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003645 if (ret)
3646 goto parse_error;
3647 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3648 &ad->u.net.v6info.daddr);
3649 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650#endif /* IPV6 */
3651 default:
David Howellscf9481e2008-07-27 21:31:07 +10003652 addrp = NULL;
3653 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 }
3655
David Howellscf9481e2008-07-27 21:31:07 +10003656parse_error:
3657 printk(KERN_WARNING
3658 "SELinux: failure in selinux_parse_skb(),"
3659 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003661
3662okay:
3663 if (_addrp)
3664 *_addrp = addrp;
3665 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666}
3667
Paul Moore4f6a9932007-03-01 14:35:22 -05003668/**
Paul Moore220deb92008-01-29 08:38:23 -05003669 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003670 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003671 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003672 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003673 *
3674 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003675 * Check the various different forms of network peer labeling and determine
3676 * the peer label/SID for the packet; most of the magic actually occurs in
3677 * the security server function security_net_peersid_cmp(). The function
3678 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3679 * or -EACCES if @sid is invalid due to inconsistencies with the different
3680 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003681 *
3682 */
Paul Moore220deb92008-01-29 08:38:23 -05003683static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003684{
Paul Moore71f1cb02008-01-29 08:51:16 -05003685 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003686 u32 xfrm_sid;
3687 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003688 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003689
3690 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003691 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003692
Paul Moore71f1cb02008-01-29 08:51:16 -05003693 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3694 if (unlikely(err)) {
3695 printk(KERN_WARNING
3696 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3697 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003698 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003699 }
Paul Moore220deb92008-01-29 08:38:23 -05003700
3701 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003702}
3703
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704/* socket security operations */
3705static int socket_has_perm(struct task_struct *task, struct socket *sock,
3706 u32 perms)
3707{
3708 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003710 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 int err = 0;
3712
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 isec = SOCK_INODE(sock)->i_security;
3714
3715 if (isec->sid == SECINITSID_KERNEL)
3716 goto out;
David Howells275bb412008-11-14 10:39:19 +11003717 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
Eric Paris828dfe12008-04-17 13:17:49 -04003719 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003721 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
3723out:
3724 return err;
3725}
3726
3727static int selinux_socket_create(int family, int type,
3728 int protocol, int kern)
3729{
David Howells275bb412008-11-14 10:39:19 +11003730 const struct cred *cred = current_cred();
3731 const struct task_security_struct *tsec = cred->security;
3732 u32 sid, newsid;
3733 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735
3736 if (kern)
3737 goto out;
3738
David Howells275bb412008-11-14 10:39:19 +11003739 sid = tsec->sid;
3740 newsid = tsec->sockcreate_sid ?: sid;
3741
3742 secclass = socket_type_to_security_class(family, type, protocol);
3743 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
3745out:
3746 return err;
3747}
3748
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003749static int selinux_socket_post_create(struct socket *sock, int family,
3750 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751{
David Howells275bb412008-11-14 10:39:19 +11003752 const struct cred *cred = current_cred();
3753 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003755 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003756 u32 sid, newsid;
3757 int err = 0;
3758
3759 sid = tsec->sid;
3760 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
3762 isec = SOCK_INODE(sock)->i_security;
3763
David Howells275bb412008-11-14 10:39:19 +11003764 if (kern)
3765 isec->sid = SECINITSID_KERNEL;
3766 else if (newsid)
3767 isec->sid = newsid;
3768 else
3769 isec->sid = sid;
3770
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 isec->initialized = 1;
3773
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003774 if (sock->sk) {
3775 sksec = sock->sk->sk_security;
3776 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003777 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003778 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003779 }
3780
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003781 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782}
3783
3784/* Range of port numbers used to automatically bind.
3785 Need to determine whether we should perform a name_bind
3786 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
3788static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3789{
3790 u16 family;
3791 int err;
3792
3793 err = socket_has_perm(current, sock, SOCKET__BIND);
3794 if (err)
3795 goto out;
3796
3797 /*
3798 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003799 * Multiple address binding for SCTP is not supported yet: we just
3800 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 */
3802 family = sock->sk->sk_family;
3803 if (family == PF_INET || family == PF_INET6) {
3804 char *addrp;
3805 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 struct avc_audit_data ad;
3807 struct sockaddr_in *addr4 = NULL;
3808 struct sockaddr_in6 *addr6 = NULL;
3809 unsigned short snum;
3810 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003811 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 isec = SOCK_INODE(sock)->i_security;
3814
3815 if (family == PF_INET) {
3816 addr4 = (struct sockaddr_in *)address;
3817 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 addrp = (char *)&addr4->sin_addr.s_addr;
3819 } else {
3820 addr6 = (struct sockaddr_in6 *)address;
3821 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 addrp = (char *)&addr6->sin6_addr.s6_addr;
3823 }
3824
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003825 if (snum) {
3826 int low, high;
3827
3828 inet_get_local_port_range(&low, &high);
3829
3830 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003831 err = sel_netport_sid(sk->sk_protocol,
3832 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003833 if (err)
3834 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003835 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003836 ad.u.net.sport = htons(snum);
3837 ad.u.net.family = family;
3838 err = avc_has_perm(isec->sid, sid,
3839 isec->sclass,
3840 SOCKET__NAME_BIND, &ad);
3841 if (err)
3842 goto out;
3843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 }
Eric Paris828dfe12008-04-17 13:17:49 -04003845
3846 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003847 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 node_perm = TCP_SOCKET__NODE_BIND;
3849 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003850
James Morris13402582005-09-30 14:24:34 -04003851 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 node_perm = UDP_SOCKET__NODE_BIND;
3853 break;
James Morris2ee92d42006-11-13 16:09:01 -08003854
3855 case SECCLASS_DCCP_SOCKET:
3856 node_perm = DCCP_SOCKET__NODE_BIND;
3857 break;
3858
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 default:
3860 node_perm = RAWIP_SOCKET__NODE_BIND;
3861 break;
3862 }
Eric Paris828dfe12008-04-17 13:17:49 -04003863
Paul Moore224dfbd2008-01-29 08:38:13 -05003864 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 if (err)
3866 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003867
3868 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 ad.u.net.sport = htons(snum);
3870 ad.u.net.family = family;
3871
3872 if (family == PF_INET)
3873 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3874 else
3875 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3876
3877 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003878 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 if (err)
3880 goto out;
3881 }
3882out:
3883 return err;
3884}
3885
3886static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3887{
Paul Moore014ab192008-10-10 10:16:33 -04003888 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 struct inode_security_struct *isec;
3890 int err;
3891
3892 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3893 if (err)
3894 return err;
3895
3896 /*
James Morris2ee92d42006-11-13 16:09:01 -08003897 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 */
3899 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003900 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3901 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 struct avc_audit_data ad;
3903 struct sockaddr_in *addr4 = NULL;
3904 struct sockaddr_in6 *addr6 = NULL;
3905 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003906 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
3908 if (sk->sk_family == PF_INET) {
3909 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003910 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 return -EINVAL;
3912 snum = ntohs(addr4->sin_port);
3913 } else {
3914 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003915 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 return -EINVAL;
3917 snum = ntohs(addr6->sin6_port);
3918 }
3919
Paul Moore3e112172008-04-10 10:48:14 -04003920 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 if (err)
3922 goto out;
3923
James Morris2ee92d42006-11-13 16:09:01 -08003924 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3925 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3926
Eric Paris828dfe12008-04-17 13:17:49 -04003927 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 ad.u.net.dport = htons(snum);
3929 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003930 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 if (err)
3932 goto out;
3933 }
3934
Paul Moore014ab192008-10-10 10:16:33 -04003935 err = selinux_netlbl_socket_connect(sk, address);
3936
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937out:
3938 return err;
3939}
3940
3941static int selinux_socket_listen(struct socket *sock, int backlog)
3942{
3943 return socket_has_perm(current, sock, SOCKET__LISTEN);
3944}
3945
3946static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3947{
3948 int err;
3949 struct inode_security_struct *isec;
3950 struct inode_security_struct *newisec;
3951
3952 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3953 if (err)
3954 return err;
3955
3956 newisec = SOCK_INODE(newsock)->i_security;
3957
3958 isec = SOCK_INODE(sock)->i_security;
3959 newisec->sclass = isec->sclass;
3960 newisec->sid = isec->sid;
3961 newisec->initialized = 1;
3962
3963 return 0;
3964}
3965
3966static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003967 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003969 int rc;
3970
3971 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3972 if (rc)
3973 return rc;
3974
3975 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976}
3977
3978static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3979 int size, int flags)
3980{
3981 return socket_has_perm(current, sock, SOCKET__READ);
3982}
3983
3984static int selinux_socket_getsockname(struct socket *sock)
3985{
3986 return socket_has_perm(current, sock, SOCKET__GETATTR);
3987}
3988
3989static int selinux_socket_getpeername(struct socket *sock)
3990{
3991 return socket_has_perm(current, sock, SOCKET__GETATTR);
3992}
3993
Eric Paris828dfe12008-04-17 13:17:49 -04003994static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995{
Paul Mooref8687af2006-10-30 15:22:15 -08003996 int err;
3997
3998 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3999 if (err)
4000 return err;
4001
4002 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003}
4004
4005static int selinux_socket_getsockopt(struct socket *sock, int level,
4006 int optname)
4007{
4008 return socket_has_perm(current, sock, SOCKET__GETOPT);
4009}
4010
4011static int selinux_socket_shutdown(struct socket *sock, int how)
4012{
4013 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
4014}
4015
4016static int selinux_socket_unix_stream_connect(struct socket *sock,
4017 struct socket *other,
4018 struct sock *newsk)
4019{
4020 struct sk_security_struct *ssec;
4021 struct inode_security_struct *isec;
4022 struct inode_security_struct *other_isec;
4023 struct avc_audit_data ad;
4024 int err;
4025
4026 err = secondary_ops->unix_stream_connect(sock, other, newsk);
4027 if (err)
4028 return err;
4029
4030 isec = SOCK_INODE(sock)->i_security;
4031 other_isec = SOCK_INODE(other)->i_security;
4032
Eric Paris828dfe12008-04-17 13:17:49 -04004033 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 ad.u.net.sk = other->sk;
4035
4036 err = avc_has_perm(isec->sid, other_isec->sid,
4037 isec->sclass,
4038 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4039 if (err)
4040 return err;
4041
4042 /* connecting socket */
4043 ssec = sock->sk->sk_security;
4044 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004045
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 /* server child socket */
4047 ssec = newsk->sk_security;
4048 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004049 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4050
4051 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052}
4053
4054static int selinux_socket_unix_may_send(struct socket *sock,
4055 struct socket *other)
4056{
4057 struct inode_security_struct *isec;
4058 struct inode_security_struct *other_isec;
4059 struct avc_audit_data ad;
4060 int err;
4061
4062 isec = SOCK_INODE(sock)->i_security;
4063 other_isec = SOCK_INODE(other)->i_security;
4064
Eric Paris828dfe12008-04-17 13:17:49 -04004065 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 ad.u.net.sk = other->sk;
4067
4068 err = avc_has_perm(isec->sid, other_isec->sid,
4069 isec->sclass, SOCKET__SENDTO, &ad);
4070 if (err)
4071 return err;
4072
4073 return 0;
4074}
4075
Paul Mooreeffad8d2008-01-29 08:49:27 -05004076static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4077 u32 peer_sid,
4078 struct avc_audit_data *ad)
4079{
4080 int err;
4081 u32 if_sid;
4082 u32 node_sid;
4083
4084 err = sel_netif_sid(ifindex, &if_sid);
4085 if (err)
4086 return err;
4087 err = avc_has_perm(peer_sid, if_sid,
4088 SECCLASS_NETIF, NETIF__INGRESS, ad);
4089 if (err)
4090 return err;
4091
4092 err = sel_netnode_sid(addrp, family, &node_sid);
4093 if (err)
4094 return err;
4095 return avc_has_perm(peer_sid, node_sid,
4096 SECCLASS_NODE, NODE__RECVFROM, ad);
4097}
4098
Paul Moore220deb92008-01-29 08:38:23 -05004099static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4100 struct sk_buff *skb,
4101 struct avc_audit_data *ad,
4102 u16 family,
4103 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104{
Paul Moore220deb92008-01-29 08:38:23 -05004105 int err;
4106 struct sk_security_struct *sksec = sk->sk_security;
4107 u16 sk_class;
4108 u32 netif_perm, node_perm, recv_perm;
4109 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004110
Paul Moore220deb92008-01-29 08:38:23 -05004111 sk_sid = sksec->sid;
4112 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
Paul Moore220deb92008-01-29 08:38:23 -05004114 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 case SECCLASS_UDP_SOCKET:
4116 netif_perm = NETIF__UDP_RECV;
4117 node_perm = NODE__UDP_RECV;
4118 recv_perm = UDP_SOCKET__RECV_MSG;
4119 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 case SECCLASS_TCP_SOCKET:
4121 netif_perm = NETIF__TCP_RECV;
4122 node_perm = NODE__TCP_RECV;
4123 recv_perm = TCP_SOCKET__RECV_MSG;
4124 break;
James Morris2ee92d42006-11-13 16:09:01 -08004125 case SECCLASS_DCCP_SOCKET:
4126 netif_perm = NETIF__DCCP_RECV;
4127 node_perm = NODE__DCCP_RECV;
4128 recv_perm = DCCP_SOCKET__RECV_MSG;
4129 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 default:
4131 netif_perm = NETIF__RAWIP_RECV;
4132 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004133 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 break;
4135 }
4136
Paul Moore220deb92008-01-29 08:38:23 -05004137 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004139 return err;
4140 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4141 if (err)
4142 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004143
Paul Moore224dfbd2008-01-29 08:38:13 -05004144 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004146 return err;
4147 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004149 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Paul Moore220deb92008-01-29 08:38:23 -05004151 if (!recv_perm)
4152 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004153 err = sel_netport_sid(sk->sk_protocol,
4154 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004155 if (unlikely(err)) {
4156 printk(KERN_WARNING
4157 "SELinux: failure in"
4158 " selinux_sock_rcv_skb_iptables_compat(),"
4159 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004160 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004161 }
Paul Moore220deb92008-01-29 08:38:23 -05004162 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4163}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164
Paul Moore220deb92008-01-29 08:38:23 -05004165static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004166 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004167{
4168 int err;
4169 struct sk_security_struct *sksec = sk->sk_security;
4170 u32 peer_sid;
4171 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004172 struct avc_audit_data ad;
4173 char *addrp;
4174
4175 AVC_AUDIT_DATA_INIT(&ad, NET);
4176 ad.u.net.netif = skb->iif;
4177 ad.u.net.family = family;
4178 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4179 if (err)
4180 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004181
4182 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004183 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004184 family, addrp);
4185 else
4186 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004187 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004188 if (err)
4189 return err;
4190
4191 if (selinux_policycap_netpeer) {
4192 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004194 return err;
4195 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004196 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004197 if (err)
4198 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004199 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004200 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004201 if (err)
4202 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004203 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004205
James Morris4e5ab4c2006-06-09 00:33:33 -07004206 return err;
4207}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004208
James Morris4e5ab4c2006-06-09 00:33:33 -07004209static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4210{
Paul Moore220deb92008-01-29 08:38:23 -05004211 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004212 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004213 u16 family = sk->sk_family;
4214 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004215 struct avc_audit_data ad;
4216 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004217 u8 secmark_active;
4218 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004219
James Morris4e5ab4c2006-06-09 00:33:33 -07004220 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004221 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004222
4223 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004224 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004225 family = PF_INET;
4226
Paul Moored8395c82008-10-10 10:16:30 -04004227 /* If any sort of compatibility mode is enabled then handoff processing
4228 * to the selinux_sock_rcv_skb_compat() function to deal with the
4229 * special handling. We do this in an attempt to keep this function
4230 * as fast and as clean as possible. */
4231 if (selinux_compat_net || !selinux_policycap_netpeer)
4232 return selinux_sock_rcv_skb_compat(sk, skb, family);
4233
4234 secmark_active = selinux_secmark_enabled();
4235 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4236 if (!secmark_active && !peerlbl_active)
4237 return 0;
4238
James Morris4e5ab4c2006-06-09 00:33:33 -07004239 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004240 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004241 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004242 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004243 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004244 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004245
Paul Moored8395c82008-10-10 10:16:30 -04004246 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004247 u32 peer_sid;
4248
4249 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4250 if (err)
4251 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004252 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4253 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004254 if (err) {
4255 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004256 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004257 }
Paul Moored621d352008-01-29 08:43:36 -05004258 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4259 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004260 if (err)
4261 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004262 }
4263
Paul Moored8395c82008-10-10 10:16:30 -04004264 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004265 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4266 PACKET__RECV, &ad);
4267 if (err)
4268 return err;
4269 }
4270
Paul Moored621d352008-01-29 08:43:36 -05004271 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272}
4273
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004274static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4275 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276{
4277 int err = 0;
4278 char *scontext;
4279 u32 scontext_len;
4280 struct sk_security_struct *ssec;
4281 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004282 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
4284 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004285
Paul Moore3de4bab2006-11-17 17:38:54 -05004286 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4287 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004288 ssec = sock->sk->sk_security;
4289 peer_sid = ssec->peer_sid;
4290 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004291 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 err = -ENOPROTOOPT;
4293 goto out;
4294 }
4295
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004296 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4297
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 if (err)
4299 goto out;
4300
4301 if (scontext_len > len) {
4302 err = -ERANGE;
4303 goto out_len;
4304 }
4305
4306 if (copy_to_user(optval, scontext, scontext_len))
4307 err = -EFAULT;
4308
4309out_len:
4310 if (put_user(scontext_len, optlen))
4311 err = -EFAULT;
4312
4313 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004314out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 return err;
4316}
4317
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004318static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004319{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004320 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004321 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004322
Paul Mooreaa862902008-10-10 10:16:29 -04004323 if (skb && skb->protocol == htons(ETH_P_IP))
4324 family = PF_INET;
4325 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4326 family = PF_INET6;
4327 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004328 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004329 else
4330 goto out;
4331
4332 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004333 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004334 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004335 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004336
Paul Moore75e22912008-01-29 08:38:04 -05004337out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004338 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004339 if (peer_secid == SECSID_NULL)
4340 return -EINVAL;
4341 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004342}
4343
Al Viro7d877f32005-10-21 03:20:43 -04004344static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345{
4346 return sk_alloc_security(sk, family, priority);
4347}
4348
4349static void selinux_sk_free_security(struct sock *sk)
4350{
4351 sk_free_security(sk);
4352}
4353
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004354static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4355{
4356 struct sk_security_struct *ssec = sk->sk_security;
4357 struct sk_security_struct *newssec = newsk->sk_security;
4358
4359 newssec->sid = ssec->sid;
4360 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004361 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004362
Paul Mooref74af6e2008-02-25 11:40:33 -05004363 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004364}
4365
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004366static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004367{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004368 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004369 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004370 else {
4371 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004372
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004373 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004374 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004375}
4376
Eric Paris828dfe12008-04-17 13:17:49 -04004377static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004378{
4379 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4380 struct sk_security_struct *sksec = sk->sk_security;
4381
David Woodhouse2148ccc2006-09-29 15:50:25 -07004382 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4383 sk->sk_family == PF_UNIX)
4384 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004385 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004386}
4387
Adrian Bunk9a673e52006-08-15 00:03:53 -07004388static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4389 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004390{
4391 struct sk_security_struct *sksec = sk->sk_security;
4392 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004393 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004394 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004395 u32 peersid;
4396
Paul Mooreaa862902008-10-10 10:16:29 -04004397 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4398 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4399 family = PF_INET;
4400
4401 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004402 if (err)
4403 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004404 if (peersid == SECSID_NULL) {
4405 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004406 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004407 return 0;
4408 }
4409
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004410 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4411 if (err)
4412 return err;
4413
4414 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004415 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004416 return 0;
4417}
4418
Adrian Bunk9a673e52006-08-15 00:03:53 -07004419static void selinux_inet_csk_clone(struct sock *newsk,
4420 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004421{
4422 struct sk_security_struct *newsksec = newsk->sk_security;
4423
4424 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004425 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004426 /* NOTE: Ideally, we should also get the isec->sid for the
4427 new socket in sync, but we don't have the isec available yet.
4428 So we will wait until sock_graft to do it, by which
4429 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004430
Paul Moore9f2ad662006-11-17 17:38:53 -05004431 /* We don't need to take any sort of lock here as we are the only
4432 * thread with access to newsksec */
4433 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004434}
4435
Paul Moore014ab192008-10-10 10:16:33 -04004436static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004437{
Paul Mooreaa862902008-10-10 10:16:29 -04004438 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004439 struct sk_security_struct *sksec = sk->sk_security;
4440
Paul Mooreaa862902008-10-10 10:16:29 -04004441 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4442 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4443 family = PF_INET;
4444
4445 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004446
4447 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004448}
4449
Adrian Bunk9a673e52006-08-15 00:03:53 -07004450static void selinux_req_classify_flow(const struct request_sock *req,
4451 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004452{
4453 fl->secid = req->secid;
4454}
4455
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4457{
4458 int err = 0;
4459 u32 perm;
4460 struct nlmsghdr *nlh;
4461 struct socket *sock = sk->sk_socket;
4462 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004463
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 if (skb->len < NLMSG_SPACE(0)) {
4465 err = -EINVAL;
4466 goto out;
4467 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004468 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004469
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4471 if (err) {
4472 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004473 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 "SELinux: unrecognized netlink message"
4475 " type=%hu for sclass=%hu\n",
4476 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004477 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 err = 0;
4479 }
4480
4481 /* Ignore */
4482 if (err == -ENOENT)
4483 err = 0;
4484 goto out;
4485 }
4486
4487 err = socket_has_perm(current, sock, perm);
4488out:
4489 return err;
4490}
4491
4492#ifdef CONFIG_NETFILTER
4493
Paul Mooreeffad8d2008-01-29 08:49:27 -05004494static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4495 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496{
Paul Mooredfaebe92008-10-10 10:16:31 -04004497 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004498 char *addrp;
4499 u32 peer_sid;
4500 struct avc_audit_data ad;
4501 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004502 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004503 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004504
Paul Mooreeffad8d2008-01-29 08:49:27 -05004505 if (!selinux_policycap_netpeer)
4506 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004507
Paul Mooreeffad8d2008-01-29 08:49:27 -05004508 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004509 netlbl_active = netlbl_enabled();
4510 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004511 if (!secmark_active && !peerlbl_active)
4512 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004513
Paul Moored8395c82008-10-10 10:16:30 -04004514 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4515 return NF_DROP;
4516
Paul Mooreeffad8d2008-01-29 08:49:27 -05004517 AVC_AUDIT_DATA_INIT(&ad, NET);
4518 ad.u.net.netif = ifindex;
4519 ad.u.net.family = family;
4520 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4521 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
Paul Mooredfaebe92008-10-10 10:16:31 -04004523 if (peerlbl_active) {
4524 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4525 peer_sid, &ad);
4526 if (err) {
4527 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004528 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004529 }
4530 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004531
4532 if (secmark_active)
4533 if (avc_has_perm(peer_sid, skb->secmark,
4534 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4535 return NF_DROP;
4536
Paul Moore948bf852008-10-10 10:16:32 -04004537 if (netlbl_active)
4538 /* we do this in the FORWARD path and not the POST_ROUTING
4539 * path because we want to make sure we apply the necessary
4540 * labeling before IPsec is applied so we can leverage AH
4541 * protection */
4542 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4543 return NF_DROP;
4544
Paul Mooreeffad8d2008-01-29 08:49:27 -05004545 return NF_ACCEPT;
4546}
4547
4548static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4549 struct sk_buff *skb,
4550 const struct net_device *in,
4551 const struct net_device *out,
4552 int (*okfn)(struct sk_buff *))
4553{
4554 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4555}
4556
4557#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4558static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4559 struct sk_buff *skb,
4560 const struct net_device *in,
4561 const struct net_device *out,
4562 int (*okfn)(struct sk_buff *))
4563{
4564 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4565}
4566#endif /* IPV6 */
4567
Paul Moore948bf852008-10-10 10:16:32 -04004568static unsigned int selinux_ip_output(struct sk_buff *skb,
4569 u16 family)
4570{
4571 u32 sid;
4572
4573 if (!netlbl_enabled())
4574 return NF_ACCEPT;
4575
4576 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4577 * because we want to make sure we apply the necessary labeling
4578 * before IPsec is applied so we can leverage AH protection */
4579 if (skb->sk) {
4580 struct sk_security_struct *sksec = skb->sk->sk_security;
4581 sid = sksec->sid;
4582 } else
4583 sid = SECINITSID_KERNEL;
4584 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4585 return NF_DROP;
4586
4587 return NF_ACCEPT;
4588}
4589
4590static unsigned int selinux_ipv4_output(unsigned int hooknum,
4591 struct sk_buff *skb,
4592 const struct net_device *in,
4593 const struct net_device *out,
4594 int (*okfn)(struct sk_buff *))
4595{
4596 return selinux_ip_output(skb, PF_INET);
4597}
4598
Paul Mooreeffad8d2008-01-29 08:49:27 -05004599static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4600 int ifindex,
4601 struct avc_audit_data *ad,
4602 u16 family, char *addrp)
4603{
4604 int err;
4605 struct sk_security_struct *sksec = sk->sk_security;
4606 u16 sk_class;
4607 u32 netif_perm, node_perm, send_perm;
4608 u32 port_sid, node_sid, if_sid, sk_sid;
4609
4610 sk_sid = sksec->sid;
4611 sk_class = sksec->sclass;
4612
4613 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 case SECCLASS_UDP_SOCKET:
4615 netif_perm = NETIF__UDP_SEND;
4616 node_perm = NODE__UDP_SEND;
4617 send_perm = UDP_SOCKET__SEND_MSG;
4618 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 case SECCLASS_TCP_SOCKET:
4620 netif_perm = NETIF__TCP_SEND;
4621 node_perm = NODE__TCP_SEND;
4622 send_perm = TCP_SOCKET__SEND_MSG;
4623 break;
James Morris2ee92d42006-11-13 16:09:01 -08004624 case SECCLASS_DCCP_SOCKET:
4625 netif_perm = NETIF__DCCP_SEND;
4626 node_perm = NODE__DCCP_SEND;
4627 send_perm = DCCP_SOCKET__SEND_MSG;
4628 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 default:
4630 netif_perm = NETIF__RAWIP_SEND;
4631 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004632 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 break;
4634 }
4635
Paul Mooreeffad8d2008-01-29 08:49:27 -05004636 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004637 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004638 return err;
4639 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4640 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004641
Paul Moore224dfbd2008-01-29 08:38:13 -05004642 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004643 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004644 return err;
4645 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004646 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004647 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648
Paul Mooreeffad8d2008-01-29 08:49:27 -05004649 if (send_perm != 0)
4650 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Paul Moore3e112172008-04-10 10:48:14 -04004652 err = sel_netport_sid(sk->sk_protocol,
4653 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004654 if (unlikely(err)) {
4655 printk(KERN_WARNING
4656 "SELinux: failure in"
4657 " selinux_ip_postroute_iptables_compat(),"
4658 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004659 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004660 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004661 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004662}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663
Paul Mooreeffad8d2008-01-29 08:49:27 -05004664static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4665 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004666 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004667{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004668 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004669 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004670 struct avc_audit_data ad;
4671 char *addrp;
4672 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004673
Paul Mooreeffad8d2008-01-29 08:49:27 -05004674 if (sk == NULL)
4675 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004676 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004677
Paul Moored8395c82008-10-10 10:16:30 -04004678 AVC_AUDIT_DATA_INIT(&ad, NET);
4679 ad.u.net.netif = ifindex;
4680 ad.u.net.family = family;
4681 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4682 return NF_DROP;
4683
Paul Mooreeffad8d2008-01-29 08:49:27 -05004684 if (selinux_compat_net) {
4685 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004686 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004687 return NF_DROP;
4688 } else {
4689 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004690 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004691 return NF_DROP;
4692 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004693
Paul Mooreeffad8d2008-01-29 08:49:27 -05004694 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004695 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004696 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004697
Paul Mooreeffad8d2008-01-29 08:49:27 -05004698 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699}
4700
Paul Mooreeffad8d2008-01-29 08:49:27 -05004701static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4702 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004704 u32 secmark_perm;
4705 u32 peer_sid;
4706 struct sock *sk;
4707 struct avc_audit_data ad;
4708 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004709 u8 secmark_active;
4710 u8 peerlbl_active;
4711
Paul Mooreeffad8d2008-01-29 08:49:27 -05004712 /* If any sort of compatibility mode is enabled then handoff processing
4713 * to the selinux_ip_postroute_compat() function to deal with the
4714 * special handling. We do this in an attempt to keep this function
4715 * as fast and as clean as possible. */
4716 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004717 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004718
4719 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4720 * packet transformation so allow the packet to pass without any checks
4721 * since we'll have another chance to perform access control checks
4722 * when the packet is on it's final way out.
4723 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4724 * is NULL, in this case go ahead and apply access control. */
4725 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4726 return NF_ACCEPT;
4727
4728 secmark_active = selinux_secmark_enabled();
4729 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4730 if (!secmark_active && !peerlbl_active)
4731 return NF_ACCEPT;
4732
Paul Moored8395c82008-10-10 10:16:30 -04004733 /* if the packet is being forwarded then get the peer label from the
4734 * packet itself; otherwise check to see if it is from a local
4735 * application or the kernel, if from an application get the peer label
4736 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004737 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004738 if (sk == NULL) {
4739 switch (family) {
4740 case PF_INET:
4741 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4742 secmark_perm = PACKET__FORWARD_OUT;
4743 else
4744 secmark_perm = PACKET__SEND;
4745 break;
4746 case PF_INET6:
4747 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4748 secmark_perm = PACKET__FORWARD_OUT;
4749 else
4750 secmark_perm = PACKET__SEND;
4751 break;
4752 default:
4753 return NF_DROP;
4754 }
4755 if (secmark_perm == PACKET__FORWARD_OUT) {
4756 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4757 return NF_DROP;
4758 } else
4759 peer_sid = SECINITSID_KERNEL;
4760 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004761 struct sk_security_struct *sksec = sk->sk_security;
4762 peer_sid = sksec->sid;
4763 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004764 }
4765
Paul Moored8395c82008-10-10 10:16:30 -04004766 AVC_AUDIT_DATA_INIT(&ad, NET);
4767 ad.u.net.netif = ifindex;
4768 ad.u.net.family = family;
4769 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4770 return NF_DROP;
4771
Paul Mooreeffad8d2008-01-29 08:49:27 -05004772 if (secmark_active)
4773 if (avc_has_perm(peer_sid, skb->secmark,
4774 SECCLASS_PACKET, secmark_perm, &ad))
4775 return NF_DROP;
4776
4777 if (peerlbl_active) {
4778 u32 if_sid;
4779 u32 node_sid;
4780
4781 if (sel_netif_sid(ifindex, &if_sid))
4782 return NF_DROP;
4783 if (avc_has_perm(peer_sid, if_sid,
4784 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4785 return NF_DROP;
4786
4787 if (sel_netnode_sid(addrp, family, &node_sid))
4788 return NF_DROP;
4789 if (avc_has_perm(peer_sid, node_sid,
4790 SECCLASS_NODE, NODE__SENDTO, &ad))
4791 return NF_DROP;
4792 }
4793
4794 return NF_ACCEPT;
4795}
4796
4797static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4798 struct sk_buff *skb,
4799 const struct net_device *in,
4800 const struct net_device *out,
4801 int (*okfn)(struct sk_buff *))
4802{
4803 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804}
4805
4806#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004807static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4808 struct sk_buff *skb,
4809 const struct net_device *in,
4810 const struct net_device *out,
4811 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004813 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815#endif /* IPV6 */
4816
4817#endif /* CONFIG_NETFILTER */
4818
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4820{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 int err;
4822
4823 err = secondary_ops->netlink_send(sk, skb);
4824 if (err)
4825 return err;
4826
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4828 err = selinux_nlmsg_perm(sk, skb);
4829
4830 return err;
4831}
4832
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004833static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004835 int err;
4836 struct avc_audit_data ad;
4837
4838 err = secondary_ops->netlink_recv(skb, capability);
4839 if (err)
4840 return err;
4841
4842 AVC_AUDIT_DATA_INIT(&ad, CAP);
4843 ad.u.cap = capability;
4844
4845 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004846 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847}
4848
4849static int ipc_alloc_security(struct task_struct *task,
4850 struct kern_ipc_perm *perm,
4851 u16 sclass)
4852{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004854 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855
James Morris89d155e2005-10-30 14:59:21 -08004856 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 if (!isec)
4858 return -ENOMEM;
4859
David Howells275bb412008-11-14 10:39:19 +11004860 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004862 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 perm->security = isec;
4864
4865 return 0;
4866}
4867
4868static void ipc_free_security(struct kern_ipc_perm *perm)
4869{
4870 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 perm->security = NULL;
4872 kfree(isec);
4873}
4874
4875static int msg_msg_alloc_security(struct msg_msg *msg)
4876{
4877 struct msg_security_struct *msec;
4878
James Morris89d155e2005-10-30 14:59:21 -08004879 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 if (!msec)
4881 return -ENOMEM;
4882
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 msec->sid = SECINITSID_UNLABELED;
4884 msg->security = msec;
4885
4886 return 0;
4887}
4888
4889static void msg_msg_free_security(struct msg_msg *msg)
4890{
4891 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
4893 msg->security = NULL;
4894 kfree(msec);
4895}
4896
4897static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004898 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 struct ipc_security_struct *isec;
4901 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004902 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 isec = ipc_perms->security;
4905
4906 AVC_AUDIT_DATA_INIT(&ad, IPC);
4907 ad.u.ipc_id = ipc_perms->key;
4908
David Howells275bb412008-11-14 10:39:19 +11004909 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910}
4911
4912static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4913{
4914 return msg_msg_alloc_security(msg);
4915}
4916
4917static void selinux_msg_msg_free_security(struct msg_msg *msg)
4918{
4919 msg_msg_free_security(msg);
4920}
4921
4922/* message queue security operations */
4923static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4924{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 struct ipc_security_struct *isec;
4926 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004927 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 int rc;
4929
4930 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4931 if (rc)
4932 return rc;
4933
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 isec = msq->q_perm.security;
4935
4936 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004937 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938
David Howells275bb412008-11-14 10:39:19 +11004939 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 MSGQ__CREATE, &ad);
4941 if (rc) {
4942 ipc_free_security(&msq->q_perm);
4943 return rc;
4944 }
4945 return 0;
4946}
4947
4948static void selinux_msg_queue_free_security(struct msg_queue *msq)
4949{
4950 ipc_free_security(&msq->q_perm);
4951}
4952
4953static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4954{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 struct ipc_security_struct *isec;
4956 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004957 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 isec = msq->q_perm.security;
4960
4961 AVC_AUDIT_DATA_INIT(&ad, IPC);
4962 ad.u.ipc_id = msq->q_perm.key;
4963
David Howells275bb412008-11-14 10:39:19 +11004964 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 MSGQ__ASSOCIATE, &ad);
4966}
4967
4968static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4969{
4970 int err;
4971 int perms;
4972
Eric Paris828dfe12008-04-17 13:17:49 -04004973 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 case IPC_INFO:
4975 case MSG_INFO:
4976 /* No specific object, just general system-wide information. */
4977 return task_has_system(current, SYSTEM__IPC_INFO);
4978 case IPC_STAT:
4979 case MSG_STAT:
4980 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4981 break;
4982 case IPC_SET:
4983 perms = MSGQ__SETATTR;
4984 break;
4985 case IPC_RMID:
4986 perms = MSGQ__DESTROY;
4987 break;
4988 default:
4989 return 0;
4990 }
4991
Stephen Smalley6af963f2005-05-01 08:58:39 -07004992 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 return err;
4994}
4995
4996static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4997{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 struct ipc_security_struct *isec;
4999 struct msg_security_struct *msec;
5000 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005001 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 int rc;
5003
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 isec = msq->q_perm.security;
5005 msec = msg->security;
5006
5007 /*
5008 * First time through, need to assign label to the message
5009 */
5010 if (msec->sid == SECINITSID_UNLABELED) {
5011 /*
5012 * Compute new sid based on current process and
5013 * message queue this message will be stored in
5014 */
David Howells275bb412008-11-14 10:39:19 +11005015 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 &msec->sid);
5017 if (rc)
5018 return rc;
5019 }
5020
5021 AVC_AUDIT_DATA_INIT(&ad, IPC);
5022 ad.u.ipc_id = msq->q_perm.key;
5023
5024 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005025 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 MSGQ__WRITE, &ad);
5027 if (!rc)
5028 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005029 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5030 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 if (!rc)
5032 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005033 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5034 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
5036 return rc;
5037}
5038
5039static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5040 struct task_struct *target,
5041 long type, int mode)
5042{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 struct ipc_security_struct *isec;
5044 struct msg_security_struct *msec;
5045 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005046 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 int rc;
5048
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 isec = msq->q_perm.security;
5050 msec = msg->security;
5051
5052 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005053 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054
David Howells275bb412008-11-14 10:39:19 +11005055 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 SECCLASS_MSGQ, MSGQ__READ, &ad);
5057 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005058 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 SECCLASS_MSG, MSG__RECEIVE, &ad);
5060 return rc;
5061}
5062
5063/* Shared Memory security operations */
5064static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5065{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 struct ipc_security_struct *isec;
5067 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005068 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 int rc;
5070
5071 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5072 if (rc)
5073 return rc;
5074
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 isec = shp->shm_perm.security;
5076
5077 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005078 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079
David Howells275bb412008-11-14 10:39:19 +11005080 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 SHM__CREATE, &ad);
5082 if (rc) {
5083 ipc_free_security(&shp->shm_perm);
5084 return rc;
5085 }
5086 return 0;
5087}
5088
5089static void selinux_shm_free_security(struct shmid_kernel *shp)
5090{
5091 ipc_free_security(&shp->shm_perm);
5092}
5093
5094static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5095{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 struct ipc_security_struct *isec;
5097 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005098 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 isec = shp->shm_perm.security;
5101
5102 AVC_AUDIT_DATA_INIT(&ad, IPC);
5103 ad.u.ipc_id = shp->shm_perm.key;
5104
David Howells275bb412008-11-14 10:39:19 +11005105 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 SHM__ASSOCIATE, &ad);
5107}
5108
5109/* Note, at this point, shp is locked down */
5110static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5111{
5112 int perms;
5113 int err;
5114
Eric Paris828dfe12008-04-17 13:17:49 -04005115 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 case IPC_INFO:
5117 case SHM_INFO:
5118 /* No specific object, just general system-wide information. */
5119 return task_has_system(current, SYSTEM__IPC_INFO);
5120 case IPC_STAT:
5121 case SHM_STAT:
5122 perms = SHM__GETATTR | SHM__ASSOCIATE;
5123 break;
5124 case IPC_SET:
5125 perms = SHM__SETATTR;
5126 break;
5127 case SHM_LOCK:
5128 case SHM_UNLOCK:
5129 perms = SHM__LOCK;
5130 break;
5131 case IPC_RMID:
5132 perms = SHM__DESTROY;
5133 break;
5134 default:
5135 return 0;
5136 }
5137
Stephen Smalley6af963f2005-05-01 08:58:39 -07005138 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 return err;
5140}
5141
5142static int selinux_shm_shmat(struct shmid_kernel *shp,
5143 char __user *shmaddr, int shmflg)
5144{
5145 u32 perms;
5146 int rc;
5147
5148 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5149 if (rc)
5150 return rc;
5151
5152 if (shmflg & SHM_RDONLY)
5153 perms = SHM__READ;
5154 else
5155 perms = SHM__READ | SHM__WRITE;
5156
Stephen Smalley6af963f2005-05-01 08:58:39 -07005157 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158}
5159
5160/* Semaphore security operations */
5161static int selinux_sem_alloc_security(struct sem_array *sma)
5162{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 struct ipc_security_struct *isec;
5164 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005165 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 int rc;
5167
5168 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5169 if (rc)
5170 return rc;
5171
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 isec = sma->sem_perm.security;
5173
5174 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005175 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176
David Howells275bb412008-11-14 10:39:19 +11005177 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 SEM__CREATE, &ad);
5179 if (rc) {
5180 ipc_free_security(&sma->sem_perm);
5181 return rc;
5182 }
5183 return 0;
5184}
5185
5186static void selinux_sem_free_security(struct sem_array *sma)
5187{
5188 ipc_free_security(&sma->sem_perm);
5189}
5190
5191static int selinux_sem_associate(struct sem_array *sma, int semflg)
5192{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 struct ipc_security_struct *isec;
5194 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005195 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 isec = sma->sem_perm.security;
5198
5199 AVC_AUDIT_DATA_INIT(&ad, IPC);
5200 ad.u.ipc_id = sma->sem_perm.key;
5201
David Howells275bb412008-11-14 10:39:19 +11005202 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 SEM__ASSOCIATE, &ad);
5204}
5205
5206/* Note, at this point, sma is locked down */
5207static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5208{
5209 int err;
5210 u32 perms;
5211
Eric Paris828dfe12008-04-17 13:17:49 -04005212 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 case IPC_INFO:
5214 case SEM_INFO:
5215 /* No specific object, just general system-wide information. */
5216 return task_has_system(current, SYSTEM__IPC_INFO);
5217 case GETPID:
5218 case GETNCNT:
5219 case GETZCNT:
5220 perms = SEM__GETATTR;
5221 break;
5222 case GETVAL:
5223 case GETALL:
5224 perms = SEM__READ;
5225 break;
5226 case SETVAL:
5227 case SETALL:
5228 perms = SEM__WRITE;
5229 break;
5230 case IPC_RMID:
5231 perms = SEM__DESTROY;
5232 break;
5233 case IPC_SET:
5234 perms = SEM__SETATTR;
5235 break;
5236 case IPC_STAT:
5237 case SEM_STAT:
5238 perms = SEM__GETATTR | SEM__ASSOCIATE;
5239 break;
5240 default:
5241 return 0;
5242 }
5243
Stephen Smalley6af963f2005-05-01 08:58:39 -07005244 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 return err;
5246}
5247
5248static int selinux_sem_semop(struct sem_array *sma,
5249 struct sembuf *sops, unsigned nsops, int alter)
5250{
5251 u32 perms;
5252
5253 if (alter)
5254 perms = SEM__READ | SEM__WRITE;
5255 else
5256 perms = SEM__READ;
5257
Stephen Smalley6af963f2005-05-01 08:58:39 -07005258 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259}
5260
5261static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5262{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 u32 av = 0;
5264
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 av = 0;
5266 if (flag & S_IRUGO)
5267 av |= IPC__UNIX_READ;
5268 if (flag & S_IWUGO)
5269 av |= IPC__UNIX_WRITE;
5270
5271 if (av == 0)
5272 return 0;
5273
Stephen Smalley6af963f2005-05-01 08:58:39 -07005274 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275}
5276
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005277static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5278{
5279 struct ipc_security_struct *isec = ipcp->security;
5280 *secid = isec->sid;
5281}
5282
Eric Paris828dfe12008-04-17 13:17:49 -04005283static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284{
5285 if (inode)
5286 inode_doinit_with_dentry(inode, dentry);
5287}
5288
5289static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005290 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291{
David Howells275bb412008-11-14 10:39:19 +11005292 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005293 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005295 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296
5297 if (current != p) {
5298 error = task_has_perm(current, p, PROCESS__GETATTR);
5299 if (error)
5300 return error;
5301 }
5302
David Howells275bb412008-11-14 10:39:19 +11005303 rcu_read_lock();
5304 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
5306 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005307 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005309 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005311 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005313 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005314 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005315 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005316 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005317 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 else
David Howells275bb412008-11-14 10:39:19 +11005319 goto invalid;
5320 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321
5322 if (!sid)
5323 return 0;
5324
Al Viro04ff9702007-03-12 16:17:58 +00005325 error = security_sid_to_context(sid, value, &len);
5326 if (error)
5327 return error;
5328 return len;
David Howells275bb412008-11-14 10:39:19 +11005329
5330invalid:
5331 rcu_read_unlock();
5332 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333}
5334
5335static int selinux_setprocattr(struct task_struct *p,
5336 char *name, void *value, size_t size)
5337{
5338 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005339 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005340 struct cred *new;
5341 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 int error;
5343 char *str = value;
5344
5345 if (current != p) {
5346 /* SELinux only allows a process to change its own
5347 security attributes. */
5348 return -EACCES;
5349 }
5350
5351 /*
5352 * Basic control over ability to set these attributes at all.
5353 * current == p, but we'll pass them separately in case the
5354 * above restriction is ever removed.
5355 */
5356 if (!strcmp(name, "exec"))
5357 error = task_has_perm(current, p, PROCESS__SETEXEC);
5358 else if (!strcmp(name, "fscreate"))
5359 error = task_has_perm(current, p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005360 else if (!strcmp(name, "keycreate"))
5361 error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005362 else if (!strcmp(name, "sockcreate"))
5363 error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 else if (!strcmp(name, "current"))
5365 error = task_has_perm(current, p, PROCESS__SETCURRENT);
5366 else
5367 error = -EINVAL;
5368 if (error)
5369 return error;
5370
5371 /* Obtain a SID for the context, if one was specified. */
5372 if (size && str[1] && str[1] != '\n') {
5373 if (str[size-1] == '\n') {
5374 str[size-1] = 0;
5375 size--;
5376 }
5377 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005378 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5379 if (!capable(CAP_MAC_ADMIN))
5380 return error;
5381 error = security_context_to_sid_force(value, size,
5382 &sid);
5383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 if (error)
5385 return error;
5386 }
5387
David Howellsd84f4f92008-11-14 10:39:23 +11005388 new = prepare_creds();
5389 if (!new)
5390 return -ENOMEM;
5391
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 /* Permission checking based on the specified context is
5393 performed during the actual operation (execve,
5394 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005395 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 checks and may_create for the file creation checks. The
5397 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005398 tsec = new->security;
5399 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005401 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005403 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005404 error = may_create_key(sid, p);
5405 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005406 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005407 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005408 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005409 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005410 } else if (!strcmp(name, "current")) {
5411 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005413 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005414
David Howellsd84f4f92008-11-14 10:39:23 +11005415 /* Only allow single threaded processes to change context */
5416 error = -EPERM;
5417 if (!is_single_threaded(p)) {
5418 error = security_bounded_transition(tsec->sid, sid);
5419 if (error)
5420 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422
5423 /* Check permissions for the transition. */
5424 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005425 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005427 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428
5429 /* Check for ptracing, and update the task SID if ok.
5430 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005431 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005433 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005434 if (tracer)
5435 ptsid = task_sid(tracer);
5436 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437
David Howellsd84f4f92008-11-14 10:39:23 +11005438 if (tracer) {
5439 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5440 PROCESS__PTRACE, NULL);
5441 if (error)
5442 goto abort_change;
5443 }
5444
5445 tsec->sid = sid;
5446 } else {
5447 error = -EINVAL;
5448 goto abort_change;
5449 }
5450
5451 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005453
5454abort_change:
5455 abort_creds(new);
5456 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457}
5458
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005459static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5460{
5461 return security_sid_to_context(secid, secdata, seclen);
5462}
5463
David Howells7bf570d2008-04-29 20:52:51 +01005464static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005465{
5466 return security_context_to_sid(secdata, seclen, secid);
5467}
5468
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005469static void selinux_release_secctx(char *secdata, u32 seclen)
5470{
Paul Moore088999e2007-08-01 11:12:58 -04005471 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005472}
5473
Michael LeMayd7200242006-06-22 14:47:17 -07005474#ifdef CONFIG_KEYS
5475
David Howellsd84f4f92008-11-14 10:39:23 +11005476static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005477 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005478{
David Howellsd84f4f92008-11-14 10:39:23 +11005479 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005480 struct key_security_struct *ksec;
5481
5482 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5483 if (!ksec)
5484 return -ENOMEM;
5485
David Howellsd84f4f92008-11-14 10:39:23 +11005486 tsec = cred->security;
5487 if (tsec->keycreate_sid)
5488 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005489 else
David Howellsd84f4f92008-11-14 10:39:23 +11005490 ksec->sid = tsec->sid;
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,
David Howellsd84f4f92008-11-14 10:39:23 +11005505 const struct cred *cred,
5506 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005507{
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 Howellsd84f4f92008-11-14 10:39:23 +11005518 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005519
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,
David Howellsd84f4f92008-11-14 10:39:23 +11005548 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 .sysctl = selinux_sysctl,
5550 .capable = selinux_capable,
5551 .quotactl = selinux_quotactl,
5552 .quota_on = selinux_quota_on,
5553 .syslog = selinux_syslog,
5554 .vm_enough_memory = selinux_vm_enough_memory,
5555
5556 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005557 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
5559 .bprm_alloc_security = selinux_bprm_alloc_security,
5560 .bprm_free_security = selinux_bprm_free_security,
5561 .bprm_apply_creds = selinux_bprm_apply_creds,
5562 .bprm_post_apply_creds = selinux_bprm_post_apply_creds,
5563 .bprm_set_security = selinux_bprm_set_security,
5564 .bprm_check_security = selinux_bprm_check_security,
5565 .bprm_secureexec = selinux_bprm_secureexec,
5566
5567 .sb_alloc_security = selinux_sb_alloc_security,
5568 .sb_free_security = selinux_sb_free_security,
5569 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005570 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005571 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 .sb_statfs = selinux_sb_statfs,
5573 .sb_mount = selinux_mount,
5574 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005575 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005576 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005577 .sb_parse_opts_str = selinux_parse_opts_str,
5578
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579
5580 .inode_alloc_security = selinux_inode_alloc_security,
5581 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005582 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 .inode_unlink = selinux_inode_unlink,
5586 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 .inode_rmdir = selinux_inode_rmdir,
5589 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 .inode_readlink = selinux_inode_readlink,
5592 .inode_follow_link = selinux_inode_follow_link,
5593 .inode_permission = selinux_inode_permission,
5594 .inode_setattr = selinux_inode_setattr,
5595 .inode_getattr = selinux_inode_getattr,
5596 .inode_setxattr = selinux_inode_setxattr,
5597 .inode_post_setxattr = selinux_inode_post_setxattr,
5598 .inode_getxattr = selinux_inode_getxattr,
5599 .inode_listxattr = selinux_inode_listxattr,
5600 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005601 .inode_getsecurity = selinux_inode_getsecurity,
5602 .inode_setsecurity = selinux_inode_setsecurity,
5603 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005604 .inode_need_killpriv = selinux_inode_need_killpriv,
5605 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005606 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607
5608 .file_permission = selinux_file_permission,
5609 .file_alloc_security = selinux_file_alloc_security,
5610 .file_free_security = selinux_file_free_security,
5611 .file_ioctl = selinux_file_ioctl,
5612 .file_mmap = selinux_file_mmap,
5613 .file_mprotect = selinux_file_mprotect,
5614 .file_lock = selinux_file_lock,
5615 .file_fcntl = selinux_file_fcntl,
5616 .file_set_fowner = selinux_file_set_fowner,
5617 .file_send_sigiotask = selinux_file_send_sigiotask,
5618 .file_receive = selinux_file_receive,
5619
Eric Paris828dfe12008-04-17 13:17:49 -04005620 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005621
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005623 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005624 .cred_prepare = selinux_cred_prepare,
5625 .cred_commit = selinux_cred_commit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005627 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 .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,
Eric Paris828dfe12008-04-17 13:17:49 -04005644 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
5646 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005647 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648
5649 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5650 .msg_msg_free_security = selinux_msg_msg_free_security,
5651
5652 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5653 .msg_queue_free_security = selinux_msg_queue_free_security,
5654 .msg_queue_associate = selinux_msg_queue_associate,
5655 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5656 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5657 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5658
5659 .shm_alloc_security = selinux_shm_alloc_security,
5660 .shm_free_security = selinux_shm_free_security,
5661 .shm_associate = selinux_shm_associate,
5662 .shm_shmctl = selinux_shm_shmctl,
5663 .shm_shmat = selinux_shm_shmat,
5664
Eric Paris828dfe12008-04-17 13:17:49 -04005665 .sem_alloc_security = selinux_sem_alloc_security,
5666 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 .sem_associate = selinux_sem_associate,
5668 .sem_semctl = selinux_sem_semctl,
5669 .sem_semop = selinux_sem_semop,
5670
Eric Paris828dfe12008-04-17 13:17:49 -04005671 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672
Eric Paris828dfe12008-04-17 13:17:49 -04005673 .getprocattr = selinux_getprocattr,
5674 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005676 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005677 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005678 .release_secctx = selinux_release_secctx,
5679
Eric Paris828dfe12008-04-17 13:17:49 -04005680 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 .unix_may_send = selinux_socket_unix_may_send,
5682
5683 .socket_create = selinux_socket_create,
5684 .socket_post_create = selinux_socket_post_create,
5685 .socket_bind = selinux_socket_bind,
5686 .socket_connect = selinux_socket_connect,
5687 .socket_listen = selinux_socket_listen,
5688 .socket_accept = selinux_socket_accept,
5689 .socket_sendmsg = selinux_socket_sendmsg,
5690 .socket_recvmsg = selinux_socket_recvmsg,
5691 .socket_getsockname = selinux_socket_getsockname,
5692 .socket_getpeername = selinux_socket_getpeername,
5693 .socket_getsockopt = selinux_socket_getsockopt,
5694 .socket_setsockopt = selinux_socket_setsockopt,
5695 .socket_shutdown = selinux_socket_shutdown,
5696 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005697 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5698 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 .sk_alloc_security = selinux_sk_alloc_security,
5700 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005701 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005702 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005703 .sock_graft = selinux_sock_graft,
5704 .inet_conn_request = selinux_inet_conn_request,
5705 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005706 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005707 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005708
5709#ifdef CONFIG_SECURITY_NETWORK_XFRM
5710 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5711 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5712 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005713 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005714 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5715 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005716 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005717 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005718 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005719 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005721
5722#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005723 .key_alloc = selinux_key_alloc,
5724 .key_free = selinux_key_free,
5725 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005726 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005727#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005728
5729#ifdef CONFIG_AUDIT
5730 .audit_rule_init = selinux_audit_rule_init,
5731 .audit_rule_known = selinux_audit_rule_known,
5732 .audit_rule_match = selinux_audit_rule_match,
5733 .audit_rule_free = selinux_audit_rule_free,
5734#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735};
5736
5737static __init int selinux_init(void)
5738{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005739 if (!security_module_enable(&selinux_ops)) {
5740 selinux_enabled = 0;
5741 return 0;
5742 }
5743
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 if (!selinux_enabled) {
5745 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5746 return 0;
5747 }
5748
5749 printk(KERN_INFO "SELinux: Initializing.\n");
5750
5751 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005752 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753
James Morris7cae7e22006-03-22 00:09:22 -08005754 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5755 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005756 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 avc_init();
5758
James Morris6f0f0fd2008-07-10 17:02:07 +09005759 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005761 panic("SELinux: No initial security operations\n");
5762 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 panic("SELinux: Unable to register with kernel.\n");
5764
Eric Paris828dfe12008-04-17 13:17:49 -04005765 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005766 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005767 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005768 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005769
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 return 0;
5771}
5772
5773void selinux_complete_init(void)
5774{
Eric Parisfadcdb42007-02-22 18:11:31 -05005775 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776
5777 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005778 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005779 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 spin_lock(&sb_security_lock);
5781next_sb:
5782 if (!list_empty(&superblock_security_head)) {
5783 struct superblock_security_struct *sbsec =
5784 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005785 struct superblock_security_struct,
5786 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005790 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 down_read(&sb->s_umount);
5792 if (sb->s_root)
5793 superblock_doinit(sb, NULL);
5794 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005795 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 spin_lock(&sb_security_lock);
5797 list_del_init(&sbsec->list);
5798 goto next_sb;
5799 }
5800 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005801 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802}
5803
5804/* SELinux requires early initialization in order to label
5805 all processes and objects when they are created. */
5806security_initcall(selinux_init);
5807
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005808#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809
Paul Mooreeffad8d2008-01-29 08:49:27 -05005810static struct nf_hook_ops selinux_ipv4_ops[] = {
5811 {
5812 .hook = selinux_ipv4_postroute,
5813 .owner = THIS_MODULE,
5814 .pf = PF_INET,
5815 .hooknum = NF_INET_POST_ROUTING,
5816 .priority = NF_IP_PRI_SELINUX_LAST,
5817 },
5818 {
5819 .hook = selinux_ipv4_forward,
5820 .owner = THIS_MODULE,
5821 .pf = PF_INET,
5822 .hooknum = NF_INET_FORWARD,
5823 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005824 },
5825 {
5826 .hook = selinux_ipv4_output,
5827 .owner = THIS_MODULE,
5828 .pf = PF_INET,
5829 .hooknum = NF_INET_LOCAL_OUT,
5830 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832};
5833
5834#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5835
Paul Mooreeffad8d2008-01-29 08:49:27 -05005836static struct nf_hook_ops selinux_ipv6_ops[] = {
5837 {
5838 .hook = selinux_ipv6_postroute,
5839 .owner = THIS_MODULE,
5840 .pf = PF_INET6,
5841 .hooknum = NF_INET_POST_ROUTING,
5842 .priority = NF_IP6_PRI_SELINUX_LAST,
5843 },
5844 {
5845 .hook = selinux_ipv6_forward,
5846 .owner = THIS_MODULE,
5847 .pf = PF_INET6,
5848 .hooknum = NF_INET_FORWARD,
5849 .priority = NF_IP6_PRI_SELINUX_FIRST,
5850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851};
5852
5853#endif /* IPV6 */
5854
5855static int __init selinux_nf_ip_init(void)
5856{
5857 int err = 0;
5858
5859 if (!selinux_enabled)
5860 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005861
5862 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5863
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005864 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5865 if (err)
5866 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867
5868#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005869 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5870 if (err)
5871 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005873
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874out:
5875 return err;
5876}
5877
5878__initcall(selinux_nf_ip_init);
5879
5880#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5881static void selinux_nf_ip_exit(void)
5882{
Eric Parisfadcdb42007-02-22 18:11:31 -05005883 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005885 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005887 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888#endif /* IPV6 */
5889}
5890#endif
5891
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005892#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893
5894#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5895#define selinux_nf_ip_exit()
5896#endif
5897
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005898#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899
5900#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005901static int selinux_disabled;
5902
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903int selinux_disable(void)
5904{
5905 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906
5907 if (ss_initialized) {
5908 /* Not permitted after initial policy load. */
5909 return -EINVAL;
5910 }
5911
5912 if (selinux_disabled) {
5913 /* Only do this once. */
5914 return -EINVAL;
5915 }
5916
5917 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5918
5919 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005920 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
5922 /* Reset security_ops to the secondary module, dummy or capability. */
5923 security_ops = secondary_ops;
5924
5925 /* Unregister netfilter hooks. */
5926 selinux_nf_ip_exit();
5927
5928 /* Unregister selinuxfs. */
5929 exit_sel_fs();
5930
5931 return 0;
5932}
5933#endif