blob: 473adc5f4f9aab2333e66ebe5e38d92c6658fb3a [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 Howells3b11a1d2008-11-14 10:39:26 +1100164 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct task_security_struct *tsec;
166
James Morris89d155e2005-10-30 14:59:21 -0800167 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100169 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
David Howellsd84f4f92008-11-14 10:39:23 +1100171 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100172 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
David Howells275bb412008-11-14 10:39:19 +1100175/*
David Howells88e67f32008-11-14 10:39:21 +1100176 * get the security ID of a set of credentials
177 */
178static inline u32 cred_sid(const struct cred *cred)
179{
180 const struct task_security_struct *tsec;
181
182 tsec = cred->security;
183 return tsec->sid;
184}
185
186/*
David Howells3b11a1d2008-11-14 10:39:26 +1100187 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100188 */
189static inline u32 task_sid(const struct task_struct *task)
190{
David Howells275bb412008-11-14 10:39:19 +1100191 u32 sid;
192
193 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100194 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100195 rcu_read_unlock();
196 return sid;
197}
198
199/*
David Howells3b11a1d2008-11-14 10:39:26 +1100200 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100201 */
202static inline u32 current_sid(void)
203{
204 const struct task_security_struct *tsec = current_cred()->security;
205
206 return tsec->sid;
207}
208
David Howells88e67f32008-11-14 10:39:21 +1100209/* Allocate and free functions for each kind of security blob. */
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211static int inode_alloc_security(struct inode *inode)
212{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100214 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Josef Bacika02fe132008-04-04 09:35:05 +1100216 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 if (!isec)
218 return -ENOMEM;
219
Eric Paris23970742006-09-25 23:32:01 -0700220 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 isec->inode = inode;
223 isec->sid = SECINITSID_UNLABELED;
224 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100225 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 inode->i_security = isec;
227
228 return 0;
229}
230
231static void inode_free_security(struct inode *inode)
232{
233 struct inode_security_struct *isec = inode->i_security;
234 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 spin_lock(&sbsec->isec_lock);
237 if (!list_empty(&isec->list))
238 list_del_init(&isec->list);
239 spin_unlock(&sbsec->isec_lock);
240
241 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800242 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245static int file_alloc_security(struct file *file)
246{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100248 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800250 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if (!fsec)
252 return -ENOMEM;
253
David Howells275bb412008-11-14 10:39:19 +1100254 fsec->sid = sid;
255 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 file->f_security = fsec;
257
258 return 0;
259}
260
261static void file_free_security(struct file *file)
262{
263 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 file->f_security = NULL;
265 kfree(fsec);
266}
267
268static int superblock_alloc_security(struct super_block *sb)
269{
270 struct superblock_security_struct *sbsec;
271
James Morris89d155e2005-10-30 14:59:21 -0800272 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 if (!sbsec)
274 return -ENOMEM;
275
Eric Parisbc7e9822006-09-25 23:32:02 -0700276 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 INIT_LIST_HEAD(&sbsec->list);
278 INIT_LIST_HEAD(&sbsec->isec_head);
279 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sbsec->sb = sb;
281 sbsec->sid = SECINITSID_UNLABELED;
282 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700283 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 sb->s_security = sbsec;
285
286 return 0;
287}
288
289static void superblock_free_security(struct super_block *sb)
290{
291 struct superblock_security_struct *sbsec = sb->s_security;
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 spin_lock(&sb_security_lock);
294 if (!list_empty(&sbsec->list))
295 list_del_init(&sbsec->list);
296 spin_unlock(&sb_security_lock);
297
298 sb->s_security = NULL;
299 kfree(sbsec);
300}
301
Al Viro7d877f32005-10-21 03:20:43 -0400302static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 struct sk_security_struct *ssec;
305
James Morris89d155e2005-10-30 14:59:21 -0800306 ssec = kzalloc(sizeof(*ssec), priority);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 if (!ssec)
308 return -ENOMEM;
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 ssec->peer_sid = SECINITSID_UNLABELED;
Venkat Yekkirala892c1412006-08-04 23:08:56 -0700311 ssec->sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 sk->sk_security = ssec;
313
Paul Mooref74af6e2008-02-25 11:40:33 -0500314 selinux_netlbl_sk_security_reset(ssec, family);
Paul Moore99f59ed2006-08-29 17:53:48 -0700315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return 0;
317}
318
319static void sk_free_security(struct sock *sk)
320{
321 struct sk_security_struct *ssec = sk->sk_security;
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 sk->sk_security = NULL;
Paul Moore6c5b3fc2008-10-10 10:16:33 -0400324 selinux_netlbl_sk_security_free(ssec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 kfree(ssec);
326}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328/* The security server must be initialized before
329 any labeling or access decisions can be provided. */
330extern int ss_initialized;
331
332/* The file system's label must be initialized prior to use. */
333
334static char *labeling_behaviors[6] = {
335 "uses xattr",
336 "uses transition SIDs",
337 "uses task SIDs",
338 "uses genfs_contexts",
339 "not configured for labeling",
340 "uses mountpoint labeling",
341};
342
343static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
344
345static inline int inode_doinit(struct inode *inode)
346{
347 return inode_doinit_with_dentry(inode, NULL);
348}
349
350enum {
Eric Paris31e87932007-09-19 17:19:12 -0400351 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 Opt_context = 1,
353 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500354 Opt_defcontext = 3,
355 Opt_rootcontext = 4,
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
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500434 sbsec->flags |= SE_SBINITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
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
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500490 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500491 return -EINVAL;
492
493 if (!ss_initialized)
494 return -EINVAL;
495
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500496 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500497 /* count the number of mount options for this sb */
498 for (i = 0; i < 8; i++) {
499 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500500 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500501 tmp >>= 1;
502 }
503
Eric Parise0007522008-03-05 10:31:54 -0500504 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
505 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500506 rc = -ENOMEM;
507 goto out_free;
508 }
509
Eric Parise0007522008-03-05 10:31:54 -0500510 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
511 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500512 rc = -ENOMEM;
513 goto out_free;
514 }
515
516 i = 0;
517 if (sbsec->flags & FSCONTEXT_MNT) {
518 rc = security_sid_to_context(sbsec->sid, &context, &len);
519 if (rc)
520 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500521 opts->mnt_opts[i] = context;
522 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500523 }
524 if (sbsec->flags & CONTEXT_MNT) {
525 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
526 if (rc)
527 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500528 opts->mnt_opts[i] = context;
529 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500530 }
531 if (sbsec->flags & DEFCONTEXT_MNT) {
532 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
533 if (rc)
534 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500535 opts->mnt_opts[i] = context;
536 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500537 }
538 if (sbsec->flags & ROOTCONTEXT_MNT) {
539 struct inode *root = sbsec->sb->s_root->d_inode;
540 struct inode_security_struct *isec = root->i_security;
541
542 rc = security_sid_to_context(isec->sid, &context, &len);
543 if (rc)
544 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500545 opts->mnt_opts[i] = context;
546 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500547 }
548
Eric Parise0007522008-03-05 10:31:54 -0500549 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500550
551 return 0;
552
553out_free:
Eric Parise0007522008-03-05 10:31:54 -0500554 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500555 return rc;
556}
557
558static int bad_option(struct superblock_security_struct *sbsec, char flag,
559 u32 old_sid, u32 new_sid)
560{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500561 char mnt_flags = sbsec->flags & SE_MNTMASK;
562
Eric Parisc9180a52007-11-30 13:00:35 -0500563 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500564 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500565 if (!(sbsec->flags & flag) ||
566 (old_sid != new_sid))
567 return 1;
568
569 /* check if we were passed the same options twice,
570 * aka someone passed context=a,context=b
571 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500572 if (!(sbsec->flags & SE_SBINITIALIZED))
573 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500574 return 1;
575 return 0;
576}
Eric Parise0007522008-03-05 10:31:54 -0500577
Eric Parisc9180a52007-11-30 13:00:35 -0500578/*
579 * Allow filesystems with binary mount data to explicitly set mount point
580 * labeling information.
581 */
Eric Parise0007522008-03-05 10:31:54 -0500582static int selinux_set_mnt_opts(struct super_block *sb,
583 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500584{
David Howells275bb412008-11-14 10:39:19 +1100585 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500586 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500587 struct superblock_security_struct *sbsec = sb->s_security;
588 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000589 struct inode *inode = sbsec->sb->s_root->d_inode;
590 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500591 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
592 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500593 char **mount_options = opts->mnt_opts;
594 int *flags = opts->mnt_opts_flags;
595 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500596
597 mutex_lock(&sbsec->lock);
598
599 if (!ss_initialized) {
600 if (!num_opts) {
601 /* Defer initialization until selinux_complete_init,
602 after the initial policy is loaded and the security
603 server is ready to handle calls. */
604 spin_lock(&sb_security_lock);
605 if (list_empty(&sbsec->list))
606 list_add(&sbsec->list, &superblock_security_head);
607 spin_unlock(&sb_security_lock);
608 goto out;
609 }
610 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400611 printk(KERN_WARNING "SELinux: Unable to set superblock options "
612 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500613 goto out;
614 }
615
616 /*
Eric Parise0007522008-03-05 10:31:54 -0500617 * Binary mount data FS will come through this function twice. Once
618 * from an explicit call and once from the generic calls from the vfs.
619 * Since the generic VFS calls will not contain any security mount data
620 * we need to skip the double mount verification.
621 *
622 * This does open a hole in which we will not notice if the first
623 * mount using this sb set explict options and a second mount using
624 * this sb does not set any security options. (The first options
625 * will be used for both mounts)
626 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500627 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500628 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400629 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500630
631 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500632 * parse the mount options, check if they are valid sids.
633 * also check if someone is trying to mount the same sb more
634 * than once with different security options.
635 */
636 for (i = 0; i < num_opts; i++) {
637 u32 sid;
638 rc = security_context_to_sid(mount_options[i],
639 strlen(mount_options[i]), &sid);
640 if (rc) {
641 printk(KERN_WARNING "SELinux: security_context_to_sid"
642 "(%s) failed for (dev %s, type %s) errno=%d\n",
643 mount_options[i], sb->s_id, name, rc);
644 goto out;
645 }
646 switch (flags[i]) {
647 case FSCONTEXT_MNT:
648 fscontext_sid = sid;
649
650 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
651 fscontext_sid))
652 goto out_double_mount;
653
654 sbsec->flags |= FSCONTEXT_MNT;
655 break;
656 case CONTEXT_MNT:
657 context_sid = sid;
658
659 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
660 context_sid))
661 goto out_double_mount;
662
663 sbsec->flags |= CONTEXT_MNT;
664 break;
665 case ROOTCONTEXT_MNT:
666 rootcontext_sid = sid;
667
668 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
669 rootcontext_sid))
670 goto out_double_mount;
671
672 sbsec->flags |= ROOTCONTEXT_MNT;
673
674 break;
675 case DEFCONTEXT_MNT:
676 defcontext_sid = sid;
677
678 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
679 defcontext_sid))
680 goto out_double_mount;
681
682 sbsec->flags |= DEFCONTEXT_MNT;
683
684 break;
685 default:
686 rc = -EINVAL;
687 goto out;
688 }
689 }
690
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500691 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500692 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500693 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500694 goto out_double_mount;
695 rc = 0;
696 goto out;
697 }
698
James Morris089be432008-07-15 18:32:49 +1000699 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500700 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500701
702 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500703 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500704 if (rc) {
705 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000706 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500707 goto out;
708 }
709
710 /* sets the context of the superblock for the fs being mounted. */
711 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100712 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500713 if (rc)
714 goto out;
715
716 sbsec->sid = fscontext_sid;
717 }
718
719 /*
720 * Switch to using mount point labeling behavior.
721 * sets the label used on all file below the mountpoint, and will set
722 * the superblock context if not already set.
723 */
724 if (context_sid) {
725 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100726 rc = may_context_mount_sb_relabel(context_sid, sbsec,
727 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500728 if (rc)
729 goto out;
730 sbsec->sid = context_sid;
731 } else {
David Howells275bb412008-11-14 10:39:19 +1100732 rc = may_context_mount_inode_relabel(context_sid, sbsec,
733 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500734 if (rc)
735 goto out;
736 }
737 if (!rootcontext_sid)
738 rootcontext_sid = context_sid;
739
740 sbsec->mntpoint_sid = context_sid;
741 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
742 }
743
744 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100745 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
746 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500747 if (rc)
748 goto out;
749
750 root_isec->sid = rootcontext_sid;
751 root_isec->initialized = 1;
752 }
753
754 if (defcontext_sid) {
755 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
756 rc = -EINVAL;
757 printk(KERN_WARNING "SELinux: defcontext option is "
758 "invalid for this filesystem type\n");
759 goto out;
760 }
761
762 if (defcontext_sid != sbsec->def_sid) {
763 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100764 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500765 if (rc)
766 goto out;
767 }
768
769 sbsec->def_sid = defcontext_sid;
770 }
771
772 rc = sb_finish_set_opts(sb);
773out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700774 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500776out_double_mount:
777 rc = -EINVAL;
778 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
779 "security settings for (dev %s, type %s)\n", sb->s_id, name);
780 goto out;
781}
782
783static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
784 struct super_block *newsb)
785{
786 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
787 struct superblock_security_struct *newsbsec = newsb->s_security;
788
789 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
790 int set_context = (oldsbsec->flags & CONTEXT_MNT);
791 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
792
Eric Paris0f5e6422008-04-21 16:24:11 -0400793 /*
794 * if the parent was able to be mounted it clearly had no special lsm
795 * mount options. thus we can safely put this sb on the list and deal
796 * with it later
797 */
798 if (!ss_initialized) {
799 spin_lock(&sb_security_lock);
800 if (list_empty(&newsbsec->list))
801 list_add(&newsbsec->list, &superblock_security_head);
802 spin_unlock(&sb_security_lock);
803 return;
804 }
Eric Parisc9180a52007-11-30 13:00:35 -0500805
Eric Parisc9180a52007-11-30 13:00:35 -0500806 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500807 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500808
Eric Paris5a552612008-04-09 14:08:35 -0400809 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500810 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400811 return;
812
Eric Parisc9180a52007-11-30 13:00:35 -0500813 mutex_lock(&newsbsec->lock);
814
815 newsbsec->flags = oldsbsec->flags;
816
817 newsbsec->sid = oldsbsec->sid;
818 newsbsec->def_sid = oldsbsec->def_sid;
819 newsbsec->behavior = oldsbsec->behavior;
820
821 if (set_context) {
822 u32 sid = oldsbsec->mntpoint_sid;
823
824 if (!set_fscontext)
825 newsbsec->sid = sid;
826 if (!set_rootcontext) {
827 struct inode *newinode = newsb->s_root->d_inode;
828 struct inode_security_struct *newisec = newinode->i_security;
829 newisec->sid = sid;
830 }
831 newsbsec->mntpoint_sid = sid;
832 }
833 if (set_rootcontext) {
834 const struct inode *oldinode = oldsb->s_root->d_inode;
835 const struct inode_security_struct *oldisec = oldinode->i_security;
836 struct inode *newinode = newsb->s_root->d_inode;
837 struct inode_security_struct *newisec = newinode->i_security;
838
839 newisec->sid = oldisec->sid;
840 }
841
842 sb_finish_set_opts(newsb);
843 mutex_unlock(&newsbsec->lock);
844}
845
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200846static int selinux_parse_opts_str(char *options,
847 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500848{
Eric Parise0007522008-03-05 10:31:54 -0500849 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500850 char *context = NULL, *defcontext = NULL;
851 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500852 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500853
Eric Parise0007522008-03-05 10:31:54 -0500854 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500855
856 /* Standard string-based options. */
857 while ((p = strsep(&options, "|")) != NULL) {
858 int token;
859 substring_t args[MAX_OPT_ARGS];
860
861 if (!*p)
862 continue;
863
864 token = match_token(p, tokens, args);
865
866 switch (token) {
867 case Opt_context:
868 if (context || defcontext) {
869 rc = -EINVAL;
870 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
871 goto out_err;
872 }
873 context = match_strdup(&args[0]);
874 if (!context) {
875 rc = -ENOMEM;
876 goto out_err;
877 }
878 break;
879
880 case Opt_fscontext:
881 if (fscontext) {
882 rc = -EINVAL;
883 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
884 goto out_err;
885 }
886 fscontext = match_strdup(&args[0]);
887 if (!fscontext) {
888 rc = -ENOMEM;
889 goto out_err;
890 }
891 break;
892
893 case Opt_rootcontext:
894 if (rootcontext) {
895 rc = -EINVAL;
896 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
897 goto out_err;
898 }
899 rootcontext = match_strdup(&args[0]);
900 if (!rootcontext) {
901 rc = -ENOMEM;
902 goto out_err;
903 }
904 break;
905
906 case Opt_defcontext:
907 if (context || defcontext) {
908 rc = -EINVAL;
909 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
910 goto out_err;
911 }
912 defcontext = match_strdup(&args[0]);
913 if (!defcontext) {
914 rc = -ENOMEM;
915 goto out_err;
916 }
917 break;
918
919 default:
920 rc = -EINVAL;
921 printk(KERN_WARNING "SELinux: unknown mount option\n");
922 goto out_err;
923
924 }
925 }
926
Eric Parise0007522008-03-05 10:31:54 -0500927 rc = -ENOMEM;
928 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
929 if (!opts->mnt_opts)
930 goto out_err;
931
932 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
933 if (!opts->mnt_opts_flags) {
934 kfree(opts->mnt_opts);
935 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500936 }
937
Eric Parise0007522008-03-05 10:31:54 -0500938 if (fscontext) {
939 opts->mnt_opts[num_mnt_opts] = fscontext;
940 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
941 }
942 if (context) {
943 opts->mnt_opts[num_mnt_opts] = context;
944 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
945 }
946 if (rootcontext) {
947 opts->mnt_opts[num_mnt_opts] = rootcontext;
948 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
949 }
950 if (defcontext) {
951 opts->mnt_opts[num_mnt_opts] = defcontext;
952 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
953 }
954
955 opts->num_mnt_opts = num_mnt_opts;
956 return 0;
957
Eric Parisc9180a52007-11-30 13:00:35 -0500958out_err:
959 kfree(context);
960 kfree(defcontext);
961 kfree(fscontext);
962 kfree(rootcontext);
963 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964}
Eric Parise0007522008-03-05 10:31:54 -0500965/*
966 * string mount options parsing and call set the sbsec
967 */
968static int superblock_doinit(struct super_block *sb, void *data)
969{
970 int rc = 0;
971 char *options = data;
972 struct security_mnt_opts opts;
973
974 security_init_mnt_opts(&opts);
975
976 if (!data)
977 goto out;
978
979 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
980
981 rc = selinux_parse_opts_str(options, &opts);
982 if (rc)
983 goto out_err;
984
985out:
986 rc = selinux_set_mnt_opts(sb, &opts);
987
988out_err:
989 security_free_mnt_opts(&opts);
990 return rc;
991}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Adrian Bunk3583a712008-07-22 20:21:23 +0300993static void selinux_write_opts(struct seq_file *m,
994 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000995{
996 int i;
997 char *prefix;
998
999 for (i = 0; i < opts->num_mnt_opts; i++) {
1000 char *has_comma = strchr(opts->mnt_opts[i], ',');
1001
1002 switch (opts->mnt_opts_flags[i]) {
1003 case CONTEXT_MNT:
1004 prefix = CONTEXT_STR;
1005 break;
1006 case FSCONTEXT_MNT:
1007 prefix = FSCONTEXT_STR;
1008 break;
1009 case ROOTCONTEXT_MNT:
1010 prefix = ROOTCONTEXT_STR;
1011 break;
1012 case DEFCONTEXT_MNT:
1013 prefix = DEFCONTEXT_STR;
1014 break;
1015 default:
1016 BUG();
1017 };
1018 /* we need a comma before each option */
1019 seq_putc(m, ',');
1020 seq_puts(m, prefix);
1021 if (has_comma)
1022 seq_putc(m, '\"');
1023 seq_puts(m, opts->mnt_opts[i]);
1024 if (has_comma)
1025 seq_putc(m, '\"');
1026 }
1027}
1028
1029static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1030{
1031 struct security_mnt_opts opts;
1032 int rc;
1033
1034 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001035 if (rc) {
1036 /* before policy load we may get EINVAL, don't show anything */
1037 if (rc == -EINVAL)
1038 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001039 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001040 }
Eric Paris2069f452008-07-04 09:47:13 +10001041
1042 selinux_write_opts(m, &opts);
1043
1044 security_free_mnt_opts(&opts);
1045
1046 return rc;
1047}
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049static inline u16 inode_mode_to_security_class(umode_t mode)
1050{
1051 switch (mode & S_IFMT) {
1052 case S_IFSOCK:
1053 return SECCLASS_SOCK_FILE;
1054 case S_IFLNK:
1055 return SECCLASS_LNK_FILE;
1056 case S_IFREG:
1057 return SECCLASS_FILE;
1058 case S_IFBLK:
1059 return SECCLASS_BLK_FILE;
1060 case S_IFDIR:
1061 return SECCLASS_DIR;
1062 case S_IFCHR:
1063 return SECCLASS_CHR_FILE;
1064 case S_IFIFO:
1065 return SECCLASS_FIFO_FILE;
1066
1067 }
1068
1069 return SECCLASS_FILE;
1070}
1071
James Morris13402582005-09-30 14:24:34 -04001072static inline int default_protocol_stream(int protocol)
1073{
1074 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1075}
1076
1077static inline int default_protocol_dgram(int protocol)
1078{
1079 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1080}
1081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1083{
1084 switch (family) {
1085 case PF_UNIX:
1086 switch (type) {
1087 case SOCK_STREAM:
1088 case SOCK_SEQPACKET:
1089 return SECCLASS_UNIX_STREAM_SOCKET;
1090 case SOCK_DGRAM:
1091 return SECCLASS_UNIX_DGRAM_SOCKET;
1092 }
1093 break;
1094 case PF_INET:
1095 case PF_INET6:
1096 switch (type) {
1097 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001098 if (default_protocol_stream(protocol))
1099 return SECCLASS_TCP_SOCKET;
1100 else
1101 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001103 if (default_protocol_dgram(protocol))
1104 return SECCLASS_UDP_SOCKET;
1105 else
1106 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001107 case SOCK_DCCP:
1108 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001109 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return SECCLASS_RAWIP_SOCKET;
1111 }
1112 break;
1113 case PF_NETLINK:
1114 switch (protocol) {
1115 case NETLINK_ROUTE:
1116 return SECCLASS_NETLINK_ROUTE_SOCKET;
1117 case NETLINK_FIREWALL:
1118 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001119 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1121 case NETLINK_NFLOG:
1122 return SECCLASS_NETLINK_NFLOG_SOCKET;
1123 case NETLINK_XFRM:
1124 return SECCLASS_NETLINK_XFRM_SOCKET;
1125 case NETLINK_SELINUX:
1126 return SECCLASS_NETLINK_SELINUX_SOCKET;
1127 case NETLINK_AUDIT:
1128 return SECCLASS_NETLINK_AUDIT_SOCKET;
1129 case NETLINK_IP6_FW:
1130 return SECCLASS_NETLINK_IP6FW_SOCKET;
1131 case NETLINK_DNRTMSG:
1132 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001133 case NETLINK_KOBJECT_UEVENT:
1134 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 default:
1136 return SECCLASS_NETLINK_SOCKET;
1137 }
1138 case PF_PACKET:
1139 return SECCLASS_PACKET_SOCKET;
1140 case PF_KEY:
1141 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001142 case PF_APPLETALK:
1143 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 }
1145
1146 return SECCLASS_SOCKET;
1147}
1148
1149#ifdef CONFIG_PROC_FS
1150static int selinux_proc_get_sid(struct proc_dir_entry *de,
1151 u16 tclass,
1152 u32 *sid)
1153{
1154 int buflen, rc;
1155 char *buffer, *path, *end;
1156
Eric Paris828dfe12008-04-17 13:17:49 -04001157 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (!buffer)
1159 return -ENOMEM;
1160
1161 buflen = PAGE_SIZE;
1162 end = buffer+buflen;
1163 *--end = '\0';
1164 buflen--;
1165 path = end-1;
1166 *path = '/';
1167 while (de && de != de->parent) {
1168 buflen -= de->namelen + 1;
1169 if (buflen < 0)
1170 break;
1171 end -= de->namelen;
1172 memcpy(end, de->name, de->namelen);
1173 *--end = '/';
1174 path = end;
1175 de = de->parent;
1176 }
1177 rc = security_genfs_sid("proc", path, tclass, sid);
1178 free_page((unsigned long)buffer);
1179 return rc;
1180}
1181#else
1182static int selinux_proc_get_sid(struct proc_dir_entry *de,
1183 u16 tclass,
1184 u32 *sid)
1185{
1186 return -EINVAL;
1187}
1188#endif
1189
1190/* The inode's security attributes must be initialized before first use. */
1191static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1192{
1193 struct superblock_security_struct *sbsec = NULL;
1194 struct inode_security_struct *isec = inode->i_security;
1195 u32 sid;
1196 struct dentry *dentry;
1197#define INITCONTEXTLEN 255
1198 char *context = NULL;
1199 unsigned len = 0;
1200 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
1202 if (isec->initialized)
1203 goto out;
1204
Eric Paris23970742006-09-25 23:32:01 -07001205 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001207 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001210 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 /* Defer initialization until selinux_complete_init,
1212 after the initial policy is loaded and the security
1213 server is ready to handle calls. */
1214 spin_lock(&sbsec->isec_lock);
1215 if (list_empty(&isec->list))
1216 list_add(&isec->list, &sbsec->isec_head);
1217 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001218 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
1220
1221 switch (sbsec->behavior) {
1222 case SECURITY_FS_USE_XATTR:
1223 if (!inode->i_op->getxattr) {
1224 isec->sid = sbsec->def_sid;
1225 break;
1226 }
1227
1228 /* Need a dentry, since the xattr API requires one.
1229 Life would be simpler if we could just pass the inode. */
1230 if (opt_dentry) {
1231 /* Called from d_instantiate or d_splice_alias. */
1232 dentry = dget(opt_dentry);
1233 } else {
1234 /* Called from selinux_complete_init, try to find a dentry. */
1235 dentry = d_find_alias(inode);
1236 }
1237 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001238 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001239 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001241 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243
1244 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001245 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 if (!context) {
1247 rc = -ENOMEM;
1248 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001249 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 }
1251 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1252 context, len);
1253 if (rc == -ERANGE) {
1254 /* Need a larger buffer. Query for the right size. */
1255 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1256 NULL, 0);
1257 if (rc < 0) {
1258 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001259 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
1261 kfree(context);
1262 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001263 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 if (!context) {
1265 rc = -ENOMEM;
1266 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001267 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 }
1269 rc = inode->i_op->getxattr(dentry,
1270 XATTR_NAME_SELINUX,
1271 context, len);
1272 }
1273 dput(dentry);
1274 if (rc < 0) {
1275 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001276 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001277 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 -rc, inode->i_sb->s_id, inode->i_ino);
1279 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001280 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 }
1282 /* Map ENODATA to the default file SID */
1283 sid = sbsec->def_sid;
1284 rc = 0;
1285 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001286 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001287 sbsec->def_sid,
1288 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001290 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001292 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 inode->i_sb->s_id, inode->i_ino);
1294 kfree(context);
1295 /* Leave with the unlabeled SID */
1296 rc = 0;
1297 break;
1298 }
1299 }
1300 kfree(context);
1301 isec->sid = sid;
1302 break;
1303 case SECURITY_FS_USE_TASK:
1304 isec->sid = isec->task_sid;
1305 break;
1306 case SECURITY_FS_USE_TRANS:
1307 /* Default to the fs SID. */
1308 isec->sid = sbsec->sid;
1309
1310 /* Try to obtain a transition SID. */
1311 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1312 rc = security_transition_sid(isec->task_sid,
1313 sbsec->sid,
1314 isec->sclass,
1315 &sid);
1316 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001317 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 isec->sid = sid;
1319 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001320 case SECURITY_FS_USE_MNTPOINT:
1321 isec->sid = sbsec->mntpoint_sid;
1322 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001324 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 isec->sid = sbsec->sid;
1326
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001327 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 struct proc_inode *proci = PROC_I(inode);
1329 if (proci->pde) {
1330 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1331 rc = selinux_proc_get_sid(proci->pde,
1332 isec->sclass,
1333 &sid);
1334 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001335 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 isec->sid = sid;
1337 }
1338 }
1339 break;
1340 }
1341
1342 isec->initialized = 1;
1343
Eric Paris23970742006-09-25 23:32:01 -07001344out_unlock:
1345 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346out:
1347 if (isec->sclass == SECCLASS_FILE)
1348 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return rc;
1350}
1351
1352/* Convert a Linux signal to an access vector. */
1353static inline u32 signal_to_av(int sig)
1354{
1355 u32 perm = 0;
1356
1357 switch (sig) {
1358 case SIGCHLD:
1359 /* Commonly granted from child to parent. */
1360 perm = PROCESS__SIGCHLD;
1361 break;
1362 case SIGKILL:
1363 /* Cannot be caught or ignored */
1364 perm = PROCESS__SIGKILL;
1365 break;
1366 case SIGSTOP:
1367 /* Cannot be caught or ignored */
1368 perm = PROCESS__SIGSTOP;
1369 break;
1370 default:
1371 /* All other signals. */
1372 perm = PROCESS__SIGNAL;
1373 break;
1374 }
1375
1376 return perm;
1377}
1378
David Howells275bb412008-11-14 10:39:19 +11001379/*
David Howellsd84f4f92008-11-14 10:39:23 +11001380 * Check permission between a pair of credentials
1381 * fork check, ptrace check, etc.
1382 */
1383static int cred_has_perm(const struct cred *actor,
1384 const struct cred *target,
1385 u32 perms)
1386{
1387 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1388
1389 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1390}
1391
1392/*
David Howells88e67f32008-11-14 10:39:21 +11001393 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001394 * fork check, ptrace check, etc.
1395 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001396 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001397 */
1398static int task_has_perm(const struct task_struct *tsk1,
1399 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 u32 perms)
1401{
David Howells275bb412008-11-14 10:39:19 +11001402 const struct task_security_struct *__tsec1, *__tsec2;
1403 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
David Howells275bb412008-11-14 10:39:19 +11001405 rcu_read_lock();
1406 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1407 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1408 rcu_read_unlock();
1409 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410}
1411
David Howells3b11a1d2008-11-14 10:39:26 +11001412/*
1413 * Check permission between current and another task, e.g. signal checks,
1414 * fork check, ptrace check, etc.
1415 * current is the actor and tsk2 is the target
1416 * - this uses current's subjective creds
1417 */
1418static int current_has_perm(const struct task_struct *tsk,
1419 u32 perms)
1420{
1421 u32 sid, tsid;
1422
1423 sid = current_sid();
1424 tsid = task_sid(tsk);
1425 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1426}
1427
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001428#if CAP_LAST_CAP > 63
1429#error Fix SELinux to handle capabilities > 63.
1430#endif
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432/* Check whether a task is allowed to use a capability. */
1433static int task_has_capability(struct task_struct *tsk,
David Howells3699c532009-01-06 22:27:01 +00001434 const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001435 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001438 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001439 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001440 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001441 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001442 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Eric Paris828dfe12008-04-17 13:17:49 -04001444 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 ad.tsk = tsk;
1446 ad.u.cap = cap;
1447
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001448 switch (CAP_TO_INDEX(cap)) {
1449 case 0:
1450 sclass = SECCLASS_CAPABILITY;
1451 break;
1452 case 1:
1453 sclass = SECCLASS_CAPABILITY2;
1454 break;
1455 default:
1456 printk(KERN_ERR
1457 "SELinux: out of range capability %d\n", cap);
1458 BUG();
1459 }
Eric Paris06112162008-11-11 22:02:50 +11001460
David Howells275bb412008-11-14 10:39:19 +11001461 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001462 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001463 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001464 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465}
1466
1467/* Check whether a task is allowed to use a system operation. */
1468static int task_has_system(struct task_struct *tsk,
1469 u32 perms)
1470{
David Howells275bb412008-11-14 10:39:19 +11001471 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
David Howells275bb412008-11-14 10:39:19 +11001473 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 SECCLASS_SYSTEM, perms, NULL);
1475}
1476
1477/* Check whether a task has a particular permission to an inode.
1478 The 'adp' parameter is optional and allows other audit
1479 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001480static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 struct inode *inode,
1482 u32 perms,
1483 struct avc_audit_data *adp)
1484{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 struct inode_security_struct *isec;
1486 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001487 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
Eric Paris828dfe12008-04-17 13:17:49 -04001489 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001490 return 0;
1491
David Howells88e67f32008-11-14 10:39:21 +11001492 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 isec = inode->i_security;
1494
1495 if (!adp) {
1496 adp = &ad;
1497 AVC_AUDIT_DATA_INIT(&ad, FS);
1498 ad.u.fs.inode = inode;
1499 }
1500
David Howells275bb412008-11-14 10:39:19 +11001501 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502}
1503
1504/* Same as inode_has_perm, but pass explicit audit data containing
1505 the dentry to help the auditing code to more easily generate the
1506 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001507static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 struct vfsmount *mnt,
1509 struct dentry *dentry,
1510 u32 av)
1511{
1512 struct inode *inode = dentry->d_inode;
1513 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001514
Eric Paris828dfe12008-04-17 13:17:49 -04001515 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001516 ad.u.fs.path.mnt = mnt;
1517 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001518 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519}
1520
1521/* Check whether a task can use an open file descriptor to
1522 access an inode in a given way. Check access to the
1523 descriptor itself, and then use dentry_has_perm to
1524 check a particular permission to the file.
1525 Access to the descriptor is implicitly granted if it
1526 has the same SID as the process. If av is zero, then
1527 access to the file is not checked, e.g. for cases
1528 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001529static int file_has_perm(const struct cred *cred,
1530 struct file *file,
1531 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001534 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001536 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 int rc;
1538
1539 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001540 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
David Howells275bb412008-11-14 10:39:19 +11001542 if (sid != fsec->sid) {
1543 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 SECCLASS_FD,
1545 FD__USE,
1546 &ad);
1547 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001548 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 }
1550
1551 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001552 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001554 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
David Howells88e67f32008-11-14 10:39:21 +11001556out:
1557 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558}
1559
1560/* Check whether a task can create a file. */
1561static int may_create(struct inode *dir,
1562 struct dentry *dentry,
1563 u16 tclass)
1564{
David Howells275bb412008-11-14 10:39:19 +11001565 const struct cred *cred = current_cred();
1566 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 struct inode_security_struct *dsec;
1568 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001569 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 struct avc_audit_data ad;
1571 int rc;
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 dsec = dir->i_security;
1574 sbsec = dir->i_sb->s_security;
1575
David Howells275bb412008-11-14 10:39:19 +11001576 sid = tsec->sid;
1577 newsid = tsec->create_sid;
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001580 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
David Howells275bb412008-11-14 10:39:19 +11001582 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 DIR__ADD_NAME | DIR__SEARCH,
1584 &ad);
1585 if (rc)
1586 return rc;
1587
David Howells275bb412008-11-14 10:39:19 +11001588 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
1589 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (rc)
1591 return rc;
1592 }
1593
David Howells275bb412008-11-14 10:39:19 +11001594 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 if (rc)
1596 return rc;
1597
1598 return avc_has_perm(newsid, sbsec->sid,
1599 SECCLASS_FILESYSTEM,
1600 FILESYSTEM__ASSOCIATE, &ad);
1601}
1602
Michael LeMay4eb582c2006-06-26 00:24:57 -07001603/* Check whether a task can create a key. */
1604static int may_create_key(u32 ksid,
1605 struct task_struct *ctx)
1606{
David Howells275bb412008-11-14 10:39:19 +11001607 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001608
David Howells275bb412008-11-14 10:39:19 +11001609 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001610}
1611
Eric Paris828dfe12008-04-17 13:17:49 -04001612#define MAY_LINK 0
1613#define MAY_UNLINK 1
1614#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
1616/* Check whether a task can link, unlink, or rmdir a file/directory. */
1617static int may_link(struct inode *dir,
1618 struct dentry *dentry,
1619 int kind)
1620
1621{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 struct inode_security_struct *dsec, *isec;
1623 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001624 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 u32 av;
1626 int rc;
1627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 dsec = dir->i_security;
1629 isec = dentry->d_inode->i_security;
1630
1631 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001632 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 av = DIR__SEARCH;
1635 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001636 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 if (rc)
1638 return rc;
1639
1640 switch (kind) {
1641 case MAY_LINK:
1642 av = FILE__LINK;
1643 break;
1644 case MAY_UNLINK:
1645 av = FILE__UNLINK;
1646 break;
1647 case MAY_RMDIR:
1648 av = DIR__RMDIR;
1649 break;
1650 default:
Eric Paris744ba352008-04-17 11:52:44 -04001651 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1652 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 return 0;
1654 }
1655
David Howells275bb412008-11-14 10:39:19 +11001656 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 return rc;
1658}
1659
1660static inline int may_rename(struct inode *old_dir,
1661 struct dentry *old_dentry,
1662 struct inode *new_dir,
1663 struct dentry *new_dentry)
1664{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1666 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001667 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 u32 av;
1669 int old_is_dir, new_is_dir;
1670 int rc;
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 old_dsec = old_dir->i_security;
1673 old_isec = old_dentry->d_inode->i_security;
1674 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1675 new_dsec = new_dir->i_security;
1676
1677 AVC_AUDIT_DATA_INIT(&ad, FS);
1678
Jan Blunck44707fd2008-02-14 19:38:33 -08001679 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001680 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1682 if (rc)
1683 return rc;
David Howells275bb412008-11-14 10:39:19 +11001684 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 old_isec->sclass, FILE__RENAME, &ad);
1686 if (rc)
1687 return rc;
1688 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001689 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 old_isec->sclass, DIR__REPARENT, &ad);
1691 if (rc)
1692 return rc;
1693 }
1694
Jan Blunck44707fd2008-02-14 19:38:33 -08001695 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 av = DIR__ADD_NAME | DIR__SEARCH;
1697 if (new_dentry->d_inode)
1698 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001699 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 if (rc)
1701 return rc;
1702 if (new_dentry->d_inode) {
1703 new_isec = new_dentry->d_inode->i_security;
1704 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001705 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 new_isec->sclass,
1707 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1708 if (rc)
1709 return rc;
1710 }
1711
1712 return 0;
1713}
1714
1715/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001716static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 struct super_block *sb,
1718 u32 perms,
1719 struct avc_audit_data *ad)
1720{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001722 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001725 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726}
1727
1728/* Convert a Linux mode and permission mask to an access vector. */
1729static inline u32 file_mask_to_av(int mode, int mask)
1730{
1731 u32 av = 0;
1732
1733 if ((mode & S_IFMT) != S_IFDIR) {
1734 if (mask & MAY_EXEC)
1735 av |= FILE__EXECUTE;
1736 if (mask & MAY_READ)
1737 av |= FILE__READ;
1738
1739 if (mask & MAY_APPEND)
1740 av |= FILE__APPEND;
1741 else if (mask & MAY_WRITE)
1742 av |= FILE__WRITE;
1743
1744 } else {
1745 if (mask & MAY_EXEC)
1746 av |= DIR__SEARCH;
1747 if (mask & MAY_WRITE)
1748 av |= DIR__WRITE;
1749 if (mask & MAY_READ)
1750 av |= DIR__READ;
1751 }
1752
1753 return av;
1754}
1755
1756/* Convert a Linux file to an access vector. */
1757static inline u32 file_to_av(struct file *file)
1758{
1759 u32 av = 0;
1760
1761 if (file->f_mode & FMODE_READ)
1762 av |= FILE__READ;
1763 if (file->f_mode & FMODE_WRITE) {
1764 if (file->f_flags & O_APPEND)
1765 av |= FILE__APPEND;
1766 else
1767 av |= FILE__WRITE;
1768 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001769 if (!av) {
1770 /*
1771 * Special file opened with flags 3 for ioctl-only use.
1772 */
1773 av = FILE__IOCTL;
1774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
1776 return av;
1777}
1778
Eric Paris8b6a5a32008-10-29 17:06:46 -04001779/*
1780 * Convert a file to an access vector and include the correct open
1781 * open permission.
1782 */
1783static inline u32 open_file_to_av(struct file *file)
1784{
1785 u32 av = file_to_av(file);
1786
1787 if (selinux_policycap_openperm) {
1788 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1789 /*
1790 * lnk files and socks do not really have an 'open'
1791 */
1792 if (S_ISREG(mode))
1793 av |= FILE__OPEN;
1794 else if (S_ISCHR(mode))
1795 av |= CHR_FILE__OPEN;
1796 else if (S_ISBLK(mode))
1797 av |= BLK_FILE__OPEN;
1798 else if (S_ISFIFO(mode))
1799 av |= FIFO_FILE__OPEN;
1800 else if (S_ISDIR(mode))
1801 av |= DIR__OPEN;
1802 else
1803 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1804 "unknown mode:%o\n", __func__, mode);
1805 }
1806 return av;
1807}
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809/* Hook functions begin here. */
1810
David Howells5cd9c582008-08-14 11:37:28 +01001811static int selinux_ptrace_may_access(struct task_struct *child,
1812 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 int rc;
1815
David Howells5cd9c582008-08-14 11:37:28 +01001816 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 if (rc)
1818 return rc;
1819
Stephen Smalley006ebb42008-05-19 08:32:49 -04001820 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001821 u32 sid = current_sid();
1822 u32 csid = task_sid(child);
1823 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001824 }
1825
David Howells3b11a1d2008-11-14 10:39:26 +11001826 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001827}
1828
1829static int selinux_ptrace_traceme(struct task_struct *parent)
1830{
1831 int rc;
1832
1833 rc = secondary_ops->ptrace_traceme(parent);
1834 if (rc)
1835 return rc;
1836
1837 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838}
1839
1840static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001841 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842{
1843 int error;
1844
David Howells3b11a1d2008-11-14 10:39:26 +11001845 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if (error)
1847 return error;
1848
1849 return secondary_ops->capget(target, effective, inheritable, permitted);
1850}
1851
David Howellsd84f4f92008-11-14 10:39:23 +11001852static int selinux_capset(struct cred *new, const struct cred *old,
1853 const kernel_cap_t *effective,
1854 const kernel_cap_t *inheritable,
1855 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856{
1857 int error;
1858
David Howellsd84f4f92008-11-14 10:39:23 +11001859 error = secondary_ops->capset(new, old,
1860 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 if (error)
1862 return error;
1863
David Howellsd84f4f92008-11-14 10:39:23 +11001864 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865}
1866
David Howells3699c532009-01-06 22:27:01 +00001867static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
1868 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869{
1870 int rc;
1871
David Howells3699c532009-01-06 22:27:01 +00001872 rc = secondary_ops->capable(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (rc)
1874 return rc;
1875
David Howells3699c532009-01-06 22:27:01 +00001876 return task_has_capability(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877}
1878
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001879static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1880{
1881 int buflen, rc;
1882 char *buffer, *path, *end;
1883
1884 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001885 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001886 if (!buffer)
1887 goto out;
1888
1889 buflen = PAGE_SIZE;
1890 end = buffer+buflen;
1891 *--end = '\0';
1892 buflen--;
1893 path = end-1;
1894 *path = '/';
1895 while (table) {
1896 const char *name = table->procname;
1897 size_t namelen = strlen(name);
1898 buflen -= namelen + 1;
1899 if (buflen < 0)
1900 goto out_free;
1901 end -= namelen;
1902 memcpy(end, name, namelen);
1903 *--end = '/';
1904 path = end;
1905 table = table->parent;
1906 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001907 buflen -= 4;
1908 if (buflen < 0)
1909 goto out_free;
1910 end -= 4;
1911 memcpy(end, "/sys", 4);
1912 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001913 rc = security_genfs_sid("proc", path, tclass, sid);
1914out_free:
1915 free_page((unsigned long)buffer);
1916out:
1917 return rc;
1918}
1919
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920static int selinux_sysctl(ctl_table *table, int op)
1921{
1922 int error = 0;
1923 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001924 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 int rc;
1926
1927 rc = secondary_ops->sysctl(table, op);
1928 if (rc)
1929 return rc;
1930
David Howells275bb412008-11-14 10:39:19 +11001931 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001933 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1934 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (rc) {
1936 /* Default to the well-defined sysctl SID. */
1937 tsid = SECINITSID_SYSCTL;
1938 }
1939
1940 /* The op values are "defined" in sysctl.c, thereby creating
1941 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001942 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11001943 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 SECCLASS_DIR, DIR__SEARCH, NULL);
1945 } else {
1946 av = 0;
1947 if (op & 004)
1948 av |= FILE__READ;
1949 if (op & 002)
1950 av |= FILE__WRITE;
1951 if (av)
David Howells275bb412008-11-14 10:39:19 +11001952 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
1956 return error;
1957}
1958
1959static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1960{
David Howells88e67f32008-11-14 10:39:21 +11001961 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 int rc = 0;
1963
1964 if (!sb)
1965 return 0;
1966
1967 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001968 case Q_SYNC:
1969 case Q_QUOTAON:
1970 case Q_QUOTAOFF:
1971 case Q_SETINFO:
1972 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001973 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001974 break;
1975 case Q_GETFMT:
1976 case Q_GETINFO:
1977 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001978 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001979 break;
1980 default:
1981 rc = 0; /* let the kernel handle invalid cmds */
1982 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 }
1984 return rc;
1985}
1986
1987static int selinux_quota_on(struct dentry *dentry)
1988{
David Howells88e67f32008-11-14 10:39:21 +11001989 const struct cred *cred = current_cred();
1990
1991 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992}
1993
1994static int selinux_syslog(int type)
1995{
1996 int rc;
1997
1998 rc = secondary_ops->syslog(type);
1999 if (rc)
2000 return rc;
2001
2002 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04002003 case 3: /* Read last kernel messages */
2004 case 10: /* Return size of the log buffer */
2005 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
2006 break;
2007 case 6: /* Disable logging to console */
2008 case 7: /* Enable logging to console */
2009 case 8: /* Set level of messages printed to console */
2010 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
2011 break;
2012 case 0: /* Close log */
2013 case 1: /* Open log */
2014 case 2: /* Read from log */
2015 case 4: /* Read/clear last kernel messages */
2016 case 5: /* Clear ring buffer */
2017 default:
2018 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2019 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
2021 return rc;
2022}
2023
2024/*
2025 * Check that a process has enough memory to allocate a new virtual
2026 * mapping. 0 means there is enough memory for the allocation to
2027 * succeed and -ENOMEM implies there is not.
2028 *
2029 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
2030 * if the capability is granted, but __vm_enough_memory requires 1 if
2031 * the capability is granted.
2032 *
2033 * Do not audit the selinux permission check, as this is applied to all
2034 * processes that allocate mappings.
2035 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002036static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037{
2038 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
David Howells3699c532009-01-06 22:27:01 +00002040 rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
2041 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 if (rc == 0)
2043 cap_sys_admin = 1;
2044
Alan Cox34b4e4a2007-08-22 14:01:28 -07002045 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046}
2047
2048/* binprm security operations */
2049
David Howellsa6f76f22008-11-14 10:39:24 +11002050static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051{
David Howellsa6f76f22008-11-14 10:39:24 +11002052 const struct task_security_struct *old_tsec;
2053 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 struct avc_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11002056 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 int rc;
2058
David Howellsa6f76f22008-11-14 10:39:24 +11002059 rc = secondary_ops->bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 if (rc)
2061 return rc;
2062
David Howellsa6f76f22008-11-14 10:39:24 +11002063 /* SELinux context only depends on initial program or script and not
2064 * the script interpreter */
2065 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 return 0;
2067
David Howellsa6f76f22008-11-14 10:39:24 +11002068 old_tsec = current_security();
2069 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 isec = inode->i_security;
2071
2072 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002073 new_tsec->sid = old_tsec->sid;
2074 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Michael LeMay28eba5b2006-06-27 02:53:42 -07002076 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002077 new_tsec->create_sid = 0;
2078 new_tsec->keycreate_sid = 0;
2079 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
David Howellsa6f76f22008-11-14 10:39:24 +11002081 if (old_tsec->exec_sid) {
2082 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002084 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 } else {
2086 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002087 rc = security_transition_sid(old_tsec->sid, isec->sid,
2088 SECCLASS_PROCESS, &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 if (rc)
2090 return rc;
2091 }
2092
2093 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002094 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Josef Sipek3d5ff522006-12-08 02:37:38 -08002096 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002097 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
David Howellsa6f76f22008-11-14 10:39:24 +11002099 if (new_tsec->sid == old_tsec->sid) {
2100 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2102 if (rc)
2103 return rc;
2104 } else {
2105 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002106 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2108 if (rc)
2109 return rc;
2110
David Howellsa6f76f22008-11-14 10:39:24 +11002111 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2113 if (rc)
2114 return rc;
2115
David Howellsa6f76f22008-11-14 10:39:24 +11002116 /* Check for shared state */
2117 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2118 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2119 SECCLASS_PROCESS, PROCESS__SHARE,
2120 NULL);
2121 if (rc)
2122 return -EPERM;
2123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
David Howellsa6f76f22008-11-14 10:39:24 +11002125 /* Make sure that anyone attempting to ptrace over a task that
2126 * changes its SID has the appropriate permit */
2127 if (bprm->unsafe &
2128 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2129 struct task_struct *tracer;
2130 struct task_security_struct *sec;
2131 u32 ptsid = 0;
2132
2133 rcu_read_lock();
2134 tracer = tracehook_tracer_task(current);
2135 if (likely(tracer != NULL)) {
2136 sec = __task_cred(tracer)->security;
2137 ptsid = sec->sid;
2138 }
2139 rcu_read_unlock();
2140
2141 if (ptsid != 0) {
2142 rc = avc_has_perm(ptsid, new_tsec->sid,
2143 SECCLASS_PROCESS,
2144 PROCESS__PTRACE, NULL);
2145 if (rc)
2146 return -EPERM;
2147 }
2148 }
2149
2150 /* Clear any possibly unsafe personality bits on exec: */
2151 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 }
2153
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 return 0;
2155}
2156
Eric Paris828dfe12008-04-17 13:17:49 -04002157static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158{
2159 return secondary_ops->bprm_check_security(bprm);
2160}
2161
Eric Paris828dfe12008-04-17 13:17:49 -04002162static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
David Howells275bb412008-11-14 10:39:19 +11002164 const struct cred *cred = current_cred();
2165 const struct task_security_struct *tsec = cred->security;
2166 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 int atsecure = 0;
2168
David Howells275bb412008-11-14 10:39:19 +11002169 sid = tsec->sid;
2170 osid = tsec->osid;
2171
2172 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 /* Enable secure mode for SIDs transitions unless
2174 the noatsecure permission is granted between
2175 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002176 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002177 SECCLASS_PROCESS,
2178 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 }
2180
2181 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2182}
2183
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184extern struct vfsmount *selinuxfs_mount;
2185extern struct dentry *selinux_null;
2186
2187/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002188static inline void flush_unauthorized_files(const struct cred *cred,
2189 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190{
2191 struct avc_audit_data ad;
2192 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002193 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002194 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002196 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002198 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if (tty) {
2200 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002201 if (!list_empty(&tty->tty_files)) {
2202 struct inode *inode;
2203
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 /* Revalidate access to controlling tty.
2205 Use inode_has_perm on the tty inode directly rather
2206 than using file_has_perm, as this particular open
2207 file may belong to another process and we are only
2208 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002209 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2210 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002211 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002213 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 }
2215 }
2216 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002217 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002219 /* Reset controlling tty. */
2220 if (drop_tty)
2221 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
2223 /* Revalidate access to inherited open files. */
2224
Eric Paris828dfe12008-04-17 13:17:49 -04002225 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
2227 spin_lock(&files->file_lock);
2228 for (;;) {
2229 unsigned long set, i;
2230 int fd;
2231
2232 j++;
2233 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002234 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002235 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002237 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 if (!set)
2239 continue;
2240 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002241 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (set & 1) {
2243 file = fget(i);
2244 if (!file)
2245 continue;
David Howells88e67f32008-11-14 10:39:21 +11002246 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 file,
2248 file_to_av(file))) {
2249 sys_close(i);
2250 fd = get_unused_fd();
2251 if (fd != i) {
2252 if (fd >= 0)
2253 put_unused_fd(fd);
2254 fput(file);
2255 continue;
2256 }
2257 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002258 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 } else {
David Howells745ca242008-11-14 10:39:22 +11002260 devnull = dentry_open(
2261 dget(selinux_null),
2262 mntget(selinuxfs_mount),
2263 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002264 if (IS_ERR(devnull)) {
2265 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 put_unused_fd(fd);
2267 fput(file);
2268 continue;
2269 }
2270 }
2271 fd_install(fd, devnull);
2272 }
2273 fput(file);
2274 }
2275 }
2276 spin_lock(&files->file_lock);
2277
2278 }
2279 spin_unlock(&files->file_lock);
2280}
2281
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282/*
David Howellsa6f76f22008-11-14 10:39:24 +11002283 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 */
David Howellsa6f76f22008-11-14 10:39:24 +11002285static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
David Howellsa6f76f22008-11-14 10:39:24 +11002287 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 int rc, i;
2290
David Howellsa6f76f22008-11-14 10:39:24 +11002291 secondary_ops->bprm_committing_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
David Howellsa6f76f22008-11-14 10:39:24 +11002293 new_tsec = bprm->cred->security;
2294 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 return;
2296
2297 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002298 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
David Howellsa6f76f22008-11-14 10:39:24 +11002300 /* Always clear parent death signal on SID transitions. */
2301 current->pdeath_signal = 0;
2302
2303 /* Check whether the new SID can inherit resource limits from the old
2304 * SID. If not, reset all soft limits to the lower of the current
2305 * task's hard limit and the init task's soft limit.
2306 *
2307 * Note that the setting of hard limits (even to lower them) can be
2308 * controlled by the setrlimit check. The inclusion of the init task's
2309 * soft limit into the computation is to avoid resetting soft limits
2310 * higher than the default soft limit for cases where the default is
2311 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2312 */
2313 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2314 PROCESS__RLIMITINH, NULL);
2315 if (rc) {
2316 for (i = 0; i < RLIM_NLIMITS; i++) {
2317 rlim = current->signal->rlim + i;
2318 initrlim = init_task.signal->rlim + i;
2319 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2320 }
2321 update_rlimit_cpu(rlim->rlim_cur);
2322 }
2323}
2324
2325/*
2326 * Clean up the process immediately after the installation of new credentials
2327 * due to exec
2328 */
2329static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2330{
2331 const struct task_security_struct *tsec = current_security();
2332 struct itimerval itimer;
2333 struct sighand_struct *psig;
2334 u32 osid, sid;
2335 int rc, i;
2336 unsigned long flags;
2337
2338 secondary_ops->bprm_committed_creds(bprm);
2339
2340 osid = tsec->osid;
2341 sid = tsec->sid;
2342
2343 if (sid == osid)
2344 return;
2345
2346 /* Check whether the new SID can inherit signal state from the old SID.
2347 * If not, clear itimers to avoid subsequent signal generation and
2348 * flush and unblock signals.
2349 *
2350 * This must occur _after_ the task SID has been updated so that any
2351 * kill done after the flush will be checked against the new SID.
2352 */
2353 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 if (rc) {
2355 memset(&itimer, 0, sizeof itimer);
2356 for (i = 0; i < 3; i++)
2357 do_setitimer(i, &itimer, NULL);
2358 flush_signals(current);
2359 spin_lock_irq(&current->sighand->siglock);
2360 flush_signal_handlers(current, 1);
2361 sigemptyset(&current->blocked);
2362 recalc_sigpending();
2363 spin_unlock_irq(&current->sighand->siglock);
2364 }
2365
David Howellsa6f76f22008-11-14 10:39:24 +11002366 /* Wake up the parent if it is waiting so that it can recheck
2367 * wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002368 read_lock_irq(&tasklist_lock);
2369 psig = current->parent->sighand;
2370 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002372 spin_unlock_irqrestore(&psig->siglock, flags);
2373 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374}
2375
2376/* superblock security operations */
2377
2378static int selinux_sb_alloc_security(struct super_block *sb)
2379{
2380 return superblock_alloc_security(sb);
2381}
2382
2383static void selinux_sb_free_security(struct super_block *sb)
2384{
2385 superblock_free_security(sb);
2386}
2387
2388static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2389{
2390 if (plen > olen)
2391 return 0;
2392
2393 return !memcmp(prefix, option, plen);
2394}
2395
2396static inline int selinux_option(char *option, int len)
2397{
Eric Paris832cbd92008-04-01 13:24:09 -04002398 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2399 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2400 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2401 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402}
2403
2404static inline void take_option(char **to, char *from, int *first, int len)
2405{
2406 if (!*first) {
2407 **to = ',';
2408 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002409 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 *first = 0;
2411 memcpy(*to, from, len);
2412 *to += len;
2413}
2414
Eric Paris828dfe12008-04-17 13:17:49 -04002415static inline void take_selinux_option(char **to, char *from, int *first,
2416 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002417{
2418 int current_size = 0;
2419
2420 if (!*first) {
2421 **to = '|';
2422 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002423 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002424 *first = 0;
2425
2426 while (current_size < len) {
2427 if (*from != '"') {
2428 **to = *from;
2429 *to += 1;
2430 }
2431 from += 1;
2432 current_size += 1;
2433 }
2434}
2435
Eric Parise0007522008-03-05 10:31:54 -05002436static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437{
2438 int fnosec, fsec, rc = 0;
2439 char *in_save, *in_curr, *in_end;
2440 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002441 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
2443 in_curr = orig;
2444 sec_curr = copy;
2445
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2447 if (!nosec) {
2448 rc = -ENOMEM;
2449 goto out;
2450 }
2451
2452 nosec_save = nosec;
2453 fnosec = fsec = 1;
2454 in_save = in_end = orig;
2455
2456 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002457 if (*in_end == '"')
2458 open_quote = !open_quote;
2459 if ((*in_end == ',' && open_quote == 0) ||
2460 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 int len = in_end - in_curr;
2462
2463 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002464 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 else
2466 take_option(&nosec, in_curr, &fnosec, len);
2467
2468 in_curr = in_end + 1;
2469 }
2470 } while (*in_end++);
2471
Eric Paris6931dfc2005-06-30 02:58:51 -07002472 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002473 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474out:
2475 return rc;
2476}
2477
James Morris12204e22008-12-19 10:44:42 +11002478static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479{
David Howells88e67f32008-11-14 10:39:21 +11002480 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 struct avc_audit_data ad;
2482 int rc;
2483
2484 rc = superblock_doinit(sb, data);
2485 if (rc)
2486 return rc;
2487
James Morris74192242008-12-19 11:41:10 +11002488 /* Allow all mounts performed by the kernel */
2489 if (flags & MS_KERNMOUNT)
2490 return 0;
2491
Eric Paris828dfe12008-04-17 13:17:49 -04002492 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002493 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002494 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495}
2496
David Howells726c3342006-06-23 02:02:58 -07002497static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498{
David Howells88e67f32008-11-14 10:39:21 +11002499 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 struct avc_audit_data ad;
2501
Eric Paris828dfe12008-04-17 13:17:49 -04002502 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002503 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002504 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505}
2506
Eric Paris828dfe12008-04-17 13:17:49 -04002507static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002508 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002509 char *type,
2510 unsigned long flags,
2511 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512{
David Howells88e67f32008-11-14 10:39:21 +11002513 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 int rc;
2515
Al Virob5266eb2008-03-22 17:48:24 -04002516 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 if (rc)
2518 return rc;
2519
2520 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002521 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002522 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 else
David Howells88e67f32008-11-14 10:39:21 +11002524 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002525 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526}
2527
2528static int selinux_umount(struct vfsmount *mnt, int flags)
2529{
David Howells88e67f32008-11-14 10:39:21 +11002530 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 int rc;
2532
2533 rc = secondary_ops->sb_umount(mnt, flags);
2534 if (rc)
2535 return rc;
2536
David Howells88e67f32008-11-14 10:39:21 +11002537 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002538 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539}
2540
2541/* inode security operations */
2542
2543static int selinux_inode_alloc_security(struct inode *inode)
2544{
2545 return inode_alloc_security(inode);
2546}
2547
2548static void selinux_inode_free_security(struct inode *inode)
2549{
2550 inode_free_security(inode);
2551}
2552
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002553static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2554 char **name, void **value,
2555 size_t *len)
2556{
David Howells275bb412008-11-14 10:39:19 +11002557 const struct cred *cred = current_cred();
2558 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002559 struct inode_security_struct *dsec;
2560 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002561 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002562 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002563 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002564
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002565 dsec = dir->i_security;
2566 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002567
David Howells275bb412008-11-14 10:39:19 +11002568 sid = tsec->sid;
2569 newsid = tsec->create_sid;
2570
2571 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
2572 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002573 inode_mode_to_security_class(inode->i_mode),
2574 &newsid);
2575 if (rc) {
2576 printk(KERN_WARNING "%s: "
2577 "security_transition_sid failed, rc=%d (dev=%s "
2578 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002579 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002580 -rc, inode->i_sb->s_id, inode->i_ino);
2581 return rc;
2582 }
2583 }
2584
Eric Paris296fddf2006-09-25 23:32:00 -07002585 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002586 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002587 struct inode_security_struct *isec = inode->i_security;
2588 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2589 isec->sid = newsid;
2590 isec->initialized = 1;
2591 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002592
Stephen Smalley8aad3872006-03-22 00:09:13 -08002593 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002594 return -EOPNOTSUPP;
2595
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002596 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002597 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002598 if (!namep)
2599 return -ENOMEM;
2600 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002601 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002602
2603 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002604 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002605 if (rc) {
2606 kfree(namep);
2607 return rc;
2608 }
2609 *value = context;
2610 *len = clen;
2611 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002612
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002613 return 0;
2614}
2615
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2617{
2618 return may_create(dir, dentry, SECCLASS_FILE);
2619}
2620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2622{
2623 int rc;
2624
Eric Paris828dfe12008-04-17 13:17:49 -04002625 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 if (rc)
2627 return rc;
2628 return may_link(dir, old_dentry, MAY_LINK);
2629}
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2632{
2633 int rc;
2634
2635 rc = secondary_ops->inode_unlink(dir, dentry);
2636 if (rc)
2637 return rc;
2638 return may_link(dir, dentry, MAY_UNLINK);
2639}
2640
2641static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2642{
2643 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2644}
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2647{
2648 return may_create(dir, dentry, SECCLASS_DIR);
2649}
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2652{
2653 return may_link(dir, dentry, MAY_RMDIR);
2654}
2655
2656static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2657{
2658 int rc;
2659
2660 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2661 if (rc)
2662 return rc;
2663
2664 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2665}
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002668 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
2670 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2671}
2672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673static int selinux_inode_readlink(struct dentry *dentry)
2674{
David Howells88e67f32008-11-14 10:39:21 +11002675 const struct cred *cred = current_cred();
2676
2677 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678}
2679
2680static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2681{
David Howells88e67f32008-11-14 10:39:21 +11002682 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 int rc;
2684
Eric Paris828dfe12008-04-17 13:17:49 -04002685 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 if (rc)
2687 return rc;
David Howells88e67f32008-11-14 10:39:21 +11002688 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689}
2690
Al Virob77b0642008-07-17 09:37:02 -04002691static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692{
David Howells88e67f32008-11-14 10:39:21 +11002693 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 int rc;
2695
Al Virob77b0642008-07-17 09:37:02 -04002696 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 if (rc)
2698 return rc;
2699
2700 if (!mask) {
2701 /* No permission to check. Existence test. */
2702 return 0;
2703 }
2704
David Howells88e67f32008-11-14 10:39:21 +11002705 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002706 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707}
2708
2709static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2710{
David Howells88e67f32008-11-14 10:39:21 +11002711 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 int rc;
2713
2714 rc = secondary_ops->inode_setattr(dentry, iattr);
2715 if (rc)
2716 return rc;
2717
2718 if (iattr->ia_valid & ATTR_FORCE)
2719 return 0;
2720
2721 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2722 ATTR_ATIME_SET | ATTR_MTIME_SET))
David Howells88e67f32008-11-14 10:39:21 +11002723 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
David Howells88e67f32008-11-14 10:39:21 +11002725 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726}
2727
2728static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2729{
David Howells88e67f32008-11-14 10:39:21 +11002730 const struct cred *cred = current_cred();
2731
2732 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733}
2734
David Howells8f0cfa52008-04-29 00:59:41 -07002735static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002736{
David Howells88e67f32008-11-14 10:39:21 +11002737 const struct cred *cred = current_cred();
2738
Serge E. Hallynb5376772007-10-16 23:31:36 -07002739 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2740 sizeof XATTR_SECURITY_PREFIX - 1)) {
2741 if (!strcmp(name, XATTR_NAME_CAPS)) {
2742 if (!capable(CAP_SETFCAP))
2743 return -EPERM;
2744 } else if (!capable(CAP_SYS_ADMIN)) {
2745 /* A different attribute in the security namespace.
2746 Restrict to administrator. */
2747 return -EPERM;
2748 }
2749 }
2750
2751 /* Not an attribute we recognize, so just check the
2752 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002753 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002754}
2755
David Howells8f0cfa52008-04-29 00:59:41 -07002756static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2757 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 struct inode *inode = dentry->d_inode;
2760 struct inode_security_struct *isec = inode->i_security;
2761 struct superblock_security_struct *sbsec;
2762 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002763 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 int rc = 0;
2765
Serge E. Hallynb5376772007-10-16 23:31:36 -07002766 if (strcmp(name, XATTR_NAME_SELINUX))
2767 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
2769 sbsec = inode->i_sb->s_security;
2770 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2771 return -EOPNOTSUPP;
2772
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302773 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return -EPERM;
2775
Eric Paris828dfe12008-04-17 13:17:49 -04002776 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002777 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
David Howells275bb412008-11-14 10:39:19 +11002779 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 FILE__RELABELFROM, &ad);
2781 if (rc)
2782 return rc;
2783
2784 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002785 if (rc == -EINVAL) {
2786 if (!capable(CAP_MAC_ADMIN))
2787 return rc;
2788 rc = security_context_to_sid_force(value, size, &newsid);
2789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 if (rc)
2791 return rc;
2792
David Howells275bb412008-11-14 10:39:19 +11002793 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 FILE__RELABELTO, &ad);
2795 if (rc)
2796 return rc;
2797
David Howells275bb412008-11-14 10:39:19 +11002798 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002799 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 if (rc)
2801 return rc;
2802
2803 return avc_has_perm(newsid,
2804 sbsec->sid,
2805 SECCLASS_FILESYSTEM,
2806 FILESYSTEM__ASSOCIATE,
2807 &ad);
2808}
2809
David Howells8f0cfa52008-04-29 00:59:41 -07002810static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002811 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002812 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813{
2814 struct inode *inode = dentry->d_inode;
2815 struct inode_security_struct *isec = inode->i_security;
2816 u32 newsid;
2817 int rc;
2818
2819 if (strcmp(name, XATTR_NAME_SELINUX)) {
2820 /* Not an attribute we recognize, so nothing to do. */
2821 return;
2822 }
2823
Stephen Smalley12b29f32008-05-07 13:03:20 -04002824 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002826 printk(KERN_ERR "SELinux: unable to map context to SID"
2827 "for (%s, %lu), rc=%d\n",
2828 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 return;
2830 }
2831
2832 isec->sid = newsid;
2833 return;
2834}
2835
David Howells8f0cfa52008-04-29 00:59:41 -07002836static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837{
David Howells88e67f32008-11-14 10:39:21 +11002838 const struct cred *cred = current_cred();
2839
2840 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841}
2842
Eric Paris828dfe12008-04-17 13:17:49 -04002843static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844{
David Howells88e67f32008-11-14 10:39:21 +11002845 const struct cred *cred = current_cred();
2846
2847 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848}
2849
David Howells8f0cfa52008-04-29 00:59:41 -07002850static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002852 if (strcmp(name, XATTR_NAME_SELINUX))
2853 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854
2855 /* No one is allowed to remove a SELinux security label.
2856 You can change the label, but all data must be labeled. */
2857 return -EACCES;
2858}
2859
James Morrisd381d8a2005-10-30 14:59:22 -08002860/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002861 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002862 *
2863 * Permission check is handled by selinux_inode_getxattr hook.
2864 */
David P. Quigley42492592008-02-04 22:29:39 -08002865static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866{
David P. Quigley42492592008-02-04 22:29:39 -08002867 u32 size;
2868 int error;
2869 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002872 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2873 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002875 /*
2876 * If the caller has CAP_MAC_ADMIN, then get the raw context
2877 * value even if it is not defined by current policy; otherwise,
2878 * use the in-core value under current policy.
2879 * Use the non-auditing forms of the permission checks since
2880 * getxattr may be called by unprivileged processes commonly
2881 * and lack of permission just means that we fall back to the
2882 * in-core context value, not a denial.
2883 */
David Howells3699c532009-01-06 22:27:01 +00002884 error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
2885 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002886 if (!error)
2887 error = security_sid_to_context_force(isec->sid, &context,
2888 &size);
2889 else
2890 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002891 if (error)
2892 return error;
2893 error = size;
2894 if (alloc) {
2895 *buffer = context;
2896 goto out_nofree;
2897 }
2898 kfree(context);
2899out_nofree:
2900 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901}
2902
2903static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002904 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905{
2906 struct inode_security_struct *isec = inode->i_security;
2907 u32 newsid;
2908 int rc;
2909
2910 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2911 return -EOPNOTSUPP;
2912
2913 if (!value || !size)
2914 return -EACCES;
2915
Eric Paris828dfe12008-04-17 13:17:49 -04002916 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 if (rc)
2918 return rc;
2919
2920 isec->sid = newsid;
2921 return 0;
2922}
2923
2924static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2925{
2926 const int len = sizeof(XATTR_NAME_SELINUX);
2927 if (buffer && len <= buffer_size)
2928 memcpy(buffer, XATTR_NAME_SELINUX, len);
2929 return len;
2930}
2931
Serge E. Hallynb5376772007-10-16 23:31:36 -07002932static int selinux_inode_need_killpriv(struct dentry *dentry)
2933{
2934 return secondary_ops->inode_need_killpriv(dentry);
2935}
2936
2937static int selinux_inode_killpriv(struct dentry *dentry)
2938{
2939 return secondary_ops->inode_killpriv(dentry);
2940}
2941
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002942static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2943{
2944 struct inode_security_struct *isec = inode->i_security;
2945 *secid = isec->sid;
2946}
2947
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948/* file security operations */
2949
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002950static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951{
David Howells88e67f32008-11-14 10:39:21 +11002952 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002953 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002954 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
2956 if (!mask) {
2957 /* No permission to check. Existence test. */
2958 return 0;
2959 }
2960
2961 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2962 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2963 mask |= MAY_APPEND;
2964
David Howells88e67f32008-11-14 10:39:21 +11002965 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002966 file_mask_to_av(inode->i_mode, mask));
2967 if (rc)
2968 return rc;
2969
2970 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971}
2972
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002973static int selinux_file_permission(struct file *file, int mask)
2974{
2975 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002976 struct file_security_struct *fsec = file->f_security;
2977 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11002978 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002979
2980 if (!mask) {
2981 /* No permission to check. Existence test. */
2982 return 0;
2983 }
2984
David Howells275bb412008-11-14 10:39:19 +11002985 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002986 && fsec->pseqno == avc_policy_seqno())
2987 return selinux_netlbl_inode_permission(inode, mask);
2988
2989 return selinux_revalidate_file_permission(file, mask);
2990}
2991
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992static int selinux_file_alloc_security(struct file *file)
2993{
2994 return file_alloc_security(file);
2995}
2996
2997static void selinux_file_free_security(struct file *file)
2998{
2999 file_free_security(file);
3000}
3001
3002static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3003 unsigned long arg)
3004{
David Howells88e67f32008-11-14 10:39:21 +11003005 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04003006 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
Stephen Smalley242631c2008-06-05 09:21:28 -04003008 if (_IOC_DIR(cmd) & _IOC_WRITE)
3009 av |= FILE__WRITE;
3010 if (_IOC_DIR(cmd) & _IOC_READ)
3011 av |= FILE__READ;
3012 if (!av)
3013 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
David Howells88e67f32008-11-14 10:39:21 +11003015 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016}
3017
3018static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3019{
David Howells88e67f32008-11-14 10:39:21 +11003020 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003021 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003022
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023#ifndef CONFIG_PPC32
3024 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3025 /*
3026 * We are making executable an anonymous mapping or a
3027 * private file mapping that will also be writable.
3028 * This has an additional check.
3029 */
David Howellsd84f4f92008-11-14 10:39:23 +11003030 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003032 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 }
3034#endif
3035
3036 if (file) {
3037 /* read access is always possible with a mapping */
3038 u32 av = FILE__READ;
3039
3040 /* write access only matters if the mapping is shared */
3041 if (shared && (prot & PROT_WRITE))
3042 av |= FILE__WRITE;
3043
3044 if (prot & PROT_EXEC)
3045 av |= FILE__EXECUTE;
3046
David Howells88e67f32008-11-14 10:39:21 +11003047 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 }
David Howellsd84f4f92008-11-14 10:39:23 +11003049
3050error:
3051 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052}
3053
3054static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003055 unsigned long prot, unsigned long flags,
3056 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057{
Eric Parised032182007-06-28 15:55:21 -04003058 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003059 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
Eric Parised032182007-06-28 15:55:21 -04003061 if (addr < mmap_min_addr)
3062 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3063 MEMPROTECT__MMAP_ZERO, NULL);
3064 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 return rc;
3066
3067 if (selinux_checkreqprot)
3068 prot = reqprot;
3069
3070 return file_map_prot_check(file, prot,
3071 (flags & MAP_TYPE) == MAP_SHARED);
3072}
3073
3074static int selinux_file_mprotect(struct vm_area_struct *vma,
3075 unsigned long reqprot,
3076 unsigned long prot)
3077{
David Howells88e67f32008-11-14 10:39:21 +11003078 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 int rc;
3080
3081 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3082 if (rc)
3083 return rc;
3084
3085 if (selinux_checkreqprot)
3086 prot = reqprot;
3087
3088#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003089 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3090 rc = 0;
3091 if (vma->vm_start >= vma->vm_mm->start_brk &&
3092 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003093 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003094 } else if (!vma->vm_file &&
3095 vma->vm_start <= vma->vm_mm->start_stack &&
3096 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003097 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003098 } else if (vma->vm_file && vma->anon_vma) {
3099 /*
3100 * We are making executable a file mapping that has
3101 * had some COW done. Since pages might have been
3102 * written, check ability to execute the possibly
3103 * modified content. This typically should only
3104 * occur for text relocations.
3105 */
David Howellsd84f4f92008-11-14 10:39:23 +11003106 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003107 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003108 if (rc)
3109 return rc;
3110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111#endif
3112
3113 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3114}
3115
3116static int selinux_file_lock(struct file *file, unsigned int cmd)
3117{
David Howells88e67f32008-11-14 10:39:21 +11003118 const struct cred *cred = current_cred();
3119
3120 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121}
3122
3123static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3124 unsigned long arg)
3125{
David Howells88e67f32008-11-14 10:39:21 +11003126 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 int err = 0;
3128
3129 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003130 case F_SETFL:
3131 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3132 err = -EINVAL;
3133 break;
3134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
Eric Paris828dfe12008-04-17 13:17:49 -04003136 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003137 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003139 }
3140 /* fall through */
3141 case F_SETOWN:
3142 case F_SETSIG:
3143 case F_GETFL:
3144 case F_GETOWN:
3145 case F_GETSIG:
3146 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003147 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003148 break;
3149 case F_GETLK:
3150 case F_SETLK:
3151 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003153 case F_GETLK64:
3154 case F_SETLK64:
3155 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003157 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3158 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003160 }
David Howells88e67f32008-11-14 10:39:21 +11003161 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003162 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 }
3164
3165 return err;
3166}
3167
3168static int selinux_file_set_fowner(struct file *file)
3169{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 struct file_security_struct *fsec;
3171
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003173 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
3175 return 0;
3176}
3177
3178static int selinux_file_send_sigiotask(struct task_struct *tsk,
3179 struct fown_struct *fown, int signum)
3180{
Eric Paris828dfe12008-04-17 13:17:49 -04003181 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003182 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 struct file_security_struct *fsec;
3185
3186 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003187 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 fsec = file->f_security;
3190
3191 if (!signum)
3192 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3193 else
3194 perm = signal_to_av(signum);
3195
David Howells275bb412008-11-14 10:39:19 +11003196 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 SECCLASS_PROCESS, perm, NULL);
3198}
3199
3200static int selinux_file_receive(struct file *file)
3201{
David Howells88e67f32008-11-14 10:39:21 +11003202 const struct cred *cred = current_cred();
3203
3204 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205}
3206
David Howells745ca242008-11-14 10:39:22 +11003207static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003208{
3209 struct file_security_struct *fsec;
3210 struct inode *inode;
3211 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003212
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003213 inode = file->f_path.dentry->d_inode;
3214 fsec = file->f_security;
3215 isec = inode->i_security;
3216 /*
3217 * Save inode label and policy sequence number
3218 * at open-time so that selinux_file_permission
3219 * can determine whether revalidation is necessary.
3220 * Task label is already saved in the file security
3221 * struct as its SID.
3222 */
3223 fsec->isid = isec->sid;
3224 fsec->pseqno = avc_policy_seqno();
3225 /*
3226 * Since the inode label or policy seqno may have changed
3227 * between the selinux_inode_permission check and the saving
3228 * of state above, recheck that access is still permitted.
3229 * Otherwise, access might never be revalidated against the
3230 * new inode label or new policy.
3231 * This check is not redundant - do not remove.
3232 */
David Howells88e67f32008-11-14 10:39:21 +11003233 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003234}
3235
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236/* task security operations */
3237
3238static int selinux_task_create(unsigned long clone_flags)
3239{
3240 int rc;
3241
3242 rc = secondary_ops->task_create(clone_flags);
3243 if (rc)
3244 return rc;
3245
David Howells3b11a1d2008-11-14 10:39:26 +11003246 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247}
3248
David Howellsf1752ee2008-11-14 10:39:17 +11003249/*
3250 * detach and free the LSM part of a set of credentials
3251 */
3252static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253{
David Howellsf1752ee2008-11-14 10:39:17 +11003254 struct task_security_struct *tsec = cred->security;
3255 cred->security = NULL;
3256 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257}
3258
David Howellsd84f4f92008-11-14 10:39:23 +11003259/*
3260 * prepare a new set of credentials for modification
3261 */
3262static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3263 gfp_t gfp)
3264{
3265 const struct task_security_struct *old_tsec;
3266 struct task_security_struct *tsec;
3267
3268 old_tsec = old->security;
3269
3270 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3271 if (!tsec)
3272 return -ENOMEM;
3273
3274 new->security = tsec;
3275 return 0;
3276}
3277
3278/*
3279 * commit new credentials
3280 */
3281static void selinux_cred_commit(struct cred *new, const struct cred *old)
3282{
3283 secondary_ops->cred_commit(new, old);
3284}
3285
David Howells3a3b7ce2008-11-14 10:39:28 +11003286/*
3287 * set the security data for a kernel service
3288 * - all the creation contexts are set to unlabelled
3289 */
3290static int selinux_kernel_act_as(struct cred *new, u32 secid)
3291{
3292 struct task_security_struct *tsec = new->security;
3293 u32 sid = current_sid();
3294 int ret;
3295
3296 ret = avc_has_perm(sid, secid,
3297 SECCLASS_KERNEL_SERVICE,
3298 KERNEL_SERVICE__USE_AS_OVERRIDE,
3299 NULL);
3300 if (ret == 0) {
3301 tsec->sid = secid;
3302 tsec->create_sid = 0;
3303 tsec->keycreate_sid = 0;
3304 tsec->sockcreate_sid = 0;
3305 }
3306 return ret;
3307}
3308
3309/*
3310 * set the file creation context in a security record to the same as the
3311 * objective context of the specified inode
3312 */
3313static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3314{
3315 struct inode_security_struct *isec = inode->i_security;
3316 struct task_security_struct *tsec = new->security;
3317 u32 sid = current_sid();
3318 int ret;
3319
3320 ret = avc_has_perm(sid, isec->sid,
3321 SECCLASS_KERNEL_SERVICE,
3322 KERNEL_SERVICE__CREATE_FILES_AS,
3323 NULL);
3324
3325 if (ret == 0)
3326 tsec->create_sid = isec->sid;
3327 return 0;
3328}
3329
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3331{
3332 /* Since setuid only affects the current process, and
3333 since the SELinux controls are not based on the Linux
3334 identity attributes, SELinux does not need to control
3335 this operation. However, SELinux does control the use
3336 of the CAP_SETUID and CAP_SETGID capabilities using the
3337 capable hook. */
3338 return 0;
3339}
3340
David Howellsd84f4f92008-11-14 10:39:23 +11003341static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3342 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343{
David Howellsd84f4f92008-11-14 10:39:23 +11003344 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345}
3346
3347static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3348{
3349 /* See the comment for setuid above. */
3350 return 0;
3351}
3352
3353static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3354{
David Howells3b11a1d2008-11-14 10:39:26 +11003355 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356}
3357
3358static int selinux_task_getpgid(struct task_struct *p)
3359{
David Howells3b11a1d2008-11-14 10:39:26 +11003360 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361}
3362
3363static int selinux_task_getsid(struct task_struct *p)
3364{
David Howells3b11a1d2008-11-14 10:39:26 +11003365 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366}
3367
David Quigleyf9008e42006-06-30 01:55:46 -07003368static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3369{
David Howells275bb412008-11-14 10:39:19 +11003370 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003371}
3372
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373static int selinux_task_setgroups(struct group_info *group_info)
3374{
3375 /* See the comment for setuid above. */
3376 return 0;
3377}
3378
3379static int selinux_task_setnice(struct task_struct *p, int nice)
3380{
3381 int rc;
3382
3383 rc = secondary_ops->task_setnice(p, nice);
3384 if (rc)
3385 return rc;
3386
David Howells3b11a1d2008-11-14 10:39:26 +11003387 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388}
3389
James Morris03e68062006-06-23 02:03:58 -07003390static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3391{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003392 int rc;
3393
3394 rc = secondary_ops->task_setioprio(p, ioprio);
3395 if (rc)
3396 return rc;
3397
David Howells3b11a1d2008-11-14 10:39:26 +11003398 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003399}
3400
David Quigleya1836a42006-06-30 01:55:49 -07003401static int selinux_task_getioprio(struct task_struct *p)
3402{
David Howells3b11a1d2008-11-14 10:39:26 +11003403 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003404}
3405
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3407{
3408 struct rlimit *old_rlim = current->signal->rlim + resource;
3409 int rc;
3410
3411 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3412 if (rc)
3413 return rc;
3414
3415 /* Control the ability to change the hard limit (whether
3416 lowering or raising it), so that the hard limit can
3417 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003418 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003420 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 return 0;
3423}
3424
3425static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3426{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003427 int rc;
3428
3429 rc = secondary_ops->task_setscheduler(p, policy, lp);
3430 if (rc)
3431 return rc;
3432
David Howells3b11a1d2008-11-14 10:39:26 +11003433 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434}
3435
3436static int selinux_task_getscheduler(struct task_struct *p)
3437{
David Howells3b11a1d2008-11-14 10:39:26 +11003438 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439}
3440
David Quigley35601542006-06-23 02:04:01 -07003441static int selinux_task_movememory(struct task_struct *p)
3442{
David Howells3b11a1d2008-11-14 10:39:26 +11003443 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003444}
3445
David Quigleyf9008e42006-06-30 01:55:46 -07003446static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3447 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
3449 u32 perm;
3450 int rc;
3451
David Quigleyf9008e42006-06-30 01:55:46 -07003452 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 if (rc)
3454 return rc;
3455
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 if (!sig)
3457 perm = PROCESS__SIGNULL; /* null signal; existence test */
3458 else
3459 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003460 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003461 rc = avc_has_perm(secid, task_sid(p),
3462 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003463 else
David Howells3b11a1d2008-11-14 10:39:26 +11003464 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003465 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466}
3467
3468static int selinux_task_prctl(int option,
3469 unsigned long arg2,
3470 unsigned long arg3,
3471 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003472 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473{
3474 /* The current prctl operations do not appear to require
3475 any SELinux controls since they merely observe or modify
3476 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003477 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478}
3479
3480static int selinux_task_wait(struct task_struct *p)
3481{
Eric Paris8a535142007-10-22 16:10:31 -04003482 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483}
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485static void selinux_task_to_inode(struct task_struct *p,
3486 struct inode *inode)
3487{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003489 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
David Howells275bb412008-11-14 10:39:19 +11003491 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493}
3494
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003496static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3497 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498{
3499 int offset, ihlen, ret = -EINVAL;
3500 struct iphdr _iph, *ih;
3501
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003502 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3504 if (ih == NULL)
3505 goto out;
3506
3507 ihlen = ih->ihl * 4;
3508 if (ihlen < sizeof(_iph))
3509 goto out;
3510
3511 ad->u.net.v4info.saddr = ih->saddr;
3512 ad->u.net.v4info.daddr = ih->daddr;
3513 ret = 0;
3514
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003515 if (proto)
3516 *proto = ih->protocol;
3517
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003519 case IPPROTO_TCP: {
3520 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
Eric Paris828dfe12008-04-17 13:17:49 -04003522 if (ntohs(ih->frag_off) & IP_OFFSET)
3523 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
3525 offset += ihlen;
3526 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3527 if (th == NULL)
3528 break;
3529
3530 ad->u.net.sport = th->source;
3531 ad->u.net.dport = th->dest;
3532 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
Eric Paris828dfe12008-04-17 13:17:49 -04003535 case IPPROTO_UDP: {
3536 struct udphdr _udph, *uh;
3537
3538 if (ntohs(ih->frag_off) & IP_OFFSET)
3539 break;
3540
3541 offset += ihlen;
3542 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3543 if (uh == NULL)
3544 break;
3545
3546 ad->u.net.sport = uh->source;
3547 ad->u.net.dport = uh->dest;
3548 break;
3549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
James Morris2ee92d42006-11-13 16:09:01 -08003551 case IPPROTO_DCCP: {
3552 struct dccp_hdr _dccph, *dh;
3553
3554 if (ntohs(ih->frag_off) & IP_OFFSET)
3555 break;
3556
3557 offset += ihlen;
3558 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3559 if (dh == NULL)
3560 break;
3561
3562 ad->u.net.sport = dh->dccph_sport;
3563 ad->u.net.dport = dh->dccph_dport;
3564 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003565 }
James Morris2ee92d42006-11-13 16:09:01 -08003566
Eric Paris828dfe12008-04-17 13:17:49 -04003567 default:
3568 break;
3569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570out:
3571 return ret;
3572}
3573
3574#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3575
3576/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003577static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3578 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579{
3580 u8 nexthdr;
3581 int ret = -EINVAL, offset;
3582 struct ipv6hdr _ipv6h, *ip6;
3583
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003584 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3586 if (ip6 == NULL)
3587 goto out;
3588
3589 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3590 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3591 ret = 0;
3592
3593 nexthdr = ip6->nexthdr;
3594 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003595 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 if (offset < 0)
3597 goto out;
3598
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003599 if (proto)
3600 *proto = nexthdr;
3601
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 switch (nexthdr) {
3603 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003604 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
3606 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3607 if (th == NULL)
3608 break;
3609
3610 ad->u.net.sport = th->source;
3611 ad->u.net.dport = th->dest;
3612 break;
3613 }
3614
3615 case IPPROTO_UDP: {
3616 struct udphdr _udph, *uh;
3617
3618 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3619 if (uh == NULL)
3620 break;
3621
3622 ad->u.net.sport = uh->source;
3623 ad->u.net.dport = uh->dest;
3624 break;
3625 }
3626
James Morris2ee92d42006-11-13 16:09:01 -08003627 case IPPROTO_DCCP: {
3628 struct dccp_hdr _dccph, *dh;
3629
3630 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3631 if (dh == NULL)
3632 break;
3633
3634 ad->u.net.sport = dh->dccph_sport;
3635 ad->u.net.dport = dh->dccph_dport;
3636 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003637 }
James Morris2ee92d42006-11-13 16:09:01 -08003638
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 /* includes fragments */
3640 default:
3641 break;
3642 }
3643out:
3644 return ret;
3645}
3646
3647#endif /* IPV6 */
3648
3649static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003650 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651{
David Howellscf9481e2008-07-27 21:31:07 +10003652 char *addrp;
3653 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654
3655 switch (ad->u.net.family) {
3656 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003657 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003658 if (ret)
3659 goto parse_error;
3660 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3661 &ad->u.net.v4info.daddr);
3662 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663
3664#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3665 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003666 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003667 if (ret)
3668 goto parse_error;
3669 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3670 &ad->u.net.v6info.daddr);
3671 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672#endif /* IPV6 */
3673 default:
David Howellscf9481e2008-07-27 21:31:07 +10003674 addrp = NULL;
3675 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
3677
David Howellscf9481e2008-07-27 21:31:07 +10003678parse_error:
3679 printk(KERN_WARNING
3680 "SELinux: failure in selinux_parse_skb(),"
3681 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003683
3684okay:
3685 if (_addrp)
3686 *_addrp = addrp;
3687 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688}
3689
Paul Moore4f6a9932007-03-01 14:35:22 -05003690/**
Paul Moore220deb92008-01-29 08:38:23 -05003691 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003692 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003693 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003694 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003695 *
3696 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003697 * Check the various different forms of network peer labeling and determine
3698 * the peer label/SID for the packet; most of the magic actually occurs in
3699 * the security server function security_net_peersid_cmp(). The function
3700 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3701 * or -EACCES if @sid is invalid due to inconsistencies with the different
3702 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003703 *
3704 */
Paul Moore220deb92008-01-29 08:38:23 -05003705static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003706{
Paul Moore71f1cb02008-01-29 08:51:16 -05003707 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003708 u32 xfrm_sid;
3709 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003710 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003711
3712 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003713 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003714
Paul Moore71f1cb02008-01-29 08:51:16 -05003715 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3716 if (unlikely(err)) {
3717 printk(KERN_WARNING
3718 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3719 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003720 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003721 }
Paul Moore220deb92008-01-29 08:38:23 -05003722
3723 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003724}
3725
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726/* socket security operations */
3727static int socket_has_perm(struct task_struct *task, struct socket *sock,
3728 u32 perms)
3729{
3730 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003732 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 int err = 0;
3734
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 isec = SOCK_INODE(sock)->i_security;
3736
3737 if (isec->sid == SECINITSID_KERNEL)
3738 goto out;
David Howells275bb412008-11-14 10:39:19 +11003739 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Eric Paris828dfe12008-04-17 13:17:49 -04003741 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003743 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
3745out:
3746 return err;
3747}
3748
3749static int selinux_socket_create(int family, int type,
3750 int protocol, int kern)
3751{
David Howells275bb412008-11-14 10:39:19 +11003752 const struct cred *cred = current_cred();
3753 const struct task_security_struct *tsec = cred->security;
3754 u32 sid, newsid;
3755 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
3758 if (kern)
3759 goto out;
3760
David Howells275bb412008-11-14 10:39:19 +11003761 sid = tsec->sid;
3762 newsid = tsec->sockcreate_sid ?: sid;
3763
3764 secclass = socket_type_to_security_class(family, type, protocol);
3765 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766
3767out:
3768 return err;
3769}
3770
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003771static int selinux_socket_post_create(struct socket *sock, int family,
3772 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773{
David Howells275bb412008-11-14 10:39:19 +11003774 const struct cred *cred = current_cred();
3775 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003777 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003778 u32 sid, newsid;
3779 int err = 0;
3780
3781 sid = tsec->sid;
3782 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
3784 isec = SOCK_INODE(sock)->i_security;
3785
David Howells275bb412008-11-14 10:39:19 +11003786 if (kern)
3787 isec->sid = SECINITSID_KERNEL;
3788 else if (newsid)
3789 isec->sid = newsid;
3790 else
3791 isec->sid = sid;
3792
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 isec->initialized = 1;
3795
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003796 if (sock->sk) {
3797 sksec = sock->sk->sk_security;
3798 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003799 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003800 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003801 }
3802
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003803 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804}
3805
3806/* Range of port numbers used to automatically bind.
3807 Need to determine whether we should perform a name_bind
3808 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809
3810static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3811{
3812 u16 family;
3813 int err;
3814
3815 err = socket_has_perm(current, sock, SOCKET__BIND);
3816 if (err)
3817 goto out;
3818
3819 /*
3820 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003821 * Multiple address binding for SCTP is not supported yet: we just
3822 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 */
3824 family = sock->sk->sk_family;
3825 if (family == PF_INET || family == PF_INET6) {
3826 char *addrp;
3827 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 struct avc_audit_data ad;
3829 struct sockaddr_in *addr4 = NULL;
3830 struct sockaddr_in6 *addr6 = NULL;
3831 unsigned short snum;
3832 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003833 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 isec = SOCK_INODE(sock)->i_security;
3836
3837 if (family == PF_INET) {
3838 addr4 = (struct sockaddr_in *)address;
3839 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 addrp = (char *)&addr4->sin_addr.s_addr;
3841 } else {
3842 addr6 = (struct sockaddr_in6 *)address;
3843 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 addrp = (char *)&addr6->sin6_addr.s6_addr;
3845 }
3846
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003847 if (snum) {
3848 int low, high;
3849
3850 inet_get_local_port_range(&low, &high);
3851
3852 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003853 err = sel_netport_sid(sk->sk_protocol,
3854 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003855 if (err)
3856 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003857 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003858 ad.u.net.sport = htons(snum);
3859 ad.u.net.family = family;
3860 err = avc_has_perm(isec->sid, sid,
3861 isec->sclass,
3862 SOCKET__NAME_BIND, &ad);
3863 if (err)
3864 goto out;
3865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 }
Eric Paris828dfe12008-04-17 13:17:49 -04003867
3868 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003869 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 node_perm = TCP_SOCKET__NODE_BIND;
3871 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003872
James Morris13402582005-09-30 14:24:34 -04003873 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 node_perm = UDP_SOCKET__NODE_BIND;
3875 break;
James Morris2ee92d42006-11-13 16:09:01 -08003876
3877 case SECCLASS_DCCP_SOCKET:
3878 node_perm = DCCP_SOCKET__NODE_BIND;
3879 break;
3880
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 default:
3882 node_perm = RAWIP_SOCKET__NODE_BIND;
3883 break;
3884 }
Eric Paris828dfe12008-04-17 13:17:49 -04003885
Paul Moore224dfbd2008-01-29 08:38:13 -05003886 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 if (err)
3888 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003889
3890 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 ad.u.net.sport = htons(snum);
3892 ad.u.net.family = family;
3893
3894 if (family == PF_INET)
3895 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3896 else
3897 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3898
3899 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003900 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 if (err)
3902 goto out;
3903 }
3904out:
3905 return err;
3906}
3907
3908static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3909{
Paul Moore014ab192008-10-10 10:16:33 -04003910 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 struct inode_security_struct *isec;
3912 int err;
3913
3914 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3915 if (err)
3916 return err;
3917
3918 /*
James Morris2ee92d42006-11-13 16:09:01 -08003919 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 */
3921 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003922 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3923 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 struct avc_audit_data ad;
3925 struct sockaddr_in *addr4 = NULL;
3926 struct sockaddr_in6 *addr6 = NULL;
3927 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003928 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929
3930 if (sk->sk_family == PF_INET) {
3931 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003932 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 return -EINVAL;
3934 snum = ntohs(addr4->sin_port);
3935 } else {
3936 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003937 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 return -EINVAL;
3939 snum = ntohs(addr6->sin6_port);
3940 }
3941
Paul Moore3e112172008-04-10 10:48:14 -04003942 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 if (err)
3944 goto out;
3945
James Morris2ee92d42006-11-13 16:09:01 -08003946 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3947 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3948
Eric Paris828dfe12008-04-17 13:17:49 -04003949 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 ad.u.net.dport = htons(snum);
3951 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003952 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 if (err)
3954 goto out;
3955 }
3956
Paul Moore014ab192008-10-10 10:16:33 -04003957 err = selinux_netlbl_socket_connect(sk, address);
3958
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959out:
3960 return err;
3961}
3962
3963static int selinux_socket_listen(struct socket *sock, int backlog)
3964{
3965 return socket_has_perm(current, sock, SOCKET__LISTEN);
3966}
3967
3968static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3969{
3970 int err;
3971 struct inode_security_struct *isec;
3972 struct inode_security_struct *newisec;
3973
3974 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3975 if (err)
3976 return err;
3977
3978 newisec = SOCK_INODE(newsock)->i_security;
3979
3980 isec = SOCK_INODE(sock)->i_security;
3981 newisec->sclass = isec->sclass;
3982 newisec->sid = isec->sid;
3983 newisec->initialized = 1;
3984
3985 return 0;
3986}
3987
3988static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003989 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003991 int rc;
3992
3993 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3994 if (rc)
3995 return rc;
3996
3997 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998}
3999
4000static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4001 int size, int flags)
4002{
4003 return socket_has_perm(current, sock, SOCKET__READ);
4004}
4005
4006static int selinux_socket_getsockname(struct socket *sock)
4007{
4008 return socket_has_perm(current, sock, SOCKET__GETATTR);
4009}
4010
4011static int selinux_socket_getpeername(struct socket *sock)
4012{
4013 return socket_has_perm(current, sock, SOCKET__GETATTR);
4014}
4015
Eric Paris828dfe12008-04-17 13:17:49 -04004016static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017{
Paul Mooref8687af2006-10-30 15:22:15 -08004018 int err;
4019
4020 err = socket_has_perm(current, sock, SOCKET__SETOPT);
4021 if (err)
4022 return err;
4023
4024 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025}
4026
4027static int selinux_socket_getsockopt(struct socket *sock, int level,
4028 int optname)
4029{
4030 return socket_has_perm(current, sock, SOCKET__GETOPT);
4031}
4032
4033static int selinux_socket_shutdown(struct socket *sock, int how)
4034{
4035 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
4036}
4037
4038static int selinux_socket_unix_stream_connect(struct socket *sock,
4039 struct socket *other,
4040 struct sock *newsk)
4041{
4042 struct sk_security_struct *ssec;
4043 struct inode_security_struct *isec;
4044 struct inode_security_struct *other_isec;
4045 struct avc_audit_data ad;
4046 int err;
4047
4048 err = secondary_ops->unix_stream_connect(sock, other, newsk);
4049 if (err)
4050 return err;
4051
4052 isec = SOCK_INODE(sock)->i_security;
4053 other_isec = SOCK_INODE(other)->i_security;
4054
Eric Paris828dfe12008-04-17 13:17:49 -04004055 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 ad.u.net.sk = other->sk;
4057
4058 err = avc_has_perm(isec->sid, other_isec->sid,
4059 isec->sclass,
4060 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4061 if (err)
4062 return err;
4063
4064 /* connecting socket */
4065 ssec = sock->sk->sk_security;
4066 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004067
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 /* server child socket */
4069 ssec = newsk->sk_security;
4070 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004071 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4072
4073 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074}
4075
4076static int selinux_socket_unix_may_send(struct socket *sock,
4077 struct socket *other)
4078{
4079 struct inode_security_struct *isec;
4080 struct inode_security_struct *other_isec;
4081 struct avc_audit_data ad;
4082 int err;
4083
4084 isec = SOCK_INODE(sock)->i_security;
4085 other_isec = SOCK_INODE(other)->i_security;
4086
Eric Paris828dfe12008-04-17 13:17:49 -04004087 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 ad.u.net.sk = other->sk;
4089
4090 err = avc_has_perm(isec->sid, other_isec->sid,
4091 isec->sclass, SOCKET__SENDTO, &ad);
4092 if (err)
4093 return err;
4094
4095 return 0;
4096}
4097
Paul Mooreeffad8d2008-01-29 08:49:27 -05004098static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4099 u32 peer_sid,
4100 struct avc_audit_data *ad)
4101{
4102 int err;
4103 u32 if_sid;
4104 u32 node_sid;
4105
4106 err = sel_netif_sid(ifindex, &if_sid);
4107 if (err)
4108 return err;
4109 err = avc_has_perm(peer_sid, if_sid,
4110 SECCLASS_NETIF, NETIF__INGRESS, ad);
4111 if (err)
4112 return err;
4113
4114 err = sel_netnode_sid(addrp, family, &node_sid);
4115 if (err)
4116 return err;
4117 return avc_has_perm(peer_sid, node_sid,
4118 SECCLASS_NODE, NODE__RECVFROM, ad);
4119}
4120
Paul Moore220deb92008-01-29 08:38:23 -05004121static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4122 struct sk_buff *skb,
4123 struct avc_audit_data *ad,
4124 u16 family,
4125 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126{
Paul Moore220deb92008-01-29 08:38:23 -05004127 int err;
4128 struct sk_security_struct *sksec = sk->sk_security;
4129 u16 sk_class;
4130 u32 netif_perm, node_perm, recv_perm;
4131 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004132
Paul Moore220deb92008-01-29 08:38:23 -05004133 sk_sid = sksec->sid;
4134 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135
Paul Moore220deb92008-01-29 08:38:23 -05004136 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 case SECCLASS_UDP_SOCKET:
4138 netif_perm = NETIF__UDP_RECV;
4139 node_perm = NODE__UDP_RECV;
4140 recv_perm = UDP_SOCKET__RECV_MSG;
4141 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 case SECCLASS_TCP_SOCKET:
4143 netif_perm = NETIF__TCP_RECV;
4144 node_perm = NODE__TCP_RECV;
4145 recv_perm = TCP_SOCKET__RECV_MSG;
4146 break;
James Morris2ee92d42006-11-13 16:09:01 -08004147 case SECCLASS_DCCP_SOCKET:
4148 netif_perm = NETIF__DCCP_RECV;
4149 node_perm = NODE__DCCP_RECV;
4150 recv_perm = DCCP_SOCKET__RECV_MSG;
4151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 default:
4153 netif_perm = NETIF__RAWIP_RECV;
4154 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004155 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 break;
4157 }
4158
Paul Moore220deb92008-01-29 08:38:23 -05004159 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004161 return err;
4162 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4163 if (err)
4164 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004165
Paul Moore224dfbd2008-01-29 08:38:13 -05004166 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004168 return err;
4169 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004171 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
Paul Moore220deb92008-01-29 08:38:23 -05004173 if (!recv_perm)
4174 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004175 err = sel_netport_sid(sk->sk_protocol,
4176 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004177 if (unlikely(err)) {
4178 printk(KERN_WARNING
4179 "SELinux: failure in"
4180 " selinux_sock_rcv_skb_iptables_compat(),"
4181 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004182 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004183 }
Paul Moore220deb92008-01-29 08:38:23 -05004184 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4185}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
Paul Moore220deb92008-01-29 08:38:23 -05004187static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004188 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004189{
Paul Moore277d3422008-12-31 12:54:11 -05004190 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004191 struct sk_security_struct *sksec = sk->sk_security;
4192 u32 peer_sid;
4193 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004194 struct avc_audit_data ad;
4195 char *addrp;
4196
4197 AVC_AUDIT_DATA_INIT(&ad, NET);
4198 ad.u.net.netif = skb->iif;
4199 ad.u.net.family = family;
4200 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4201 if (err)
4202 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004203
4204 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004205 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004206 family, addrp);
Paul Moore277d3422008-12-31 12:54:11 -05004207 else if (selinux_secmark_enabled())
Paul Moore220deb92008-01-29 08:38:23 -05004208 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004209 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004210 if (err)
4211 return err;
4212
4213 if (selinux_policycap_netpeer) {
4214 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004216 return err;
4217 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004218 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004219 if (err)
4220 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004221 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004222 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004223 if (err)
4224 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004225 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004227
James Morris4e5ab4c2006-06-09 00:33:33 -07004228 return err;
4229}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004230
James Morris4e5ab4c2006-06-09 00:33:33 -07004231static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4232{
Paul Moore220deb92008-01-29 08:38:23 -05004233 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004234 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004235 u16 family = sk->sk_family;
4236 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004237 struct avc_audit_data ad;
4238 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004239 u8 secmark_active;
4240 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004241
James Morris4e5ab4c2006-06-09 00:33:33 -07004242 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004243 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004244
4245 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004246 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004247 family = PF_INET;
4248
Paul Moored8395c82008-10-10 10:16:30 -04004249 /* If any sort of compatibility mode is enabled then handoff processing
4250 * to the selinux_sock_rcv_skb_compat() function to deal with the
4251 * special handling. We do this in an attempt to keep this function
4252 * as fast and as clean as possible. */
4253 if (selinux_compat_net || !selinux_policycap_netpeer)
4254 return selinux_sock_rcv_skb_compat(sk, skb, family);
4255
4256 secmark_active = selinux_secmark_enabled();
4257 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4258 if (!secmark_active && !peerlbl_active)
4259 return 0;
4260
James Morris4e5ab4c2006-06-09 00:33:33 -07004261 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004262 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004263 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004264 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004265 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004266 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004267
Paul Moored8395c82008-10-10 10:16:30 -04004268 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004269 u32 peer_sid;
4270
4271 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4272 if (err)
4273 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004274 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4275 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004276 if (err) {
4277 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004278 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004279 }
Paul Moored621d352008-01-29 08:43:36 -05004280 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4281 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004282 if (err)
4283 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004284 }
4285
Paul Moored8395c82008-10-10 10:16:30 -04004286 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004287 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4288 PACKET__RECV, &ad);
4289 if (err)
4290 return err;
4291 }
4292
Paul Moored621d352008-01-29 08:43:36 -05004293 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294}
4295
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004296static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4297 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298{
4299 int err = 0;
4300 char *scontext;
4301 u32 scontext_len;
4302 struct sk_security_struct *ssec;
4303 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004304 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305
4306 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004307
Paul Moore3de4bab2006-11-17 17:38:54 -05004308 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4309 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004310 ssec = sock->sk->sk_security;
4311 peer_sid = ssec->peer_sid;
4312 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004313 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 err = -ENOPROTOOPT;
4315 goto out;
4316 }
4317
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004318 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4319
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 if (err)
4321 goto out;
4322
4323 if (scontext_len > len) {
4324 err = -ERANGE;
4325 goto out_len;
4326 }
4327
4328 if (copy_to_user(optval, scontext, scontext_len))
4329 err = -EFAULT;
4330
4331out_len:
4332 if (put_user(scontext_len, optlen))
4333 err = -EFAULT;
4334
4335 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004336out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 return err;
4338}
4339
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004340static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004341{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004342 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004343 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004344
Paul Mooreaa862902008-10-10 10:16:29 -04004345 if (skb && skb->protocol == htons(ETH_P_IP))
4346 family = PF_INET;
4347 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4348 family = PF_INET6;
4349 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004350 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004351 else
4352 goto out;
4353
4354 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004355 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004356 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004357 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004358
Paul Moore75e22912008-01-29 08:38:04 -05004359out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004360 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004361 if (peer_secid == SECSID_NULL)
4362 return -EINVAL;
4363 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004364}
4365
Al Viro7d877f32005-10-21 03:20:43 -04004366static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367{
4368 return sk_alloc_security(sk, family, priority);
4369}
4370
4371static void selinux_sk_free_security(struct sock *sk)
4372{
4373 sk_free_security(sk);
4374}
4375
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004376static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4377{
4378 struct sk_security_struct *ssec = sk->sk_security;
4379 struct sk_security_struct *newssec = newsk->sk_security;
4380
4381 newssec->sid = ssec->sid;
4382 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004383 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004384
Paul Mooref74af6e2008-02-25 11:40:33 -05004385 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004386}
4387
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004388static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004389{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004390 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004391 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004392 else {
4393 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004394
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004395 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004396 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004397}
4398
Eric Paris828dfe12008-04-17 13:17:49 -04004399static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004400{
4401 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4402 struct sk_security_struct *sksec = sk->sk_security;
4403
David Woodhouse2148ccc2006-09-29 15:50:25 -07004404 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4405 sk->sk_family == PF_UNIX)
4406 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004407 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004408}
4409
Adrian Bunk9a673e52006-08-15 00:03:53 -07004410static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4411 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004412{
4413 struct sk_security_struct *sksec = sk->sk_security;
4414 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004415 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004416 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004417 u32 peersid;
4418
Paul Mooreaa862902008-10-10 10:16:29 -04004419 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4420 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4421 family = PF_INET;
4422
4423 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004424 if (err)
4425 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004426 if (peersid == SECSID_NULL) {
4427 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004428 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004429 return 0;
4430 }
4431
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004432 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4433 if (err)
4434 return err;
4435
4436 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004437 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004438 return 0;
4439}
4440
Adrian Bunk9a673e52006-08-15 00:03:53 -07004441static void selinux_inet_csk_clone(struct sock *newsk,
4442 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004443{
4444 struct sk_security_struct *newsksec = newsk->sk_security;
4445
4446 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004447 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004448 /* NOTE: Ideally, we should also get the isec->sid for the
4449 new socket in sync, but we don't have the isec available yet.
4450 So we will wait until sock_graft to do it, by which
4451 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004452
Paul Moore9f2ad662006-11-17 17:38:53 -05004453 /* We don't need to take any sort of lock here as we are the only
4454 * thread with access to newsksec */
4455 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004456}
4457
Paul Moore014ab192008-10-10 10:16:33 -04004458static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004459{
Paul Mooreaa862902008-10-10 10:16:29 -04004460 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004461 struct sk_security_struct *sksec = sk->sk_security;
4462
Paul Mooreaa862902008-10-10 10:16:29 -04004463 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4464 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4465 family = PF_INET;
4466
4467 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004468
4469 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004470}
4471
Adrian Bunk9a673e52006-08-15 00:03:53 -07004472static void selinux_req_classify_flow(const struct request_sock *req,
4473 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004474{
4475 fl->secid = req->secid;
4476}
4477
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4479{
4480 int err = 0;
4481 u32 perm;
4482 struct nlmsghdr *nlh;
4483 struct socket *sock = sk->sk_socket;
4484 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004485
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 if (skb->len < NLMSG_SPACE(0)) {
4487 err = -EINVAL;
4488 goto out;
4489 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004490 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004491
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4493 if (err) {
4494 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004495 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 "SELinux: unrecognized netlink message"
4497 " type=%hu for sclass=%hu\n",
4498 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004499 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 err = 0;
4501 }
4502
4503 /* Ignore */
4504 if (err == -ENOENT)
4505 err = 0;
4506 goto out;
4507 }
4508
4509 err = socket_has_perm(current, sock, perm);
4510out:
4511 return err;
4512}
4513
4514#ifdef CONFIG_NETFILTER
4515
Paul Mooreeffad8d2008-01-29 08:49:27 -05004516static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4517 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518{
Paul Mooredfaebe92008-10-10 10:16:31 -04004519 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004520 char *addrp;
4521 u32 peer_sid;
4522 struct avc_audit_data ad;
4523 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004524 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004525 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004526
Paul Mooreeffad8d2008-01-29 08:49:27 -05004527 if (!selinux_policycap_netpeer)
4528 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004529
Paul Mooreeffad8d2008-01-29 08:49:27 -05004530 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004531 netlbl_active = netlbl_enabled();
4532 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004533 if (!secmark_active && !peerlbl_active)
4534 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004535
Paul Moored8395c82008-10-10 10:16:30 -04004536 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4537 return NF_DROP;
4538
Paul Mooreeffad8d2008-01-29 08:49:27 -05004539 AVC_AUDIT_DATA_INIT(&ad, NET);
4540 ad.u.net.netif = ifindex;
4541 ad.u.net.family = family;
4542 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4543 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Paul Mooredfaebe92008-10-10 10:16:31 -04004545 if (peerlbl_active) {
4546 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4547 peer_sid, &ad);
4548 if (err) {
4549 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004550 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004551 }
4552 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004553
4554 if (secmark_active)
4555 if (avc_has_perm(peer_sid, skb->secmark,
4556 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4557 return NF_DROP;
4558
Paul Moore948bf852008-10-10 10:16:32 -04004559 if (netlbl_active)
4560 /* we do this in the FORWARD path and not the POST_ROUTING
4561 * path because we want to make sure we apply the necessary
4562 * labeling before IPsec is applied so we can leverage AH
4563 * protection */
4564 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4565 return NF_DROP;
4566
Paul Mooreeffad8d2008-01-29 08:49:27 -05004567 return NF_ACCEPT;
4568}
4569
4570static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4571 struct sk_buff *skb,
4572 const struct net_device *in,
4573 const struct net_device *out,
4574 int (*okfn)(struct sk_buff *))
4575{
4576 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4577}
4578
4579#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4580static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4581 struct sk_buff *skb,
4582 const struct net_device *in,
4583 const struct net_device *out,
4584 int (*okfn)(struct sk_buff *))
4585{
4586 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4587}
4588#endif /* IPV6 */
4589
Paul Moore948bf852008-10-10 10:16:32 -04004590static unsigned int selinux_ip_output(struct sk_buff *skb,
4591 u16 family)
4592{
4593 u32 sid;
4594
4595 if (!netlbl_enabled())
4596 return NF_ACCEPT;
4597
4598 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4599 * because we want to make sure we apply the necessary labeling
4600 * before IPsec is applied so we can leverage AH protection */
4601 if (skb->sk) {
4602 struct sk_security_struct *sksec = skb->sk->sk_security;
4603 sid = sksec->sid;
4604 } else
4605 sid = SECINITSID_KERNEL;
4606 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4607 return NF_DROP;
4608
4609 return NF_ACCEPT;
4610}
4611
4612static unsigned int selinux_ipv4_output(unsigned int hooknum,
4613 struct sk_buff *skb,
4614 const struct net_device *in,
4615 const struct net_device *out,
4616 int (*okfn)(struct sk_buff *))
4617{
4618 return selinux_ip_output(skb, PF_INET);
4619}
4620
Paul Mooreeffad8d2008-01-29 08:49:27 -05004621static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4622 int ifindex,
4623 struct avc_audit_data *ad,
4624 u16 family, char *addrp)
4625{
4626 int err;
4627 struct sk_security_struct *sksec = sk->sk_security;
4628 u16 sk_class;
4629 u32 netif_perm, node_perm, send_perm;
4630 u32 port_sid, node_sid, if_sid, sk_sid;
4631
4632 sk_sid = sksec->sid;
4633 sk_class = sksec->sclass;
4634
4635 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 case SECCLASS_UDP_SOCKET:
4637 netif_perm = NETIF__UDP_SEND;
4638 node_perm = NODE__UDP_SEND;
4639 send_perm = UDP_SOCKET__SEND_MSG;
4640 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 case SECCLASS_TCP_SOCKET:
4642 netif_perm = NETIF__TCP_SEND;
4643 node_perm = NODE__TCP_SEND;
4644 send_perm = TCP_SOCKET__SEND_MSG;
4645 break;
James Morris2ee92d42006-11-13 16:09:01 -08004646 case SECCLASS_DCCP_SOCKET:
4647 netif_perm = NETIF__DCCP_SEND;
4648 node_perm = NODE__DCCP_SEND;
4649 send_perm = DCCP_SOCKET__SEND_MSG;
4650 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 default:
4652 netif_perm = NETIF__RAWIP_SEND;
4653 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004654 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 break;
4656 }
4657
Paul Mooreeffad8d2008-01-29 08:49:27 -05004658 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004659 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004660 return err;
4661 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4662 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004663
Paul Moore224dfbd2008-01-29 08:38:13 -05004664 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004665 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004666 return err;
4667 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004668 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004669 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
Paul Mooreeffad8d2008-01-29 08:49:27 -05004671 if (send_perm != 0)
4672 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673
Paul Moore3e112172008-04-10 10:48:14 -04004674 err = sel_netport_sid(sk->sk_protocol,
4675 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004676 if (unlikely(err)) {
4677 printk(KERN_WARNING
4678 "SELinux: failure in"
4679 " selinux_ip_postroute_iptables_compat(),"
4680 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004681 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004682 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004683 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004684}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685
Paul Mooreeffad8d2008-01-29 08:49:27 -05004686static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4687 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004688 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004689{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004690 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004691 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004692 struct avc_audit_data ad;
4693 char *addrp;
4694 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004695
Paul Mooreeffad8d2008-01-29 08:49:27 -05004696 if (sk == NULL)
4697 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004698 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004699
Paul Moored8395c82008-10-10 10:16:30 -04004700 AVC_AUDIT_DATA_INIT(&ad, NET);
4701 ad.u.net.netif = ifindex;
4702 ad.u.net.family = family;
4703 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4704 return NF_DROP;
4705
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706 if (selinux_compat_net) {
4707 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004708 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004709 return NF_DROP;
Paul Moore277d3422008-12-31 12:54:11 -05004710 } else if (selinux_secmark_enabled()) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004711 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004712 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004713 return NF_DROP;
4714 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004715
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004717 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004718 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004719
Paul Mooreeffad8d2008-01-29 08:49:27 -05004720 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721}
4722
Paul Mooreeffad8d2008-01-29 08:49:27 -05004723static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4724 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004726 u32 secmark_perm;
4727 u32 peer_sid;
4728 struct sock *sk;
4729 struct avc_audit_data ad;
4730 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004731 u8 secmark_active;
4732 u8 peerlbl_active;
4733
Paul Mooreeffad8d2008-01-29 08:49:27 -05004734 /* If any sort of compatibility mode is enabled then handoff processing
4735 * to the selinux_ip_postroute_compat() function to deal with the
4736 * special handling. We do this in an attempt to keep this function
4737 * as fast and as clean as possible. */
4738 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004739 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004740#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004741 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4742 * packet transformation so allow the packet to pass without any checks
4743 * since we'll have another chance to perform access control checks
4744 * when the packet is on it's final way out.
4745 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4746 * is NULL, in this case go ahead and apply access control. */
4747 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4748 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004749#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004750 secmark_active = selinux_secmark_enabled();
4751 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4752 if (!secmark_active && !peerlbl_active)
4753 return NF_ACCEPT;
4754
Paul Moored8395c82008-10-10 10:16:30 -04004755 /* if the packet is being forwarded then get the peer label from the
4756 * packet itself; otherwise check to see if it is from a local
4757 * application or the kernel, if from an application get the peer label
4758 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004759 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004760 if (sk == NULL) {
4761 switch (family) {
4762 case PF_INET:
4763 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4764 secmark_perm = PACKET__FORWARD_OUT;
4765 else
4766 secmark_perm = PACKET__SEND;
4767 break;
4768 case PF_INET6:
4769 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4770 secmark_perm = PACKET__FORWARD_OUT;
4771 else
4772 secmark_perm = PACKET__SEND;
4773 break;
4774 default:
4775 return NF_DROP;
4776 }
4777 if (secmark_perm == PACKET__FORWARD_OUT) {
4778 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4779 return NF_DROP;
4780 } else
4781 peer_sid = SECINITSID_KERNEL;
4782 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004783 struct sk_security_struct *sksec = sk->sk_security;
4784 peer_sid = sksec->sid;
4785 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004786 }
4787
Paul Moored8395c82008-10-10 10:16:30 -04004788 AVC_AUDIT_DATA_INIT(&ad, NET);
4789 ad.u.net.netif = ifindex;
4790 ad.u.net.family = family;
4791 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4792 return NF_DROP;
4793
Paul Mooreeffad8d2008-01-29 08:49:27 -05004794 if (secmark_active)
4795 if (avc_has_perm(peer_sid, skb->secmark,
4796 SECCLASS_PACKET, secmark_perm, &ad))
4797 return NF_DROP;
4798
4799 if (peerlbl_active) {
4800 u32 if_sid;
4801 u32 node_sid;
4802
4803 if (sel_netif_sid(ifindex, &if_sid))
4804 return NF_DROP;
4805 if (avc_has_perm(peer_sid, if_sid,
4806 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4807 return NF_DROP;
4808
4809 if (sel_netnode_sid(addrp, family, &node_sid))
4810 return NF_DROP;
4811 if (avc_has_perm(peer_sid, node_sid,
4812 SECCLASS_NODE, NODE__SENDTO, &ad))
4813 return NF_DROP;
4814 }
4815
4816 return NF_ACCEPT;
4817}
4818
4819static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4820 struct sk_buff *skb,
4821 const struct net_device *in,
4822 const struct net_device *out,
4823 int (*okfn)(struct sk_buff *))
4824{
4825 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826}
4827
4828#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004829static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4830 struct sk_buff *skb,
4831 const struct net_device *in,
4832 const struct net_device *out,
4833 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004835 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837#endif /* IPV6 */
4838
4839#endif /* CONFIG_NETFILTER */
4840
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4842{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 int err;
4844
4845 err = secondary_ops->netlink_send(sk, skb);
4846 if (err)
4847 return err;
4848
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4850 err = selinux_nlmsg_perm(sk, skb);
4851
4852 return err;
4853}
4854
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004855static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004857 int err;
4858 struct avc_audit_data ad;
4859
4860 err = secondary_ops->netlink_recv(skb, capability);
4861 if (err)
4862 return err;
4863
4864 AVC_AUDIT_DATA_INIT(&ad, CAP);
4865 ad.u.cap = capability;
4866
4867 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004868 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869}
4870
4871static int ipc_alloc_security(struct task_struct *task,
4872 struct kern_ipc_perm *perm,
4873 u16 sclass)
4874{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004876 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877
James Morris89d155e2005-10-30 14:59:21 -08004878 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 if (!isec)
4880 return -ENOMEM;
4881
David Howells275bb412008-11-14 10:39:19 +11004882 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004884 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 perm->security = isec;
4886
4887 return 0;
4888}
4889
4890static void ipc_free_security(struct kern_ipc_perm *perm)
4891{
4892 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 perm->security = NULL;
4894 kfree(isec);
4895}
4896
4897static int msg_msg_alloc_security(struct msg_msg *msg)
4898{
4899 struct msg_security_struct *msec;
4900
James Morris89d155e2005-10-30 14:59:21 -08004901 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 if (!msec)
4903 return -ENOMEM;
4904
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 msec->sid = SECINITSID_UNLABELED;
4906 msg->security = msec;
4907
4908 return 0;
4909}
4910
4911static void msg_msg_free_security(struct msg_msg *msg)
4912{
4913 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914
4915 msg->security = NULL;
4916 kfree(msec);
4917}
4918
4919static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004920 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 struct ipc_security_struct *isec;
4923 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004924 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 isec = ipc_perms->security;
4927
4928 AVC_AUDIT_DATA_INIT(&ad, IPC);
4929 ad.u.ipc_id = ipc_perms->key;
4930
David Howells275bb412008-11-14 10:39:19 +11004931 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932}
4933
4934static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4935{
4936 return msg_msg_alloc_security(msg);
4937}
4938
4939static void selinux_msg_msg_free_security(struct msg_msg *msg)
4940{
4941 msg_msg_free_security(msg);
4942}
4943
4944/* message queue security operations */
4945static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4946{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 struct ipc_security_struct *isec;
4948 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004949 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 int rc;
4951
4952 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4953 if (rc)
4954 return rc;
4955
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 isec = msq->q_perm.security;
4957
4958 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004959 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960
David Howells275bb412008-11-14 10:39:19 +11004961 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 MSGQ__CREATE, &ad);
4963 if (rc) {
4964 ipc_free_security(&msq->q_perm);
4965 return rc;
4966 }
4967 return 0;
4968}
4969
4970static void selinux_msg_queue_free_security(struct msg_queue *msq)
4971{
4972 ipc_free_security(&msq->q_perm);
4973}
4974
4975static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4976{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 struct ipc_security_struct *isec;
4978 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004979 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 isec = msq->q_perm.security;
4982
4983 AVC_AUDIT_DATA_INIT(&ad, IPC);
4984 ad.u.ipc_id = msq->q_perm.key;
4985
David Howells275bb412008-11-14 10:39:19 +11004986 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 MSGQ__ASSOCIATE, &ad);
4988}
4989
4990static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4991{
4992 int err;
4993 int perms;
4994
Eric Paris828dfe12008-04-17 13:17:49 -04004995 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 case IPC_INFO:
4997 case MSG_INFO:
4998 /* No specific object, just general system-wide information. */
4999 return task_has_system(current, SYSTEM__IPC_INFO);
5000 case IPC_STAT:
5001 case MSG_STAT:
5002 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
5003 break;
5004 case IPC_SET:
5005 perms = MSGQ__SETATTR;
5006 break;
5007 case IPC_RMID:
5008 perms = MSGQ__DESTROY;
5009 break;
5010 default:
5011 return 0;
5012 }
5013
Stephen Smalley6af963f2005-05-01 08:58:39 -07005014 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 return err;
5016}
5017
5018static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
5019{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 struct ipc_security_struct *isec;
5021 struct msg_security_struct *msec;
5022 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005023 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 int rc;
5025
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 isec = msq->q_perm.security;
5027 msec = msg->security;
5028
5029 /*
5030 * First time through, need to assign label to the message
5031 */
5032 if (msec->sid == SECINITSID_UNLABELED) {
5033 /*
5034 * Compute new sid based on current process and
5035 * message queue this message will be stored in
5036 */
David Howells275bb412008-11-14 10:39:19 +11005037 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 &msec->sid);
5039 if (rc)
5040 return rc;
5041 }
5042
5043 AVC_AUDIT_DATA_INIT(&ad, IPC);
5044 ad.u.ipc_id = msq->q_perm.key;
5045
5046 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005047 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 MSGQ__WRITE, &ad);
5049 if (!rc)
5050 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005051 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5052 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 if (!rc)
5054 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005055 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5056 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057
5058 return rc;
5059}
5060
5061static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5062 struct task_struct *target,
5063 long type, int mode)
5064{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 struct ipc_security_struct *isec;
5066 struct msg_security_struct *msec;
5067 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005068 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 int rc;
5070
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 isec = msq->q_perm.security;
5072 msec = msg->security;
5073
5074 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005075 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076
David Howells275bb412008-11-14 10:39:19 +11005077 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 SECCLASS_MSGQ, MSGQ__READ, &ad);
5079 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005080 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 SECCLASS_MSG, MSG__RECEIVE, &ad);
5082 return rc;
5083}
5084
5085/* Shared Memory security operations */
5086static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5087{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 struct ipc_security_struct *isec;
5089 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005090 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 int rc;
5092
5093 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5094 if (rc)
5095 return rc;
5096
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 isec = shp->shm_perm.security;
5098
5099 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005100 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101
David Howells275bb412008-11-14 10:39:19 +11005102 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 SHM__CREATE, &ad);
5104 if (rc) {
5105 ipc_free_security(&shp->shm_perm);
5106 return rc;
5107 }
5108 return 0;
5109}
5110
5111static void selinux_shm_free_security(struct shmid_kernel *shp)
5112{
5113 ipc_free_security(&shp->shm_perm);
5114}
5115
5116static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5117{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 struct ipc_security_struct *isec;
5119 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005120 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 isec = shp->shm_perm.security;
5123
5124 AVC_AUDIT_DATA_INIT(&ad, IPC);
5125 ad.u.ipc_id = shp->shm_perm.key;
5126
David Howells275bb412008-11-14 10:39:19 +11005127 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 SHM__ASSOCIATE, &ad);
5129}
5130
5131/* Note, at this point, shp is locked down */
5132static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5133{
5134 int perms;
5135 int err;
5136
Eric Paris828dfe12008-04-17 13:17:49 -04005137 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 case IPC_INFO:
5139 case SHM_INFO:
5140 /* No specific object, just general system-wide information. */
5141 return task_has_system(current, SYSTEM__IPC_INFO);
5142 case IPC_STAT:
5143 case SHM_STAT:
5144 perms = SHM__GETATTR | SHM__ASSOCIATE;
5145 break;
5146 case IPC_SET:
5147 perms = SHM__SETATTR;
5148 break;
5149 case SHM_LOCK:
5150 case SHM_UNLOCK:
5151 perms = SHM__LOCK;
5152 break;
5153 case IPC_RMID:
5154 perms = SHM__DESTROY;
5155 break;
5156 default:
5157 return 0;
5158 }
5159
Stephen Smalley6af963f2005-05-01 08:58:39 -07005160 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 return err;
5162}
5163
5164static int selinux_shm_shmat(struct shmid_kernel *shp,
5165 char __user *shmaddr, int shmflg)
5166{
5167 u32 perms;
5168 int rc;
5169
5170 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5171 if (rc)
5172 return rc;
5173
5174 if (shmflg & SHM_RDONLY)
5175 perms = SHM__READ;
5176 else
5177 perms = SHM__READ | SHM__WRITE;
5178
Stephen Smalley6af963f2005-05-01 08:58:39 -07005179 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180}
5181
5182/* Semaphore security operations */
5183static int selinux_sem_alloc_security(struct sem_array *sma)
5184{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 struct ipc_security_struct *isec;
5186 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005187 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 int rc;
5189
5190 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5191 if (rc)
5192 return rc;
5193
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 isec = sma->sem_perm.security;
5195
5196 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005197 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198
David Howells275bb412008-11-14 10:39:19 +11005199 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 SEM__CREATE, &ad);
5201 if (rc) {
5202 ipc_free_security(&sma->sem_perm);
5203 return rc;
5204 }
5205 return 0;
5206}
5207
5208static void selinux_sem_free_security(struct sem_array *sma)
5209{
5210 ipc_free_security(&sma->sem_perm);
5211}
5212
5213static int selinux_sem_associate(struct sem_array *sma, int semflg)
5214{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 struct ipc_security_struct *isec;
5216 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005217 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 isec = sma->sem_perm.security;
5220
5221 AVC_AUDIT_DATA_INIT(&ad, IPC);
5222 ad.u.ipc_id = sma->sem_perm.key;
5223
David Howells275bb412008-11-14 10:39:19 +11005224 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 SEM__ASSOCIATE, &ad);
5226}
5227
5228/* Note, at this point, sma is locked down */
5229static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5230{
5231 int err;
5232 u32 perms;
5233
Eric Paris828dfe12008-04-17 13:17:49 -04005234 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 case IPC_INFO:
5236 case SEM_INFO:
5237 /* No specific object, just general system-wide information. */
5238 return task_has_system(current, SYSTEM__IPC_INFO);
5239 case GETPID:
5240 case GETNCNT:
5241 case GETZCNT:
5242 perms = SEM__GETATTR;
5243 break;
5244 case GETVAL:
5245 case GETALL:
5246 perms = SEM__READ;
5247 break;
5248 case SETVAL:
5249 case SETALL:
5250 perms = SEM__WRITE;
5251 break;
5252 case IPC_RMID:
5253 perms = SEM__DESTROY;
5254 break;
5255 case IPC_SET:
5256 perms = SEM__SETATTR;
5257 break;
5258 case IPC_STAT:
5259 case SEM_STAT:
5260 perms = SEM__GETATTR | SEM__ASSOCIATE;
5261 break;
5262 default:
5263 return 0;
5264 }
5265
Stephen Smalley6af963f2005-05-01 08:58:39 -07005266 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 return err;
5268}
5269
5270static int selinux_sem_semop(struct sem_array *sma,
5271 struct sembuf *sops, unsigned nsops, int alter)
5272{
5273 u32 perms;
5274
5275 if (alter)
5276 perms = SEM__READ | SEM__WRITE;
5277 else
5278 perms = SEM__READ;
5279
Stephen Smalley6af963f2005-05-01 08:58:39 -07005280 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281}
5282
5283static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5284{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 u32 av = 0;
5286
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 av = 0;
5288 if (flag & S_IRUGO)
5289 av |= IPC__UNIX_READ;
5290 if (flag & S_IWUGO)
5291 av |= IPC__UNIX_WRITE;
5292
5293 if (av == 0)
5294 return 0;
5295
Stephen Smalley6af963f2005-05-01 08:58:39 -07005296 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297}
5298
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005299static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5300{
5301 struct ipc_security_struct *isec = ipcp->security;
5302 *secid = isec->sid;
5303}
5304
Eric Paris828dfe12008-04-17 13:17:49 -04005305static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306{
5307 if (inode)
5308 inode_doinit_with_dentry(inode, dentry);
5309}
5310
5311static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005312 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313{
David Howells275bb412008-11-14 10:39:19 +11005314 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005315 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005317 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318
5319 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005320 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 if (error)
5322 return error;
5323 }
5324
David Howells275bb412008-11-14 10:39:19 +11005325 rcu_read_lock();
5326 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
5328 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005329 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005331 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005333 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005335 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005336 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005337 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005338 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005339 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 else
David Howells275bb412008-11-14 10:39:19 +11005341 goto invalid;
5342 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343
5344 if (!sid)
5345 return 0;
5346
Al Viro04ff9702007-03-12 16:17:58 +00005347 error = security_sid_to_context(sid, value, &len);
5348 if (error)
5349 return error;
5350 return len;
David Howells275bb412008-11-14 10:39:19 +11005351
5352invalid:
5353 rcu_read_unlock();
5354 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355}
5356
5357static int selinux_setprocattr(struct task_struct *p,
5358 char *name, void *value, size_t size)
5359{
5360 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005361 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005362 struct cred *new;
5363 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 int error;
5365 char *str = value;
5366
5367 if (current != p) {
5368 /* SELinux only allows a process to change its own
5369 security attributes. */
5370 return -EACCES;
5371 }
5372
5373 /*
5374 * Basic control over ability to set these attributes at all.
5375 * current == p, but we'll pass them separately in case the
5376 * above restriction is ever removed.
5377 */
5378 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005379 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005381 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005382 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005383 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005384 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005385 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005387 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 else
5389 error = -EINVAL;
5390 if (error)
5391 return error;
5392
5393 /* Obtain a SID for the context, if one was specified. */
5394 if (size && str[1] && str[1] != '\n') {
5395 if (str[size-1] == '\n') {
5396 str[size-1] = 0;
5397 size--;
5398 }
5399 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005400 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5401 if (!capable(CAP_MAC_ADMIN))
5402 return error;
5403 error = security_context_to_sid_force(value, size,
5404 &sid);
5405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 if (error)
5407 return error;
5408 }
5409
David Howellsd84f4f92008-11-14 10:39:23 +11005410 new = prepare_creds();
5411 if (!new)
5412 return -ENOMEM;
5413
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 /* Permission checking based on the specified context is
5415 performed during the actual operation (execve,
5416 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005417 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 checks and may_create for the file creation checks. The
5419 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005420 tsec = new->security;
5421 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005423 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005425 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005426 error = may_create_key(sid, p);
5427 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005428 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005429 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005430 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005431 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005432 } else if (!strcmp(name, "current")) {
5433 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005435 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005436
David Howellsd84f4f92008-11-14 10:39:23 +11005437 /* Only allow single threaded processes to change context */
5438 error = -EPERM;
5439 if (!is_single_threaded(p)) {
5440 error = security_bounded_transition(tsec->sid, sid);
5441 if (error)
5442 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444
5445 /* Check permissions for the transition. */
5446 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005447 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005449 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450
5451 /* Check for ptracing, and update the task SID if ok.
5452 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005453 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005455 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005456 if (tracer)
5457 ptsid = task_sid(tracer);
5458 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
David Howellsd84f4f92008-11-14 10:39:23 +11005460 if (tracer) {
5461 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5462 PROCESS__PTRACE, NULL);
5463 if (error)
5464 goto abort_change;
5465 }
5466
5467 tsec->sid = sid;
5468 } else {
5469 error = -EINVAL;
5470 goto abort_change;
5471 }
5472
5473 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005475
5476abort_change:
5477 abort_creds(new);
5478 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479}
5480
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005481static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5482{
5483 return security_sid_to_context(secid, secdata, seclen);
5484}
5485
David Howells7bf570d2008-04-29 20:52:51 +01005486static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005487{
5488 return security_context_to_sid(secdata, seclen, secid);
5489}
5490
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005491static void selinux_release_secctx(char *secdata, u32 seclen)
5492{
Paul Moore088999e2007-08-01 11:12:58 -04005493 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005494}
5495
Michael LeMayd7200242006-06-22 14:47:17 -07005496#ifdef CONFIG_KEYS
5497
David Howellsd84f4f92008-11-14 10:39:23 +11005498static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005499 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005500{
David Howellsd84f4f92008-11-14 10:39:23 +11005501 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005502 struct key_security_struct *ksec;
5503
5504 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5505 if (!ksec)
5506 return -ENOMEM;
5507
David Howellsd84f4f92008-11-14 10:39:23 +11005508 tsec = cred->security;
5509 if (tsec->keycreate_sid)
5510 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005511 else
David Howellsd84f4f92008-11-14 10:39:23 +11005512 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005513
David Howells275bb412008-11-14 10:39:19 +11005514 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005515 return 0;
5516}
5517
5518static void selinux_key_free(struct key *k)
5519{
5520 struct key_security_struct *ksec = k->security;
5521
5522 k->security = NULL;
5523 kfree(ksec);
5524}
5525
5526static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005527 const struct cred *cred,
5528 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005529{
5530 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005531 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005532 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005533
5534 /* if no specific permissions are requested, we skip the
5535 permission check. No serious, additional covert channels
5536 appear to be created. */
5537 if (perm == 0)
5538 return 0;
5539
David Howellsd84f4f92008-11-14 10:39:23 +11005540 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005541
5542 key = key_ref_to_ptr(key_ref);
5543 ksec = key->security;
5544
5545 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005546}
5547
David Howells70a5bb72008-04-29 01:01:26 -07005548static int selinux_key_getsecurity(struct key *key, char **_buffer)
5549{
5550 struct key_security_struct *ksec = key->security;
5551 char *context = NULL;
5552 unsigned len;
5553 int rc;
5554
5555 rc = security_sid_to_context(ksec->sid, &context, &len);
5556 if (!rc)
5557 rc = len;
5558 *_buffer = context;
5559 return rc;
5560}
5561
Michael LeMayd7200242006-06-22 14:47:17 -07005562#endif
5563
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005565 .name = "selinux",
5566
David Howells5cd9c582008-08-14 11:37:28 +01005567 .ptrace_may_access = selinux_ptrace_may_access,
5568 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005570 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 .sysctl = selinux_sysctl,
5572 .capable = selinux_capable,
5573 .quotactl = selinux_quotactl,
5574 .quota_on = selinux_quota_on,
5575 .syslog = selinux_syslog,
5576 .vm_enough_memory = selinux_vm_enough_memory,
5577
5578 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005579 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
David Howellsa6f76f22008-11-14 10:39:24 +11005581 .bprm_set_creds = selinux_bprm_set_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 .bprm_check_security = selinux_bprm_check_security,
David Howellsa6f76f22008-11-14 10:39:24 +11005583 .bprm_committing_creds = selinux_bprm_committing_creds,
5584 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 .bprm_secureexec = selinux_bprm_secureexec,
5586
5587 .sb_alloc_security = selinux_sb_alloc_security,
5588 .sb_free_security = selinux_sb_free_security,
5589 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005590 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005591 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 .sb_statfs = selinux_sb_statfs,
5593 .sb_mount = selinux_mount,
5594 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005595 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005596 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005597 .sb_parse_opts_str = selinux_parse_opts_str,
5598
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
5600 .inode_alloc_security = selinux_inode_alloc_security,
5601 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005602 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 .inode_unlink = selinux_inode_unlink,
5606 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 .inode_rmdir = selinux_inode_rmdir,
5609 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 .inode_readlink = selinux_inode_readlink,
5612 .inode_follow_link = selinux_inode_follow_link,
5613 .inode_permission = selinux_inode_permission,
5614 .inode_setattr = selinux_inode_setattr,
5615 .inode_getattr = selinux_inode_getattr,
5616 .inode_setxattr = selinux_inode_setxattr,
5617 .inode_post_setxattr = selinux_inode_post_setxattr,
5618 .inode_getxattr = selinux_inode_getxattr,
5619 .inode_listxattr = selinux_inode_listxattr,
5620 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005621 .inode_getsecurity = selinux_inode_getsecurity,
5622 .inode_setsecurity = selinux_inode_setsecurity,
5623 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005624 .inode_need_killpriv = selinux_inode_need_killpriv,
5625 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005626 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627
5628 .file_permission = selinux_file_permission,
5629 .file_alloc_security = selinux_file_alloc_security,
5630 .file_free_security = selinux_file_free_security,
5631 .file_ioctl = selinux_file_ioctl,
5632 .file_mmap = selinux_file_mmap,
5633 .file_mprotect = selinux_file_mprotect,
5634 .file_lock = selinux_file_lock,
5635 .file_fcntl = selinux_file_fcntl,
5636 .file_set_fowner = selinux_file_set_fowner,
5637 .file_send_sigiotask = selinux_file_send_sigiotask,
5638 .file_receive = selinux_file_receive,
5639
Eric Paris828dfe12008-04-17 13:17:49 -04005640 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005641
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005643 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005644 .cred_prepare = selinux_cred_prepare,
5645 .cred_commit = selinux_cred_commit,
David Howells3a3b7ce2008-11-14 10:39:28 +11005646 .kernel_act_as = selinux_kernel_act_as,
5647 .kernel_create_files_as = selinux_kernel_create_files_as,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005649 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 .task_setgid = selinux_task_setgid,
5651 .task_setpgid = selinux_task_setpgid,
5652 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005653 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005654 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 .task_setgroups = selinux_task_setgroups,
5656 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005657 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005658 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 .task_setrlimit = selinux_task_setrlimit,
5660 .task_setscheduler = selinux_task_setscheduler,
5661 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005662 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 .task_kill = selinux_task_kill,
5664 .task_wait = selinux_task_wait,
5665 .task_prctl = selinux_task_prctl,
Eric Paris828dfe12008-04-17 13:17:49 -04005666 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
5668 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005669 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
5671 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5672 .msg_msg_free_security = selinux_msg_msg_free_security,
5673
5674 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5675 .msg_queue_free_security = selinux_msg_queue_free_security,
5676 .msg_queue_associate = selinux_msg_queue_associate,
5677 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5678 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5679 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5680
5681 .shm_alloc_security = selinux_shm_alloc_security,
5682 .shm_free_security = selinux_shm_free_security,
5683 .shm_associate = selinux_shm_associate,
5684 .shm_shmctl = selinux_shm_shmctl,
5685 .shm_shmat = selinux_shm_shmat,
5686
Eric Paris828dfe12008-04-17 13:17:49 -04005687 .sem_alloc_security = selinux_sem_alloc_security,
5688 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 .sem_associate = selinux_sem_associate,
5690 .sem_semctl = selinux_sem_semctl,
5691 .sem_semop = selinux_sem_semop,
5692
Eric Paris828dfe12008-04-17 13:17:49 -04005693 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694
Eric Paris828dfe12008-04-17 13:17:49 -04005695 .getprocattr = selinux_getprocattr,
5696 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005698 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005699 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005700 .release_secctx = selinux_release_secctx,
5701
Eric Paris828dfe12008-04-17 13:17:49 -04005702 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 .unix_may_send = selinux_socket_unix_may_send,
5704
5705 .socket_create = selinux_socket_create,
5706 .socket_post_create = selinux_socket_post_create,
5707 .socket_bind = selinux_socket_bind,
5708 .socket_connect = selinux_socket_connect,
5709 .socket_listen = selinux_socket_listen,
5710 .socket_accept = selinux_socket_accept,
5711 .socket_sendmsg = selinux_socket_sendmsg,
5712 .socket_recvmsg = selinux_socket_recvmsg,
5713 .socket_getsockname = selinux_socket_getsockname,
5714 .socket_getpeername = selinux_socket_getpeername,
5715 .socket_getsockopt = selinux_socket_getsockopt,
5716 .socket_setsockopt = selinux_socket_setsockopt,
5717 .socket_shutdown = selinux_socket_shutdown,
5718 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005719 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5720 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 .sk_alloc_security = selinux_sk_alloc_security,
5722 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005723 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005724 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005725 .sock_graft = selinux_sock_graft,
5726 .inet_conn_request = selinux_inet_conn_request,
5727 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005728 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005729 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005730
5731#ifdef CONFIG_SECURITY_NETWORK_XFRM
5732 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5733 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5734 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005735 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005736 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5737 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005738 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005739 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005740 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005741 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005743
5744#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005745 .key_alloc = selinux_key_alloc,
5746 .key_free = selinux_key_free,
5747 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005748 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005749#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005750
5751#ifdef CONFIG_AUDIT
5752 .audit_rule_init = selinux_audit_rule_init,
5753 .audit_rule_known = selinux_audit_rule_known,
5754 .audit_rule_match = selinux_audit_rule_match,
5755 .audit_rule_free = selinux_audit_rule_free,
5756#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757};
5758
5759static __init int selinux_init(void)
5760{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005761 if (!security_module_enable(&selinux_ops)) {
5762 selinux_enabled = 0;
5763 return 0;
5764 }
5765
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 if (!selinux_enabled) {
5767 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5768 return 0;
5769 }
5770
5771 printk(KERN_INFO "SELinux: Initializing.\n");
5772
5773 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005774 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775
James Morris7cae7e22006-03-22 00:09:22 -08005776 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5777 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005778 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 avc_init();
5780
James Morris6f0f0fd2008-07-10 17:02:07 +09005781 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005783 panic("SELinux: No initial security operations\n");
5784 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 panic("SELinux: Unable to register with kernel.\n");
5786
Eric Paris828dfe12008-04-17 13:17:49 -04005787 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005788 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005789 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005790 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005791
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 return 0;
5793}
5794
5795void selinux_complete_init(void)
5796{
Eric Parisfadcdb42007-02-22 18:11:31 -05005797 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
5799 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005800 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005801 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 spin_lock(&sb_security_lock);
5803next_sb:
5804 if (!list_empty(&superblock_security_head)) {
5805 struct superblock_security_struct *sbsec =
5806 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005807 struct superblock_security_struct,
5808 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005812 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 down_read(&sb->s_umount);
5814 if (sb->s_root)
5815 superblock_doinit(sb, NULL);
5816 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005817 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 spin_lock(&sb_security_lock);
5819 list_del_init(&sbsec->list);
5820 goto next_sb;
5821 }
5822 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005823 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824}
5825
5826/* SELinux requires early initialization in order to label
5827 all processes and objects when they are created. */
5828security_initcall(selinux_init);
5829
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005830#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831
Paul Mooreeffad8d2008-01-29 08:49:27 -05005832static struct nf_hook_ops selinux_ipv4_ops[] = {
5833 {
5834 .hook = selinux_ipv4_postroute,
5835 .owner = THIS_MODULE,
5836 .pf = PF_INET,
5837 .hooknum = NF_INET_POST_ROUTING,
5838 .priority = NF_IP_PRI_SELINUX_LAST,
5839 },
5840 {
5841 .hook = selinux_ipv4_forward,
5842 .owner = THIS_MODULE,
5843 .pf = PF_INET,
5844 .hooknum = NF_INET_FORWARD,
5845 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005846 },
5847 {
5848 .hook = selinux_ipv4_output,
5849 .owner = THIS_MODULE,
5850 .pf = PF_INET,
5851 .hooknum = NF_INET_LOCAL_OUT,
5852 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854};
5855
5856#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5857
Paul Mooreeffad8d2008-01-29 08:49:27 -05005858static struct nf_hook_ops selinux_ipv6_ops[] = {
5859 {
5860 .hook = selinux_ipv6_postroute,
5861 .owner = THIS_MODULE,
5862 .pf = PF_INET6,
5863 .hooknum = NF_INET_POST_ROUTING,
5864 .priority = NF_IP6_PRI_SELINUX_LAST,
5865 },
5866 {
5867 .hook = selinux_ipv6_forward,
5868 .owner = THIS_MODULE,
5869 .pf = PF_INET6,
5870 .hooknum = NF_INET_FORWARD,
5871 .priority = NF_IP6_PRI_SELINUX_FIRST,
5872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873};
5874
5875#endif /* IPV6 */
5876
5877static int __init selinux_nf_ip_init(void)
5878{
5879 int err = 0;
5880
5881 if (!selinux_enabled)
5882 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005883
5884 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5885
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005886 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5887 if (err)
5888 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
5890#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005891 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5892 if (err)
5893 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005895
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896out:
5897 return err;
5898}
5899
5900__initcall(selinux_nf_ip_init);
5901
5902#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5903static void selinux_nf_ip_exit(void)
5904{
Eric Parisfadcdb42007-02-22 18:11:31 -05005905 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005907 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005909 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910#endif /* IPV6 */
5911}
5912#endif
5913
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005914#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
5916#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5917#define selinux_nf_ip_exit()
5918#endif
5919
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005920#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
5922#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005923static int selinux_disabled;
5924
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925int selinux_disable(void)
5926{
5927 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
5929 if (ss_initialized) {
5930 /* Not permitted after initial policy load. */
5931 return -EINVAL;
5932 }
5933
5934 if (selinux_disabled) {
5935 /* Only do this once. */
5936 return -EINVAL;
5937 }
5938
5939 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5940
5941 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005942 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943
5944 /* Reset security_ops to the secondary module, dummy or capability. */
5945 security_ops = secondary_ops;
5946
5947 /* Unregister netfilter hooks. */
5948 selinux_nf_ip_exit();
5949
5950 /* Unregister selinuxfs. */
5951 exit_sel_fs();
5952
5953 return 0;
5954}
5955#endif