blob: 91b06f2aa96363f49fe8999d665cd1e9328fe23a [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 sbsec->initialized = 1;
435
Eric Parisc9180a52007-11-30 13:00:35 -0500436 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500437 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500439 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500440 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sb->s_id, sb->s_type->name,
442 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500445 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 /* Initialize any other inodes associated with the superblock, e.g.
448 inodes created prior to initial policy load or inodes created
449 during get_sb by a pseudo filesystem that directly
450 populates itself. */
451 spin_lock(&sbsec->isec_lock);
452next_inode:
453 if (!list_empty(&sbsec->isec_head)) {
454 struct inode_security_struct *isec =
455 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500456 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 struct inode *inode = isec->inode;
458 spin_unlock(&sbsec->isec_lock);
459 inode = igrab(inode);
460 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500461 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 inode_doinit(inode);
463 iput(inode);
464 }
465 spin_lock(&sbsec->isec_lock);
466 list_del_init(&isec->list);
467 goto next_inode;
468 }
469 spin_unlock(&sbsec->isec_lock);
470out:
Eric Parisc9180a52007-11-30 13:00:35 -0500471 return rc;
472}
473
474/*
475 * This function should allow an FS to ask what it's mount security
476 * options were so it can use those later for submounts, displaying
477 * mount options, or whatever.
478 */
479static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500480 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500481{
482 int rc = 0, i;
483 struct superblock_security_struct *sbsec = sb->s_security;
484 char *context = NULL;
485 u32 len;
486 char tmp;
487
Eric Parise0007522008-03-05 10:31:54 -0500488 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500489
490 if (!sbsec->initialized)
491 return -EINVAL;
492
493 if (!ss_initialized)
494 return -EINVAL;
495
496 /*
497 * if we ever use sbsec flags for anything other than tracking mount
498 * settings this is going to need a mask
499 */
500 tmp = sbsec->flags;
501 /* count the number of mount options for this sb */
502 for (i = 0; i < 8; i++) {
503 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500504 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500505 tmp >>= 1;
506 }
507
Eric Parise0007522008-03-05 10:31:54 -0500508 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
509 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500510 rc = -ENOMEM;
511 goto out_free;
512 }
513
Eric Parise0007522008-03-05 10:31:54 -0500514 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
515 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500516 rc = -ENOMEM;
517 goto out_free;
518 }
519
520 i = 0;
521 if (sbsec->flags & FSCONTEXT_MNT) {
522 rc = security_sid_to_context(sbsec->sid, &context, &len);
523 if (rc)
524 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500525 opts->mnt_opts[i] = context;
526 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500527 }
528 if (sbsec->flags & CONTEXT_MNT) {
529 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
530 if (rc)
531 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500532 opts->mnt_opts[i] = context;
533 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500534 }
535 if (sbsec->flags & DEFCONTEXT_MNT) {
536 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
537 if (rc)
538 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500539 opts->mnt_opts[i] = context;
540 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500541 }
542 if (sbsec->flags & ROOTCONTEXT_MNT) {
543 struct inode *root = sbsec->sb->s_root->d_inode;
544 struct inode_security_struct *isec = root->i_security;
545
546 rc = security_sid_to_context(isec->sid, &context, &len);
547 if (rc)
548 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500549 opts->mnt_opts[i] = context;
550 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500551 }
552
Eric Parise0007522008-03-05 10:31:54 -0500553 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500554
555 return 0;
556
557out_free:
Eric Parise0007522008-03-05 10:31:54 -0500558 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500559 return rc;
560}
561
562static int bad_option(struct superblock_security_struct *sbsec, char flag,
563 u32 old_sid, u32 new_sid)
564{
565 /* check if the old mount command had the same options */
566 if (sbsec->initialized)
567 if (!(sbsec->flags & flag) ||
568 (old_sid != new_sid))
569 return 1;
570
571 /* check if we were passed the same options twice,
572 * aka someone passed context=a,context=b
573 */
574 if (!sbsec->initialized)
575 if (sbsec->flags & flag)
576 return 1;
577 return 0;
578}
Eric Parise0007522008-03-05 10:31:54 -0500579
Eric Parisc9180a52007-11-30 13:00:35 -0500580/*
581 * Allow filesystems with binary mount data to explicitly set mount point
582 * labeling information.
583 */
Eric Parise0007522008-03-05 10:31:54 -0500584static int selinux_set_mnt_opts(struct super_block *sb,
585 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500586{
David Howells275bb412008-11-14 10:39:19 +1100587 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500588 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500589 struct superblock_security_struct *sbsec = sb->s_security;
590 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000591 struct inode *inode = sbsec->sb->s_root->d_inode;
592 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500593 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
594 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500595 char **mount_options = opts->mnt_opts;
596 int *flags = opts->mnt_opts_flags;
597 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500598
599 mutex_lock(&sbsec->lock);
600
601 if (!ss_initialized) {
602 if (!num_opts) {
603 /* Defer initialization until selinux_complete_init,
604 after the initial policy is loaded and the security
605 server is ready to handle calls. */
606 spin_lock(&sb_security_lock);
607 if (list_empty(&sbsec->list))
608 list_add(&sbsec->list, &superblock_security_head);
609 spin_unlock(&sb_security_lock);
610 goto out;
611 }
612 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400613 printk(KERN_WARNING "SELinux: Unable to set superblock options "
614 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500615 goto out;
616 }
617
618 /*
Eric Parise0007522008-03-05 10:31:54 -0500619 * Binary mount data FS will come through this function twice. Once
620 * from an explicit call and once from the generic calls from the vfs.
621 * Since the generic VFS calls will not contain any security mount data
622 * we need to skip the double mount verification.
623 *
624 * This does open a hole in which we will not notice if the first
625 * mount using this sb set explict options and a second mount using
626 * this sb does not set any security options. (The first options
627 * will be used for both mounts)
628 */
629 if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
630 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400631 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500632
633 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500634 * parse the mount options, check if they are valid sids.
635 * also check if someone is trying to mount the same sb more
636 * than once with different security options.
637 */
638 for (i = 0; i < num_opts; i++) {
639 u32 sid;
640 rc = security_context_to_sid(mount_options[i],
641 strlen(mount_options[i]), &sid);
642 if (rc) {
643 printk(KERN_WARNING "SELinux: security_context_to_sid"
644 "(%s) failed for (dev %s, type %s) errno=%d\n",
645 mount_options[i], sb->s_id, name, rc);
646 goto out;
647 }
648 switch (flags[i]) {
649 case FSCONTEXT_MNT:
650 fscontext_sid = sid;
651
652 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
653 fscontext_sid))
654 goto out_double_mount;
655
656 sbsec->flags |= FSCONTEXT_MNT;
657 break;
658 case CONTEXT_MNT:
659 context_sid = sid;
660
661 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
662 context_sid))
663 goto out_double_mount;
664
665 sbsec->flags |= CONTEXT_MNT;
666 break;
667 case ROOTCONTEXT_MNT:
668 rootcontext_sid = sid;
669
670 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
671 rootcontext_sid))
672 goto out_double_mount;
673
674 sbsec->flags |= ROOTCONTEXT_MNT;
675
676 break;
677 case DEFCONTEXT_MNT:
678 defcontext_sid = sid;
679
680 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
681 defcontext_sid))
682 goto out_double_mount;
683
684 sbsec->flags |= DEFCONTEXT_MNT;
685
686 break;
687 default:
688 rc = -EINVAL;
689 goto out;
690 }
691 }
692
693 if (sbsec->initialized) {
694 /* previously mounted with options, but not on this attempt? */
695 if (sbsec->flags && !num_opts)
696 goto out_double_mount;
697 rc = 0;
698 goto out;
699 }
700
James Morris089be432008-07-15 18:32:49 +1000701 if (strcmp(sb->s_type->name, "proc") == 0)
Eric Parisc9180a52007-11-30 13:00:35 -0500702 sbsec->proc = 1;
703
704 /* Determine the labeling behavior to use for this filesystem type. */
James Morris089be432008-07-15 18:32:49 +1000705 rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500706 if (rc) {
707 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000708 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500709 goto out;
710 }
711
712 /* sets the context of the superblock for the fs being mounted. */
713 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100714 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500715 if (rc)
716 goto out;
717
718 sbsec->sid = fscontext_sid;
719 }
720
721 /*
722 * Switch to using mount point labeling behavior.
723 * sets the label used on all file below the mountpoint, and will set
724 * the superblock context if not already set.
725 */
726 if (context_sid) {
727 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100728 rc = may_context_mount_sb_relabel(context_sid, sbsec,
729 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500730 if (rc)
731 goto out;
732 sbsec->sid = context_sid;
733 } else {
David Howells275bb412008-11-14 10:39:19 +1100734 rc = may_context_mount_inode_relabel(context_sid, sbsec,
735 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500736 if (rc)
737 goto out;
738 }
739 if (!rootcontext_sid)
740 rootcontext_sid = context_sid;
741
742 sbsec->mntpoint_sid = context_sid;
743 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
744 }
745
746 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100747 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
748 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500749 if (rc)
750 goto out;
751
752 root_isec->sid = rootcontext_sid;
753 root_isec->initialized = 1;
754 }
755
756 if (defcontext_sid) {
757 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
758 rc = -EINVAL;
759 printk(KERN_WARNING "SELinux: defcontext option is "
760 "invalid for this filesystem type\n");
761 goto out;
762 }
763
764 if (defcontext_sid != sbsec->def_sid) {
765 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100766 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500767 if (rc)
768 goto out;
769 }
770
771 sbsec->def_sid = defcontext_sid;
772 }
773
774 rc = sb_finish_set_opts(sb);
775out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700776 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500778out_double_mount:
779 rc = -EINVAL;
780 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
781 "security settings for (dev %s, type %s)\n", sb->s_id, name);
782 goto out;
783}
784
785static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
786 struct super_block *newsb)
787{
788 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
789 struct superblock_security_struct *newsbsec = newsb->s_security;
790
791 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
792 int set_context = (oldsbsec->flags & CONTEXT_MNT);
793 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
794
Eric Paris0f5e6422008-04-21 16:24:11 -0400795 /*
796 * if the parent was able to be mounted it clearly had no special lsm
797 * mount options. thus we can safely put this sb on the list and deal
798 * with it later
799 */
800 if (!ss_initialized) {
801 spin_lock(&sb_security_lock);
802 if (list_empty(&newsbsec->list))
803 list_add(&newsbsec->list, &superblock_security_head);
804 spin_unlock(&sb_security_lock);
805 return;
806 }
Eric Parisc9180a52007-11-30 13:00:35 -0500807
Eric Parisc9180a52007-11-30 13:00:35 -0500808 /* how can we clone if the old one wasn't set up?? */
809 BUG_ON(!oldsbsec->initialized);
810
Eric Paris5a552612008-04-09 14:08:35 -0400811 /* if fs is reusing a sb, just let its options stand... */
812 if (newsbsec->initialized)
813 return;
814
Eric Parisc9180a52007-11-30 13:00:35 -0500815 mutex_lock(&newsbsec->lock);
816
817 newsbsec->flags = oldsbsec->flags;
818
819 newsbsec->sid = oldsbsec->sid;
820 newsbsec->def_sid = oldsbsec->def_sid;
821 newsbsec->behavior = oldsbsec->behavior;
822
823 if (set_context) {
824 u32 sid = oldsbsec->mntpoint_sid;
825
826 if (!set_fscontext)
827 newsbsec->sid = sid;
828 if (!set_rootcontext) {
829 struct inode *newinode = newsb->s_root->d_inode;
830 struct inode_security_struct *newisec = newinode->i_security;
831 newisec->sid = sid;
832 }
833 newsbsec->mntpoint_sid = sid;
834 }
835 if (set_rootcontext) {
836 const struct inode *oldinode = oldsb->s_root->d_inode;
837 const struct inode_security_struct *oldisec = oldinode->i_security;
838 struct inode *newinode = newsb->s_root->d_inode;
839 struct inode_security_struct *newisec = newinode->i_security;
840
841 newisec->sid = oldisec->sid;
842 }
843
844 sb_finish_set_opts(newsb);
845 mutex_unlock(&newsbsec->lock);
846}
847
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200848static int selinux_parse_opts_str(char *options,
849 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500850{
Eric Parise0007522008-03-05 10:31:54 -0500851 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500852 char *context = NULL, *defcontext = NULL;
853 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500854 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500855
Eric Parise0007522008-03-05 10:31:54 -0500856 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500857
858 /* Standard string-based options. */
859 while ((p = strsep(&options, "|")) != NULL) {
860 int token;
861 substring_t args[MAX_OPT_ARGS];
862
863 if (!*p)
864 continue;
865
866 token = match_token(p, tokens, args);
867
868 switch (token) {
869 case Opt_context:
870 if (context || defcontext) {
871 rc = -EINVAL;
872 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
873 goto out_err;
874 }
875 context = match_strdup(&args[0]);
876 if (!context) {
877 rc = -ENOMEM;
878 goto out_err;
879 }
880 break;
881
882 case Opt_fscontext:
883 if (fscontext) {
884 rc = -EINVAL;
885 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
886 goto out_err;
887 }
888 fscontext = match_strdup(&args[0]);
889 if (!fscontext) {
890 rc = -ENOMEM;
891 goto out_err;
892 }
893 break;
894
895 case Opt_rootcontext:
896 if (rootcontext) {
897 rc = -EINVAL;
898 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
899 goto out_err;
900 }
901 rootcontext = match_strdup(&args[0]);
902 if (!rootcontext) {
903 rc = -ENOMEM;
904 goto out_err;
905 }
906 break;
907
908 case Opt_defcontext:
909 if (context || defcontext) {
910 rc = -EINVAL;
911 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
912 goto out_err;
913 }
914 defcontext = match_strdup(&args[0]);
915 if (!defcontext) {
916 rc = -ENOMEM;
917 goto out_err;
918 }
919 break;
920
921 default:
922 rc = -EINVAL;
923 printk(KERN_WARNING "SELinux: unknown mount option\n");
924 goto out_err;
925
926 }
927 }
928
Eric Parise0007522008-03-05 10:31:54 -0500929 rc = -ENOMEM;
930 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
931 if (!opts->mnt_opts)
932 goto out_err;
933
934 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
935 if (!opts->mnt_opts_flags) {
936 kfree(opts->mnt_opts);
937 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500938 }
939
Eric Parise0007522008-03-05 10:31:54 -0500940 if (fscontext) {
941 opts->mnt_opts[num_mnt_opts] = fscontext;
942 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
943 }
944 if (context) {
945 opts->mnt_opts[num_mnt_opts] = context;
946 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
947 }
948 if (rootcontext) {
949 opts->mnt_opts[num_mnt_opts] = rootcontext;
950 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
951 }
952 if (defcontext) {
953 opts->mnt_opts[num_mnt_opts] = defcontext;
954 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
955 }
956
957 opts->num_mnt_opts = num_mnt_opts;
958 return 0;
959
Eric Parisc9180a52007-11-30 13:00:35 -0500960out_err:
961 kfree(context);
962 kfree(defcontext);
963 kfree(fscontext);
964 kfree(rootcontext);
965 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
Eric Parise0007522008-03-05 10:31:54 -0500967/*
968 * string mount options parsing and call set the sbsec
969 */
970static int superblock_doinit(struct super_block *sb, void *data)
971{
972 int rc = 0;
973 char *options = data;
974 struct security_mnt_opts opts;
975
976 security_init_mnt_opts(&opts);
977
978 if (!data)
979 goto out;
980
981 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
982
983 rc = selinux_parse_opts_str(options, &opts);
984 if (rc)
985 goto out_err;
986
987out:
988 rc = selinux_set_mnt_opts(sb, &opts);
989
990out_err:
991 security_free_mnt_opts(&opts);
992 return rc;
993}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Adrian Bunk3583a712008-07-22 20:21:23 +0300995static void selinux_write_opts(struct seq_file *m,
996 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000997{
998 int i;
999 char *prefix;
1000
1001 for (i = 0; i < opts->num_mnt_opts; i++) {
1002 char *has_comma = strchr(opts->mnt_opts[i], ',');
1003
1004 switch (opts->mnt_opts_flags[i]) {
1005 case CONTEXT_MNT:
1006 prefix = CONTEXT_STR;
1007 break;
1008 case FSCONTEXT_MNT:
1009 prefix = FSCONTEXT_STR;
1010 break;
1011 case ROOTCONTEXT_MNT:
1012 prefix = ROOTCONTEXT_STR;
1013 break;
1014 case DEFCONTEXT_MNT:
1015 prefix = DEFCONTEXT_STR;
1016 break;
1017 default:
1018 BUG();
1019 };
1020 /* we need a comma before each option */
1021 seq_putc(m, ',');
1022 seq_puts(m, prefix);
1023 if (has_comma)
1024 seq_putc(m, '\"');
1025 seq_puts(m, opts->mnt_opts[i]);
1026 if (has_comma)
1027 seq_putc(m, '\"');
1028 }
1029}
1030
1031static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1032{
1033 struct security_mnt_opts opts;
1034 int rc;
1035
1036 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001037 if (rc) {
1038 /* before policy load we may get EINVAL, don't show anything */
1039 if (rc == -EINVAL)
1040 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001041 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001042 }
Eric Paris2069f452008-07-04 09:47:13 +10001043
1044 selinux_write_opts(m, &opts);
1045
1046 security_free_mnt_opts(&opts);
1047
1048 return rc;
1049}
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051static inline u16 inode_mode_to_security_class(umode_t mode)
1052{
1053 switch (mode & S_IFMT) {
1054 case S_IFSOCK:
1055 return SECCLASS_SOCK_FILE;
1056 case S_IFLNK:
1057 return SECCLASS_LNK_FILE;
1058 case S_IFREG:
1059 return SECCLASS_FILE;
1060 case S_IFBLK:
1061 return SECCLASS_BLK_FILE;
1062 case S_IFDIR:
1063 return SECCLASS_DIR;
1064 case S_IFCHR:
1065 return SECCLASS_CHR_FILE;
1066 case S_IFIFO:
1067 return SECCLASS_FIFO_FILE;
1068
1069 }
1070
1071 return SECCLASS_FILE;
1072}
1073
James Morris13402582005-09-30 14:24:34 -04001074static inline int default_protocol_stream(int protocol)
1075{
1076 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1077}
1078
1079static inline int default_protocol_dgram(int protocol)
1080{
1081 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1082}
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1085{
1086 switch (family) {
1087 case PF_UNIX:
1088 switch (type) {
1089 case SOCK_STREAM:
1090 case SOCK_SEQPACKET:
1091 return SECCLASS_UNIX_STREAM_SOCKET;
1092 case SOCK_DGRAM:
1093 return SECCLASS_UNIX_DGRAM_SOCKET;
1094 }
1095 break;
1096 case PF_INET:
1097 case PF_INET6:
1098 switch (type) {
1099 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001100 if (default_protocol_stream(protocol))
1101 return SECCLASS_TCP_SOCKET;
1102 else
1103 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001105 if (default_protocol_dgram(protocol))
1106 return SECCLASS_UDP_SOCKET;
1107 else
1108 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001109 case SOCK_DCCP:
1110 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001111 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return SECCLASS_RAWIP_SOCKET;
1113 }
1114 break;
1115 case PF_NETLINK:
1116 switch (protocol) {
1117 case NETLINK_ROUTE:
1118 return SECCLASS_NETLINK_ROUTE_SOCKET;
1119 case NETLINK_FIREWALL:
1120 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001121 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1123 case NETLINK_NFLOG:
1124 return SECCLASS_NETLINK_NFLOG_SOCKET;
1125 case NETLINK_XFRM:
1126 return SECCLASS_NETLINK_XFRM_SOCKET;
1127 case NETLINK_SELINUX:
1128 return SECCLASS_NETLINK_SELINUX_SOCKET;
1129 case NETLINK_AUDIT:
1130 return SECCLASS_NETLINK_AUDIT_SOCKET;
1131 case NETLINK_IP6_FW:
1132 return SECCLASS_NETLINK_IP6FW_SOCKET;
1133 case NETLINK_DNRTMSG:
1134 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001135 case NETLINK_KOBJECT_UEVENT:
1136 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 default:
1138 return SECCLASS_NETLINK_SOCKET;
1139 }
1140 case PF_PACKET:
1141 return SECCLASS_PACKET_SOCKET;
1142 case PF_KEY:
1143 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001144 case PF_APPLETALK:
1145 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 }
1147
1148 return SECCLASS_SOCKET;
1149}
1150
1151#ifdef CONFIG_PROC_FS
1152static int selinux_proc_get_sid(struct proc_dir_entry *de,
1153 u16 tclass,
1154 u32 *sid)
1155{
1156 int buflen, rc;
1157 char *buffer, *path, *end;
1158
Eric Paris828dfe12008-04-17 13:17:49 -04001159 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (!buffer)
1161 return -ENOMEM;
1162
1163 buflen = PAGE_SIZE;
1164 end = buffer+buflen;
1165 *--end = '\0';
1166 buflen--;
1167 path = end-1;
1168 *path = '/';
1169 while (de && de != de->parent) {
1170 buflen -= de->namelen + 1;
1171 if (buflen < 0)
1172 break;
1173 end -= de->namelen;
1174 memcpy(end, de->name, de->namelen);
1175 *--end = '/';
1176 path = end;
1177 de = de->parent;
1178 }
1179 rc = security_genfs_sid("proc", path, tclass, sid);
1180 free_page((unsigned long)buffer);
1181 return rc;
1182}
1183#else
1184static int selinux_proc_get_sid(struct proc_dir_entry *de,
1185 u16 tclass,
1186 u32 *sid)
1187{
1188 return -EINVAL;
1189}
1190#endif
1191
1192/* The inode's security attributes must be initialized before first use. */
1193static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1194{
1195 struct superblock_security_struct *sbsec = NULL;
1196 struct inode_security_struct *isec = inode->i_security;
1197 u32 sid;
1198 struct dentry *dentry;
1199#define INITCONTEXTLEN 255
1200 char *context = NULL;
1201 unsigned len = 0;
1202 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 if (isec->initialized)
1205 goto out;
1206
Eric Paris23970742006-09-25 23:32:01 -07001207 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001209 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 sbsec = inode->i_sb->s_security;
1212 if (!sbsec->initialized) {
1213 /* Defer initialization until selinux_complete_init,
1214 after the initial policy is loaded and the security
1215 server is ready to handle calls. */
1216 spin_lock(&sbsec->isec_lock);
1217 if (list_empty(&isec->list))
1218 list_add(&isec->list, &sbsec->isec_head);
1219 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001220 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
1222
1223 switch (sbsec->behavior) {
1224 case SECURITY_FS_USE_XATTR:
1225 if (!inode->i_op->getxattr) {
1226 isec->sid = sbsec->def_sid;
1227 break;
1228 }
1229
1230 /* Need a dentry, since the xattr API requires one.
1231 Life would be simpler if we could just pass the inode. */
1232 if (opt_dentry) {
1233 /* Called from d_instantiate or d_splice_alias. */
1234 dentry = dget(opt_dentry);
1235 } else {
1236 /* Called from selinux_complete_init, try to find a dentry. */
1237 dentry = d_find_alias(inode);
1238 }
1239 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001240 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001241 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001243 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245
1246 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001247 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 if (!context) {
1249 rc = -ENOMEM;
1250 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001251 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 }
1253 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1254 context, len);
1255 if (rc == -ERANGE) {
1256 /* Need a larger buffer. Query for the right size. */
1257 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1258 NULL, 0);
1259 if (rc < 0) {
1260 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001261 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 }
1263 kfree(context);
1264 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001265 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 if (!context) {
1267 rc = -ENOMEM;
1268 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001269 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
1271 rc = inode->i_op->getxattr(dentry,
1272 XATTR_NAME_SELINUX,
1273 context, len);
1274 }
1275 dput(dentry);
1276 if (rc < 0) {
1277 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001278 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001279 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 -rc, inode->i_sb->s_id, inode->i_ino);
1281 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001282 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 }
1284 /* Map ENODATA to the default file SID */
1285 sid = sbsec->def_sid;
1286 rc = 0;
1287 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001288 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001289 sbsec->def_sid,
1290 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001292 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001294 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 inode->i_sb->s_id, inode->i_ino);
1296 kfree(context);
1297 /* Leave with the unlabeled SID */
1298 rc = 0;
1299 break;
1300 }
1301 }
1302 kfree(context);
1303 isec->sid = sid;
1304 break;
1305 case SECURITY_FS_USE_TASK:
1306 isec->sid = isec->task_sid;
1307 break;
1308 case SECURITY_FS_USE_TRANS:
1309 /* Default to the fs SID. */
1310 isec->sid = sbsec->sid;
1311
1312 /* Try to obtain a transition SID. */
1313 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1314 rc = security_transition_sid(isec->task_sid,
1315 sbsec->sid,
1316 isec->sclass,
1317 &sid);
1318 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001319 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 isec->sid = sid;
1321 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001322 case SECURITY_FS_USE_MNTPOINT:
1323 isec->sid = sbsec->mntpoint_sid;
1324 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001326 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 isec->sid = sbsec->sid;
1328
Stephen Smalleyea6b1842008-09-22 15:41:19 -04001329 if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 struct proc_inode *proci = PROC_I(inode);
1331 if (proci->pde) {
1332 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1333 rc = selinux_proc_get_sid(proci->pde,
1334 isec->sclass,
1335 &sid);
1336 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001337 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 isec->sid = sid;
1339 }
1340 }
1341 break;
1342 }
1343
1344 isec->initialized = 1;
1345
Eric Paris23970742006-09-25 23:32:01 -07001346out_unlock:
1347 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348out:
1349 if (isec->sclass == SECCLASS_FILE)
1350 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return rc;
1352}
1353
1354/* Convert a Linux signal to an access vector. */
1355static inline u32 signal_to_av(int sig)
1356{
1357 u32 perm = 0;
1358
1359 switch (sig) {
1360 case SIGCHLD:
1361 /* Commonly granted from child to parent. */
1362 perm = PROCESS__SIGCHLD;
1363 break;
1364 case SIGKILL:
1365 /* Cannot be caught or ignored */
1366 perm = PROCESS__SIGKILL;
1367 break;
1368 case SIGSTOP:
1369 /* Cannot be caught or ignored */
1370 perm = PROCESS__SIGSTOP;
1371 break;
1372 default:
1373 /* All other signals. */
1374 perm = PROCESS__SIGNAL;
1375 break;
1376 }
1377
1378 return perm;
1379}
1380
David Howells275bb412008-11-14 10:39:19 +11001381/*
David Howellsd84f4f92008-11-14 10:39:23 +11001382 * Check permission between a pair of credentials
1383 * fork check, ptrace check, etc.
1384 */
1385static int cred_has_perm(const struct cred *actor,
1386 const struct cred *target,
1387 u32 perms)
1388{
1389 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1390
1391 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1392}
1393
1394/*
David Howells88e67f32008-11-14 10:39:21 +11001395 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001396 * fork check, ptrace check, etc.
1397 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001398 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001399 */
1400static int task_has_perm(const struct task_struct *tsk1,
1401 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 u32 perms)
1403{
David Howells275bb412008-11-14 10:39:19 +11001404 const struct task_security_struct *__tsec1, *__tsec2;
1405 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
David Howells275bb412008-11-14 10:39:19 +11001407 rcu_read_lock();
1408 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1409 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1410 rcu_read_unlock();
1411 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412}
1413
David Howells3b11a1d2008-11-14 10:39:26 +11001414/*
1415 * Check permission between current and another task, e.g. signal checks,
1416 * fork check, ptrace check, etc.
1417 * current is the actor and tsk2 is the target
1418 * - this uses current's subjective creds
1419 */
1420static int current_has_perm(const struct task_struct *tsk,
1421 u32 perms)
1422{
1423 u32 sid, tsid;
1424
1425 sid = current_sid();
1426 tsid = task_sid(tsk);
1427 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1428}
1429
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001430#if CAP_LAST_CAP > 63
1431#error Fix SELinux to handle capabilities > 63.
1432#endif
1433
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434/* Check whether a task is allowed to use a capability. */
1435static int task_has_capability(struct task_struct *tsk,
Eric Paris06112162008-11-11 22:02:50 +11001436 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001439 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001440 u16 sclass;
David Howells275bb412008-11-14 10:39:19 +11001441 u32 sid = task_sid(tsk);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001442 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001443 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Eric Paris828dfe12008-04-17 13:17:49 -04001445 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 ad.tsk = tsk;
1447 ad.u.cap = cap;
1448
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001449 switch (CAP_TO_INDEX(cap)) {
1450 case 0:
1451 sclass = SECCLASS_CAPABILITY;
1452 break;
1453 case 1:
1454 sclass = SECCLASS_CAPABILITY2;
1455 break;
1456 default:
1457 printk(KERN_ERR
1458 "SELinux: out of range capability %d\n", cap);
1459 BUG();
1460 }
Eric Paris06112162008-11-11 22:02:50 +11001461
David Howells275bb412008-11-14 10:39:19 +11001462 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001463 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001464 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001465 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466}
1467
1468/* Check whether a task is allowed to use a system operation. */
1469static int task_has_system(struct task_struct *tsk,
1470 u32 perms)
1471{
David Howells275bb412008-11-14 10:39:19 +11001472 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
David Howells275bb412008-11-14 10:39:19 +11001474 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 SECCLASS_SYSTEM, perms, NULL);
1476}
1477
1478/* Check whether a task has a particular permission to an inode.
1479 The 'adp' parameter is optional and allows other audit
1480 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001481static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 struct inode *inode,
1483 u32 perms,
1484 struct avc_audit_data *adp)
1485{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 struct inode_security_struct *isec;
1487 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001488 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Eric Paris828dfe12008-04-17 13:17:49 -04001490 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001491 return 0;
1492
David Howells88e67f32008-11-14 10:39:21 +11001493 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 isec = inode->i_security;
1495
1496 if (!adp) {
1497 adp = &ad;
1498 AVC_AUDIT_DATA_INIT(&ad, FS);
1499 ad.u.fs.inode = inode;
1500 }
1501
David Howells275bb412008-11-14 10:39:19 +11001502 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503}
1504
1505/* Same as inode_has_perm, but pass explicit audit data containing
1506 the dentry to help the auditing code to more easily generate the
1507 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001508static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 struct vfsmount *mnt,
1510 struct dentry *dentry,
1511 u32 av)
1512{
1513 struct inode *inode = dentry->d_inode;
1514 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001515
Eric Paris828dfe12008-04-17 13:17:49 -04001516 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001517 ad.u.fs.path.mnt = mnt;
1518 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001519 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520}
1521
1522/* Check whether a task can use an open file descriptor to
1523 access an inode in a given way. Check access to the
1524 descriptor itself, and then use dentry_has_perm to
1525 check a particular permission to the file.
1526 Access to the descriptor is implicitly granted if it
1527 has the same SID as the process. If av is zero, then
1528 access to the file is not checked, e.g. for cases
1529 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001530static int file_has_perm(const struct cred *cred,
1531 struct file *file,
1532 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001535 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001537 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 int rc;
1539
1540 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001541 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
David Howells275bb412008-11-14 10:39:19 +11001543 if (sid != fsec->sid) {
1544 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 SECCLASS_FD,
1546 FD__USE,
1547 &ad);
1548 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001549 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 }
1551
1552 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001553 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001555 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
David Howells88e67f32008-11-14 10:39:21 +11001557out:
1558 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559}
1560
1561/* Check whether a task can create a file. */
1562static int may_create(struct inode *dir,
1563 struct dentry *dentry,
1564 u16 tclass)
1565{
David Howells275bb412008-11-14 10:39:19 +11001566 const struct cred *cred = current_cred();
1567 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 struct inode_security_struct *dsec;
1569 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001570 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 struct avc_audit_data ad;
1572 int rc;
1573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 dsec = dir->i_security;
1575 sbsec = dir->i_sb->s_security;
1576
David Howells275bb412008-11-14 10:39:19 +11001577 sid = tsec->sid;
1578 newsid = tsec->create_sid;
1579
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001581 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
David Howells275bb412008-11-14 10:39:19 +11001583 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 DIR__ADD_NAME | DIR__SEARCH,
1585 &ad);
1586 if (rc)
1587 return rc;
1588
David Howells275bb412008-11-14 10:39:19 +11001589 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
1590 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 if (rc)
1592 return rc;
1593 }
1594
David Howells275bb412008-11-14 10:39:19 +11001595 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 if (rc)
1597 return rc;
1598
1599 return avc_has_perm(newsid, sbsec->sid,
1600 SECCLASS_FILESYSTEM,
1601 FILESYSTEM__ASSOCIATE, &ad);
1602}
1603
Michael LeMay4eb582c2006-06-26 00:24:57 -07001604/* Check whether a task can create a key. */
1605static int may_create_key(u32 ksid,
1606 struct task_struct *ctx)
1607{
David Howells275bb412008-11-14 10:39:19 +11001608 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001609
David Howells275bb412008-11-14 10:39:19 +11001610 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001611}
1612
Eric Paris828dfe12008-04-17 13:17:49 -04001613#define MAY_LINK 0
1614#define MAY_UNLINK 1
1615#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617/* Check whether a task can link, unlink, or rmdir a file/directory. */
1618static int may_link(struct inode *dir,
1619 struct dentry *dentry,
1620 int kind)
1621
1622{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 struct inode_security_struct *dsec, *isec;
1624 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001625 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 u32 av;
1627 int rc;
1628
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 dsec = dir->i_security;
1630 isec = dentry->d_inode->i_security;
1631
1632 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001633 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
1635 av = DIR__SEARCH;
1636 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001637 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (rc)
1639 return rc;
1640
1641 switch (kind) {
1642 case MAY_LINK:
1643 av = FILE__LINK;
1644 break;
1645 case MAY_UNLINK:
1646 av = FILE__UNLINK;
1647 break;
1648 case MAY_RMDIR:
1649 av = DIR__RMDIR;
1650 break;
1651 default:
Eric Paris744ba352008-04-17 11:52:44 -04001652 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1653 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 return 0;
1655 }
1656
David Howells275bb412008-11-14 10:39:19 +11001657 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 return rc;
1659}
1660
1661static inline int may_rename(struct inode *old_dir,
1662 struct dentry *old_dentry,
1663 struct inode *new_dir,
1664 struct dentry *new_dentry)
1665{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1667 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001668 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 u32 av;
1670 int old_is_dir, new_is_dir;
1671 int rc;
1672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 old_dsec = old_dir->i_security;
1674 old_isec = old_dentry->d_inode->i_security;
1675 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1676 new_dsec = new_dir->i_security;
1677
1678 AVC_AUDIT_DATA_INIT(&ad, FS);
1679
Jan Blunck44707fd2008-02-14 19:38:33 -08001680 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001681 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1683 if (rc)
1684 return rc;
David Howells275bb412008-11-14 10:39:19 +11001685 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 old_isec->sclass, FILE__RENAME, &ad);
1687 if (rc)
1688 return rc;
1689 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001690 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 old_isec->sclass, DIR__REPARENT, &ad);
1692 if (rc)
1693 return rc;
1694 }
1695
Jan Blunck44707fd2008-02-14 19:38:33 -08001696 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 av = DIR__ADD_NAME | DIR__SEARCH;
1698 if (new_dentry->d_inode)
1699 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001700 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc)
1702 return rc;
1703 if (new_dentry->d_inode) {
1704 new_isec = new_dentry->d_inode->i_security;
1705 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001706 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 new_isec->sclass,
1708 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1709 if (rc)
1710 return rc;
1711 }
1712
1713 return 0;
1714}
1715
1716/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001717static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 struct super_block *sb,
1719 u32 perms,
1720 struct avc_audit_data *ad)
1721{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001723 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001726 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727}
1728
1729/* Convert a Linux mode and permission mask to an access vector. */
1730static inline u32 file_mask_to_av(int mode, int mask)
1731{
1732 u32 av = 0;
1733
1734 if ((mode & S_IFMT) != S_IFDIR) {
1735 if (mask & MAY_EXEC)
1736 av |= FILE__EXECUTE;
1737 if (mask & MAY_READ)
1738 av |= FILE__READ;
1739
1740 if (mask & MAY_APPEND)
1741 av |= FILE__APPEND;
1742 else if (mask & MAY_WRITE)
1743 av |= FILE__WRITE;
1744
1745 } else {
1746 if (mask & MAY_EXEC)
1747 av |= DIR__SEARCH;
1748 if (mask & MAY_WRITE)
1749 av |= DIR__WRITE;
1750 if (mask & MAY_READ)
1751 av |= DIR__READ;
1752 }
1753
1754 return av;
1755}
1756
1757/* Convert a Linux file to an access vector. */
1758static inline u32 file_to_av(struct file *file)
1759{
1760 u32 av = 0;
1761
1762 if (file->f_mode & FMODE_READ)
1763 av |= FILE__READ;
1764 if (file->f_mode & FMODE_WRITE) {
1765 if (file->f_flags & O_APPEND)
1766 av |= FILE__APPEND;
1767 else
1768 av |= FILE__WRITE;
1769 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001770 if (!av) {
1771 /*
1772 * Special file opened with flags 3 for ioctl-only use.
1773 */
1774 av = FILE__IOCTL;
1775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 return av;
1778}
1779
Eric Paris8b6a5a32008-10-29 17:06:46 -04001780/*
1781 * Convert a file to an access vector and include the correct open
1782 * open permission.
1783 */
1784static inline u32 open_file_to_av(struct file *file)
1785{
1786 u32 av = file_to_av(file);
1787
1788 if (selinux_policycap_openperm) {
1789 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1790 /*
1791 * lnk files and socks do not really have an 'open'
1792 */
1793 if (S_ISREG(mode))
1794 av |= FILE__OPEN;
1795 else if (S_ISCHR(mode))
1796 av |= CHR_FILE__OPEN;
1797 else if (S_ISBLK(mode))
1798 av |= BLK_FILE__OPEN;
1799 else if (S_ISFIFO(mode))
1800 av |= FIFO_FILE__OPEN;
1801 else if (S_ISDIR(mode))
1802 av |= DIR__OPEN;
1803 else
1804 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1805 "unknown mode:%o\n", __func__, mode);
1806 }
1807 return av;
1808}
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810/* Hook functions begin here. */
1811
David Howells5cd9c582008-08-14 11:37:28 +01001812static int selinux_ptrace_may_access(struct task_struct *child,
1813 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 int rc;
1816
David Howells5cd9c582008-08-14 11:37:28 +01001817 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 if (rc)
1819 return rc;
1820
Stephen Smalley006ebb42008-05-19 08:32:49 -04001821 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001822 u32 sid = current_sid();
1823 u32 csid = task_sid(child);
1824 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001825 }
1826
David Howells3b11a1d2008-11-14 10:39:26 +11001827 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001828}
1829
1830static int selinux_ptrace_traceme(struct task_struct *parent)
1831{
1832 int rc;
1833
1834 rc = secondary_ops->ptrace_traceme(parent);
1835 if (rc)
1836 return rc;
1837
1838 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839}
1840
1841static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001842 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843{
1844 int error;
1845
David Howells3b11a1d2008-11-14 10:39:26 +11001846 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if (error)
1848 return error;
1849
1850 return secondary_ops->capget(target, effective, inheritable, permitted);
1851}
1852
David Howellsd84f4f92008-11-14 10:39:23 +11001853static int selinux_capset(struct cred *new, const struct cred *old,
1854 const kernel_cap_t *effective,
1855 const kernel_cap_t *inheritable,
1856 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857{
1858 int error;
1859
David Howellsd84f4f92008-11-14 10:39:23 +11001860 error = secondary_ops->capset(new, old,
1861 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 if (error)
1863 return error;
1864
David Howellsd84f4f92008-11-14 10:39:23 +11001865 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
Eric Paris06112162008-11-11 22:02:50 +11001868static int selinux_capable(struct task_struct *tsk, int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869{
1870 int rc;
1871
Eric Paris06112162008-11-11 22:02:50 +11001872 rc = secondary_ops->capable(tsk, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (rc)
1874 return rc;
1875
Eric Paris06112162008-11-11 22:02:50 +11001876 return task_has_capability(tsk, 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
Eric Paris06674672008-11-11 22:02:57 +11002040 rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 if (rc == 0)
2042 cap_sys_admin = 1;
2043
Alan Cox34b4e4a2007-08-22 14:01:28 -07002044 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045}
2046
2047/* binprm security operations */
2048
David Howellsa6f76f22008-11-14 10:39:24 +11002049static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
David Howellsa6f76f22008-11-14 10:39:24 +11002051 const struct task_security_struct *old_tsec;
2052 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 struct avc_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11002055 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 int rc;
2057
David Howellsa6f76f22008-11-14 10:39:24 +11002058 rc = secondary_ops->bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 if (rc)
2060 return rc;
2061
David Howellsa6f76f22008-11-14 10:39:24 +11002062 /* SELinux context only depends on initial program or script and not
2063 * the script interpreter */
2064 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 return 0;
2066
David Howellsa6f76f22008-11-14 10:39:24 +11002067 old_tsec = current_security();
2068 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 isec = inode->i_security;
2070
2071 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002072 new_tsec->sid = old_tsec->sid;
2073 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
Michael LeMay28eba5b2006-06-27 02:53:42 -07002075 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002076 new_tsec->create_sid = 0;
2077 new_tsec->keycreate_sid = 0;
2078 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
David Howellsa6f76f22008-11-14 10:39:24 +11002080 if (old_tsec->exec_sid) {
2081 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002083 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 } else {
2085 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002086 rc = security_transition_sid(old_tsec->sid, isec->sid,
2087 SECCLASS_PROCESS, &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 if (rc)
2089 return rc;
2090 }
2091
2092 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002093 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Josef Sipek3d5ff522006-12-08 02:37:38 -08002095 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002096 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
David Howellsa6f76f22008-11-14 10:39:24 +11002098 if (new_tsec->sid == old_tsec->sid) {
2099 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2101 if (rc)
2102 return rc;
2103 } else {
2104 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002105 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2107 if (rc)
2108 return rc;
2109
David Howellsa6f76f22008-11-14 10:39:24 +11002110 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2112 if (rc)
2113 return rc;
2114
David Howellsa6f76f22008-11-14 10:39:24 +11002115 /* Check for shared state */
2116 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2117 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2118 SECCLASS_PROCESS, PROCESS__SHARE,
2119 NULL);
2120 if (rc)
2121 return -EPERM;
2122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
David Howellsa6f76f22008-11-14 10:39:24 +11002124 /* Make sure that anyone attempting to ptrace over a task that
2125 * changes its SID has the appropriate permit */
2126 if (bprm->unsafe &
2127 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2128 struct task_struct *tracer;
2129 struct task_security_struct *sec;
2130 u32 ptsid = 0;
2131
2132 rcu_read_lock();
2133 tracer = tracehook_tracer_task(current);
2134 if (likely(tracer != NULL)) {
2135 sec = __task_cred(tracer)->security;
2136 ptsid = sec->sid;
2137 }
2138 rcu_read_unlock();
2139
2140 if (ptsid != 0) {
2141 rc = avc_has_perm(ptsid, new_tsec->sid,
2142 SECCLASS_PROCESS,
2143 PROCESS__PTRACE, NULL);
2144 if (rc)
2145 return -EPERM;
2146 }
2147 }
2148
2149 /* Clear any possibly unsafe personality bits on exec: */
2150 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 }
2152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 return 0;
2154}
2155
Eric Paris828dfe12008-04-17 13:17:49 -04002156static int selinux_bprm_check_security(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157{
2158 return secondary_ops->bprm_check_security(bprm);
2159}
2160
Eric Paris828dfe12008-04-17 13:17:49 -04002161static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162{
David Howells275bb412008-11-14 10:39:19 +11002163 const struct cred *cred = current_cred();
2164 const struct task_security_struct *tsec = cred->security;
2165 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 int atsecure = 0;
2167
David Howells275bb412008-11-14 10:39:19 +11002168 sid = tsec->sid;
2169 osid = tsec->osid;
2170
2171 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 /* Enable secure mode for SIDs transitions unless
2173 the noatsecure permission is granted between
2174 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002175 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002176 SECCLASS_PROCESS,
2177 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 }
2179
2180 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2181}
2182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183extern struct vfsmount *selinuxfs_mount;
2184extern struct dentry *selinux_null;
2185
2186/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002187static inline void flush_unauthorized_files(const struct cred *cred,
2188 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189{
2190 struct avc_audit_data ad;
2191 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002192 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002193 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002195 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002197 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 if (tty) {
2199 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002200 if (!list_empty(&tty->tty_files)) {
2201 struct inode *inode;
2202
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 /* Revalidate access to controlling tty.
2204 Use inode_has_perm on the tty inode directly rather
2205 than using file_has_perm, as this particular open
2206 file may belong to another process and we are only
2207 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002208 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2209 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002210 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002212 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 }
2214 }
2215 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002216 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002218 /* Reset controlling tty. */
2219 if (drop_tty)
2220 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 /* Revalidate access to inherited open files. */
2223
Eric Paris828dfe12008-04-17 13:17:49 -04002224 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
2226 spin_lock(&files->file_lock);
2227 for (;;) {
2228 unsigned long set, i;
2229 int fd;
2230
2231 j++;
2232 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002233 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002234 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002236 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 if (!set)
2238 continue;
2239 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002240 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 if (set & 1) {
2242 file = fget(i);
2243 if (!file)
2244 continue;
David Howells88e67f32008-11-14 10:39:21 +11002245 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 file,
2247 file_to_av(file))) {
2248 sys_close(i);
2249 fd = get_unused_fd();
2250 if (fd != i) {
2251 if (fd >= 0)
2252 put_unused_fd(fd);
2253 fput(file);
2254 continue;
2255 }
2256 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002257 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 } else {
David Howells745ca242008-11-14 10:39:22 +11002259 devnull = dentry_open(
2260 dget(selinux_null),
2261 mntget(selinuxfs_mount),
2262 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002263 if (IS_ERR(devnull)) {
2264 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 put_unused_fd(fd);
2266 fput(file);
2267 continue;
2268 }
2269 }
2270 fd_install(fd, devnull);
2271 }
2272 fput(file);
2273 }
2274 }
2275 spin_lock(&files->file_lock);
2276
2277 }
2278 spin_unlock(&files->file_lock);
2279}
2280
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281/*
David Howellsa6f76f22008-11-14 10:39:24 +11002282 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 */
David Howellsa6f76f22008-11-14 10:39:24 +11002284static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
David Howellsa6f76f22008-11-14 10:39:24 +11002286 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 int rc, i;
2289
David Howellsa6f76f22008-11-14 10:39:24 +11002290 secondary_ops->bprm_committing_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
David Howellsa6f76f22008-11-14 10:39:24 +11002292 new_tsec = bprm->cred->security;
2293 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 return;
2295
2296 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002297 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
David Howellsa6f76f22008-11-14 10:39:24 +11002299 /* Always clear parent death signal on SID transitions. */
2300 current->pdeath_signal = 0;
2301
2302 /* Check whether the new SID can inherit resource limits from the old
2303 * SID. If not, reset all soft limits to the lower of the current
2304 * task's hard limit and the init task's soft limit.
2305 *
2306 * Note that the setting of hard limits (even to lower them) can be
2307 * controlled by the setrlimit check. The inclusion of the init task's
2308 * soft limit into the computation is to avoid resetting soft limits
2309 * higher than the default soft limit for cases where the default is
2310 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2311 */
2312 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2313 PROCESS__RLIMITINH, NULL);
2314 if (rc) {
2315 for (i = 0; i < RLIM_NLIMITS; i++) {
2316 rlim = current->signal->rlim + i;
2317 initrlim = init_task.signal->rlim + i;
2318 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2319 }
2320 update_rlimit_cpu(rlim->rlim_cur);
2321 }
2322}
2323
2324/*
2325 * Clean up the process immediately after the installation of new credentials
2326 * due to exec
2327 */
2328static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2329{
2330 const struct task_security_struct *tsec = current_security();
2331 struct itimerval itimer;
2332 struct sighand_struct *psig;
2333 u32 osid, sid;
2334 int rc, i;
2335 unsigned long flags;
2336
2337 secondary_ops->bprm_committed_creds(bprm);
2338
2339 osid = tsec->osid;
2340 sid = tsec->sid;
2341
2342 if (sid == osid)
2343 return;
2344
2345 /* Check whether the new SID can inherit signal state from the old SID.
2346 * If not, clear itimers to avoid subsequent signal generation and
2347 * flush and unblock signals.
2348 *
2349 * This must occur _after_ the task SID has been updated so that any
2350 * kill done after the flush will be checked against the new SID.
2351 */
2352 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 if (rc) {
2354 memset(&itimer, 0, sizeof itimer);
2355 for (i = 0; i < 3; i++)
2356 do_setitimer(i, &itimer, NULL);
2357 flush_signals(current);
2358 spin_lock_irq(&current->sighand->siglock);
2359 flush_signal_handlers(current, 1);
2360 sigemptyset(&current->blocked);
2361 recalc_sigpending();
2362 spin_unlock_irq(&current->sighand->siglock);
2363 }
2364
David Howellsa6f76f22008-11-14 10:39:24 +11002365 /* Wake up the parent if it is waiting so that it can recheck
2366 * wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002367 read_lock_irq(&tasklist_lock);
2368 psig = current->parent->sighand;
2369 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002371 spin_unlock_irqrestore(&psig->siglock, flags);
2372 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373}
2374
2375/* superblock security operations */
2376
2377static int selinux_sb_alloc_security(struct super_block *sb)
2378{
2379 return superblock_alloc_security(sb);
2380}
2381
2382static void selinux_sb_free_security(struct super_block *sb)
2383{
2384 superblock_free_security(sb);
2385}
2386
2387static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2388{
2389 if (plen > olen)
2390 return 0;
2391
2392 return !memcmp(prefix, option, plen);
2393}
2394
2395static inline int selinux_option(char *option, int len)
2396{
Eric Paris832cbd92008-04-01 13:24:09 -04002397 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2398 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2399 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
2400 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401}
2402
2403static inline void take_option(char **to, char *from, int *first, int len)
2404{
2405 if (!*first) {
2406 **to = ',';
2407 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002408 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 *first = 0;
2410 memcpy(*to, from, len);
2411 *to += len;
2412}
2413
Eric Paris828dfe12008-04-17 13:17:49 -04002414static inline void take_selinux_option(char **to, char *from, int *first,
2415 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002416{
2417 int current_size = 0;
2418
2419 if (!*first) {
2420 **to = '|';
2421 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002422 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002423 *first = 0;
2424
2425 while (current_size < len) {
2426 if (*from != '"') {
2427 **to = *from;
2428 *to += 1;
2429 }
2430 from += 1;
2431 current_size += 1;
2432 }
2433}
2434
Eric Parise0007522008-03-05 10:31:54 -05002435static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436{
2437 int fnosec, fsec, rc = 0;
2438 char *in_save, *in_curr, *in_end;
2439 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002440 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442 in_curr = orig;
2443 sec_curr = copy;
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2446 if (!nosec) {
2447 rc = -ENOMEM;
2448 goto out;
2449 }
2450
2451 nosec_save = nosec;
2452 fnosec = fsec = 1;
2453 in_save = in_end = orig;
2454
2455 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002456 if (*in_end == '"')
2457 open_quote = !open_quote;
2458 if ((*in_end == ',' && open_quote == 0) ||
2459 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 int len = in_end - in_curr;
2461
2462 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002463 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 else
2465 take_option(&nosec, in_curr, &fnosec, len);
2466
2467 in_curr = in_end + 1;
2468 }
2469 } while (*in_end++);
2470
Eric Paris6931dfc2005-06-30 02:58:51 -07002471 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002472 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473out:
2474 return rc;
2475}
2476
2477static int selinux_sb_kern_mount(struct super_block *sb, void *data)
2478{
David Howells88e67f32008-11-14 10:39:21 +11002479 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 struct avc_audit_data ad;
2481 int rc;
2482
2483 rc = superblock_doinit(sb, data);
2484 if (rc)
2485 return rc;
2486
Eric Paris828dfe12008-04-17 13:17:49 -04002487 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002488 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002489 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490}
2491
David Howells726c3342006-06-23 02:02:58 -07002492static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493{
David Howells88e67f32008-11-14 10:39:21 +11002494 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 struct avc_audit_data ad;
2496
Eric Paris828dfe12008-04-17 13:17:49 -04002497 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002498 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002499 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500}
2501
Eric Paris828dfe12008-04-17 13:17:49 -04002502static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002503 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002504 char *type,
2505 unsigned long flags,
2506 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507{
David Howells88e67f32008-11-14 10:39:21 +11002508 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 int rc;
2510
Al Virob5266eb2008-03-22 17:48:24 -04002511 rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 if (rc)
2513 return rc;
2514
2515 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002516 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002517 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 else
David Howells88e67f32008-11-14 10:39:21 +11002519 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002520 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521}
2522
2523static int selinux_umount(struct vfsmount *mnt, int flags)
2524{
David Howells88e67f32008-11-14 10:39:21 +11002525 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 int rc;
2527
2528 rc = secondary_ops->sb_umount(mnt, flags);
2529 if (rc)
2530 return rc;
2531
David Howells88e67f32008-11-14 10:39:21 +11002532 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002533 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534}
2535
2536/* inode security operations */
2537
2538static int selinux_inode_alloc_security(struct inode *inode)
2539{
2540 return inode_alloc_security(inode);
2541}
2542
2543static void selinux_inode_free_security(struct inode *inode)
2544{
2545 inode_free_security(inode);
2546}
2547
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002548static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2549 char **name, void **value,
2550 size_t *len)
2551{
David Howells275bb412008-11-14 10:39:19 +11002552 const struct cred *cred = current_cred();
2553 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002554 struct inode_security_struct *dsec;
2555 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002556 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002557 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002558 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002559
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002560 dsec = dir->i_security;
2561 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002562
David Howells275bb412008-11-14 10:39:19 +11002563 sid = tsec->sid;
2564 newsid = tsec->create_sid;
2565
2566 if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
2567 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002568 inode_mode_to_security_class(inode->i_mode),
2569 &newsid);
2570 if (rc) {
2571 printk(KERN_WARNING "%s: "
2572 "security_transition_sid failed, rc=%d (dev=%s "
2573 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002574 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002575 -rc, inode->i_sb->s_id, inode->i_ino);
2576 return rc;
2577 }
2578 }
2579
Eric Paris296fddf2006-09-25 23:32:00 -07002580 /* Possibly defer initialization to selinux_complete_init. */
2581 if (sbsec->initialized) {
2582 struct inode_security_struct *isec = inode->i_security;
2583 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2584 isec->sid = newsid;
2585 isec->initialized = 1;
2586 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002587
Stephen Smalley8aad3872006-03-22 00:09:13 -08002588 if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
Stephen Smalley25a74f32005-11-08 21:34:33 -08002589 return -EOPNOTSUPP;
2590
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002591 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002592 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002593 if (!namep)
2594 return -ENOMEM;
2595 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002596 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002597
2598 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002599 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002600 if (rc) {
2601 kfree(namep);
2602 return rc;
2603 }
2604 *value = context;
2605 *len = clen;
2606 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002607
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002608 return 0;
2609}
2610
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2612{
2613 return may_create(dir, dentry, SECCLASS_FILE);
2614}
2615
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2617{
2618 int rc;
2619
Eric Paris828dfe12008-04-17 13:17:49 -04002620 rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 if (rc)
2622 return rc;
2623 return may_link(dir, old_dentry, MAY_LINK);
2624}
2625
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2627{
2628 int rc;
2629
2630 rc = secondary_ops->inode_unlink(dir, dentry);
2631 if (rc)
2632 return rc;
2633 return may_link(dir, dentry, MAY_UNLINK);
2634}
2635
2636static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2637{
2638 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2639}
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2642{
2643 return may_create(dir, dentry, SECCLASS_DIR);
2644}
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2647{
2648 return may_link(dir, dentry, MAY_RMDIR);
2649}
2650
2651static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2652{
2653 int rc;
2654
2655 rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
2656 if (rc)
2657 return rc;
2658
2659 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2660}
2661
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002663 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664{
2665 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2666}
2667
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668static int selinux_inode_readlink(struct dentry *dentry)
2669{
David Howells88e67f32008-11-14 10:39:21 +11002670 const struct cred *cred = current_cred();
2671
2672 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673}
2674
2675static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2676{
David Howells88e67f32008-11-14 10:39:21 +11002677 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 int rc;
2679
Eric Paris828dfe12008-04-17 13:17:49 -04002680 rc = secondary_ops->inode_follow_link(dentry, nameidata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 if (rc)
2682 return rc;
David Howells88e67f32008-11-14 10:39:21 +11002683 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684}
2685
Al Virob77b0642008-07-17 09:37:02 -04002686static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687{
David Howells88e67f32008-11-14 10:39:21 +11002688 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 int rc;
2690
Al Virob77b0642008-07-17 09:37:02 -04002691 rc = secondary_ops->inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 if (rc)
2693 return rc;
2694
2695 if (!mask) {
2696 /* No permission to check. Existence test. */
2697 return 0;
2698 }
2699
David Howells88e67f32008-11-14 10:39:21 +11002700 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002701 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702}
2703
2704static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2705{
David Howells88e67f32008-11-14 10:39:21 +11002706 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 int rc;
2708
2709 rc = secondary_ops->inode_setattr(dentry, iattr);
2710 if (rc)
2711 return rc;
2712
2713 if (iattr->ia_valid & ATTR_FORCE)
2714 return 0;
2715
2716 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2717 ATTR_ATIME_SET | ATTR_MTIME_SET))
David Howells88e67f32008-11-14 10:39:21 +11002718 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
David Howells88e67f32008-11-14 10:39:21 +11002720 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721}
2722
2723static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2724{
David Howells88e67f32008-11-14 10:39:21 +11002725 const struct cred *cred = current_cred();
2726
2727 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728}
2729
David Howells8f0cfa52008-04-29 00:59:41 -07002730static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002731{
David Howells88e67f32008-11-14 10:39:21 +11002732 const struct cred *cred = current_cred();
2733
Serge E. Hallynb5376772007-10-16 23:31:36 -07002734 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2735 sizeof XATTR_SECURITY_PREFIX - 1)) {
2736 if (!strcmp(name, XATTR_NAME_CAPS)) {
2737 if (!capable(CAP_SETFCAP))
2738 return -EPERM;
2739 } else if (!capable(CAP_SYS_ADMIN)) {
2740 /* A different attribute in the security namespace.
2741 Restrict to administrator. */
2742 return -EPERM;
2743 }
2744 }
2745
2746 /* Not an attribute we recognize, so just check the
2747 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002748 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002749}
2750
David Howells8f0cfa52008-04-29 00:59:41 -07002751static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2752 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 struct inode *inode = dentry->d_inode;
2755 struct inode_security_struct *isec = inode->i_security;
2756 struct superblock_security_struct *sbsec;
2757 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002758 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 int rc = 0;
2760
Serge E. Hallynb5376772007-10-16 23:31:36 -07002761 if (strcmp(name, XATTR_NAME_SELINUX))
2762 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
2764 sbsec = inode->i_sb->s_security;
2765 if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
2766 return -EOPNOTSUPP;
2767
Satyam Sharma3bd858a2007-07-17 15:00:08 +05302768 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 return -EPERM;
2770
Eric Paris828dfe12008-04-17 13:17:49 -04002771 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002772 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
David Howells275bb412008-11-14 10:39:19 +11002774 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 FILE__RELABELFROM, &ad);
2776 if (rc)
2777 return rc;
2778
2779 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002780 if (rc == -EINVAL) {
2781 if (!capable(CAP_MAC_ADMIN))
2782 return rc;
2783 rc = security_context_to_sid_force(value, size, &newsid);
2784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 if (rc)
2786 return rc;
2787
David Howells275bb412008-11-14 10:39:19 +11002788 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 FILE__RELABELTO, &ad);
2790 if (rc)
2791 return rc;
2792
David Howells275bb412008-11-14 10:39:19 +11002793 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002794 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 if (rc)
2796 return rc;
2797
2798 return avc_has_perm(newsid,
2799 sbsec->sid,
2800 SECCLASS_FILESYSTEM,
2801 FILESYSTEM__ASSOCIATE,
2802 &ad);
2803}
2804
David Howells8f0cfa52008-04-29 00:59:41 -07002805static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002806 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002807 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808{
2809 struct inode *inode = dentry->d_inode;
2810 struct inode_security_struct *isec = inode->i_security;
2811 u32 newsid;
2812 int rc;
2813
2814 if (strcmp(name, XATTR_NAME_SELINUX)) {
2815 /* Not an attribute we recognize, so nothing to do. */
2816 return;
2817 }
2818
Stephen Smalley12b29f32008-05-07 13:03:20 -04002819 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002821 printk(KERN_ERR "SELinux: unable to map context to SID"
2822 "for (%s, %lu), rc=%d\n",
2823 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 return;
2825 }
2826
2827 isec->sid = newsid;
2828 return;
2829}
2830
David Howells8f0cfa52008-04-29 00:59:41 -07002831static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
David Howells88e67f32008-11-14 10:39:21 +11002833 const struct cred *cred = current_cred();
2834
2835 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836}
2837
Eric Paris828dfe12008-04-17 13:17:49 -04002838static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839{
David Howells88e67f32008-11-14 10:39:21 +11002840 const struct cred *cred = current_cred();
2841
2842 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843}
2844
David Howells8f0cfa52008-04-29 00:59:41 -07002845static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002847 if (strcmp(name, XATTR_NAME_SELINUX))
2848 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
2850 /* No one is allowed to remove a SELinux security label.
2851 You can change the label, but all data must be labeled. */
2852 return -EACCES;
2853}
2854
James Morrisd381d8a2005-10-30 14:59:22 -08002855/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002856 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002857 *
2858 * Permission check is handled by selinux_inode_getxattr hook.
2859 */
David P. Quigley42492592008-02-04 22:29:39 -08002860static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861{
David P. Quigley42492592008-02-04 22:29:39 -08002862 u32 size;
2863 int error;
2864 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002867 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2868 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002870 /*
2871 * If the caller has CAP_MAC_ADMIN, then get the raw context
2872 * value even if it is not defined by current policy; otherwise,
2873 * use the in-core value under current policy.
2874 * Use the non-auditing forms of the permission checks since
2875 * getxattr may be called by unprivileged processes commonly
2876 * and lack of permission just means that we fall back to the
2877 * in-core context value, not a denial.
2878 */
Eric Paris06674672008-11-11 22:02:57 +11002879 error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002880 if (!error)
2881 error = security_sid_to_context_force(isec->sid, &context,
2882 &size);
2883 else
2884 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002885 if (error)
2886 return error;
2887 error = size;
2888 if (alloc) {
2889 *buffer = context;
2890 goto out_nofree;
2891 }
2892 kfree(context);
2893out_nofree:
2894 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895}
2896
2897static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002898 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899{
2900 struct inode_security_struct *isec = inode->i_security;
2901 u32 newsid;
2902 int rc;
2903
2904 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2905 return -EOPNOTSUPP;
2906
2907 if (!value || !size)
2908 return -EACCES;
2909
Eric Paris828dfe12008-04-17 13:17:49 -04002910 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 if (rc)
2912 return rc;
2913
2914 isec->sid = newsid;
2915 return 0;
2916}
2917
2918static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2919{
2920 const int len = sizeof(XATTR_NAME_SELINUX);
2921 if (buffer && len <= buffer_size)
2922 memcpy(buffer, XATTR_NAME_SELINUX, len);
2923 return len;
2924}
2925
Serge E. Hallynb5376772007-10-16 23:31:36 -07002926static int selinux_inode_need_killpriv(struct dentry *dentry)
2927{
2928 return secondary_ops->inode_need_killpriv(dentry);
2929}
2930
2931static int selinux_inode_killpriv(struct dentry *dentry)
2932{
2933 return secondary_ops->inode_killpriv(dentry);
2934}
2935
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02002936static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2937{
2938 struct inode_security_struct *isec = inode->i_security;
2939 *secid = isec->sid;
2940}
2941
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942/* file security operations */
2943
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002944static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
David Howells88e67f32008-11-14 10:39:21 +11002946 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002947 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002948 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
2950 if (!mask) {
2951 /* No permission to check. Existence test. */
2952 return 0;
2953 }
2954
2955 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2956 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2957 mask |= MAY_APPEND;
2958
David Howells88e67f32008-11-14 10:39:21 +11002959 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002960 file_mask_to_av(inode->i_mode, mask));
2961 if (rc)
2962 return rc;
2963
2964 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965}
2966
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002967static int selinux_file_permission(struct file *file, int mask)
2968{
2969 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002970 struct file_security_struct *fsec = file->f_security;
2971 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11002972 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002973
2974 if (!mask) {
2975 /* No permission to check. Existence test. */
2976 return 0;
2977 }
2978
David Howells275bb412008-11-14 10:39:19 +11002979 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002980 && fsec->pseqno == avc_policy_seqno())
2981 return selinux_netlbl_inode_permission(inode, mask);
2982
2983 return selinux_revalidate_file_permission(file, mask);
2984}
2985
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986static int selinux_file_alloc_security(struct file *file)
2987{
2988 return file_alloc_security(file);
2989}
2990
2991static void selinux_file_free_security(struct file *file)
2992{
2993 file_free_security(file);
2994}
2995
2996static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2997 unsigned long arg)
2998{
David Howells88e67f32008-11-14 10:39:21 +11002999 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04003000 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
Stephen Smalley242631c2008-06-05 09:21:28 -04003002 if (_IOC_DIR(cmd) & _IOC_WRITE)
3003 av |= FILE__WRITE;
3004 if (_IOC_DIR(cmd) & _IOC_READ)
3005 av |= FILE__READ;
3006 if (!av)
3007 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
David Howells88e67f32008-11-14 10:39:21 +11003009 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010}
3011
3012static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3013{
David Howells88e67f32008-11-14 10:39:21 +11003014 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003015 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003016
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017#ifndef CONFIG_PPC32
3018 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3019 /*
3020 * We are making executable an anonymous mapping or a
3021 * private file mapping that will also be writable.
3022 * This has an additional check.
3023 */
David Howellsd84f4f92008-11-14 10:39:23 +11003024 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003026 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 }
3028#endif
3029
3030 if (file) {
3031 /* read access is always possible with a mapping */
3032 u32 av = FILE__READ;
3033
3034 /* write access only matters if the mapping is shared */
3035 if (shared && (prot & PROT_WRITE))
3036 av |= FILE__WRITE;
3037
3038 if (prot & PROT_EXEC)
3039 av |= FILE__EXECUTE;
3040
David Howells88e67f32008-11-14 10:39:21 +11003041 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 }
David Howellsd84f4f92008-11-14 10:39:23 +11003043
3044error:
3045 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046}
3047
3048static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003049 unsigned long prot, unsigned long flags,
3050 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051{
Eric Parised032182007-06-28 15:55:21 -04003052 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003053 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054
Eric Parised032182007-06-28 15:55:21 -04003055 if (addr < mmap_min_addr)
3056 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3057 MEMPROTECT__MMAP_ZERO, NULL);
3058 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 return rc;
3060
3061 if (selinux_checkreqprot)
3062 prot = reqprot;
3063
3064 return file_map_prot_check(file, prot,
3065 (flags & MAP_TYPE) == MAP_SHARED);
3066}
3067
3068static int selinux_file_mprotect(struct vm_area_struct *vma,
3069 unsigned long reqprot,
3070 unsigned long prot)
3071{
David Howells88e67f32008-11-14 10:39:21 +11003072 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 int rc;
3074
3075 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3076 if (rc)
3077 return rc;
3078
3079 if (selinux_checkreqprot)
3080 prot = reqprot;
3081
3082#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003083 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3084 rc = 0;
3085 if (vma->vm_start >= vma->vm_mm->start_brk &&
3086 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003087 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003088 } else if (!vma->vm_file &&
3089 vma->vm_start <= vma->vm_mm->start_stack &&
3090 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003091 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003092 } else if (vma->vm_file && vma->anon_vma) {
3093 /*
3094 * We are making executable a file mapping that has
3095 * had some COW done. Since pages might have been
3096 * written, check ability to execute the possibly
3097 * modified content. This typically should only
3098 * occur for text relocations.
3099 */
David Howellsd84f4f92008-11-14 10:39:23 +11003100 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003101 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003102 if (rc)
3103 return rc;
3104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105#endif
3106
3107 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3108}
3109
3110static int selinux_file_lock(struct file *file, unsigned int cmd)
3111{
David Howells88e67f32008-11-14 10:39:21 +11003112 const struct cred *cred = current_cred();
3113
3114 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115}
3116
3117static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3118 unsigned long arg)
3119{
David Howells88e67f32008-11-14 10:39:21 +11003120 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 int err = 0;
3122
3123 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003124 case F_SETFL:
3125 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3126 err = -EINVAL;
3127 break;
3128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129
Eric Paris828dfe12008-04-17 13:17:49 -04003130 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003131 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003133 }
3134 /* fall through */
3135 case F_SETOWN:
3136 case F_SETSIG:
3137 case F_GETFL:
3138 case F_GETOWN:
3139 case F_GETSIG:
3140 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003141 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003142 break;
3143 case F_GETLK:
3144 case F_SETLK:
3145 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003147 case F_GETLK64:
3148 case F_SETLK64:
3149 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003151 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3152 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003154 }
David Howells88e67f32008-11-14 10:39:21 +11003155 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003156 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 }
3158
3159 return err;
3160}
3161
3162static int selinux_file_set_fowner(struct file *file)
3163{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 struct file_security_struct *fsec;
3165
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003167 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
3169 return 0;
3170}
3171
3172static int selinux_file_send_sigiotask(struct task_struct *tsk,
3173 struct fown_struct *fown, int signum)
3174{
Eric Paris828dfe12008-04-17 13:17:49 -04003175 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003176 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 struct file_security_struct *fsec;
3179
3180 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003181 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 fsec = file->f_security;
3184
3185 if (!signum)
3186 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3187 else
3188 perm = signal_to_av(signum);
3189
David Howells275bb412008-11-14 10:39:19 +11003190 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 SECCLASS_PROCESS, perm, NULL);
3192}
3193
3194static int selinux_file_receive(struct file *file)
3195{
David Howells88e67f32008-11-14 10:39:21 +11003196 const struct cred *cred = current_cred();
3197
3198 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199}
3200
David Howells745ca242008-11-14 10:39:22 +11003201static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003202{
3203 struct file_security_struct *fsec;
3204 struct inode *inode;
3205 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003206
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003207 inode = file->f_path.dentry->d_inode;
3208 fsec = file->f_security;
3209 isec = inode->i_security;
3210 /*
3211 * Save inode label and policy sequence number
3212 * at open-time so that selinux_file_permission
3213 * can determine whether revalidation is necessary.
3214 * Task label is already saved in the file security
3215 * struct as its SID.
3216 */
3217 fsec->isid = isec->sid;
3218 fsec->pseqno = avc_policy_seqno();
3219 /*
3220 * Since the inode label or policy seqno may have changed
3221 * between the selinux_inode_permission check and the saving
3222 * of state above, recheck that access is still permitted.
3223 * Otherwise, access might never be revalidated against the
3224 * new inode label or new policy.
3225 * This check is not redundant - do not remove.
3226 */
David Howells88e67f32008-11-14 10:39:21 +11003227 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003228}
3229
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230/* task security operations */
3231
3232static int selinux_task_create(unsigned long clone_flags)
3233{
3234 int rc;
3235
3236 rc = secondary_ops->task_create(clone_flags);
3237 if (rc)
3238 return rc;
3239
David Howells3b11a1d2008-11-14 10:39:26 +11003240 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241}
3242
David Howellsf1752ee2008-11-14 10:39:17 +11003243/*
3244 * detach and free the LSM part of a set of credentials
3245 */
3246static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247{
David Howellsf1752ee2008-11-14 10:39:17 +11003248 struct task_security_struct *tsec = cred->security;
3249 cred->security = NULL;
3250 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251}
3252
David Howellsd84f4f92008-11-14 10:39:23 +11003253/*
3254 * prepare a new set of credentials for modification
3255 */
3256static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3257 gfp_t gfp)
3258{
3259 const struct task_security_struct *old_tsec;
3260 struct task_security_struct *tsec;
3261
3262 old_tsec = old->security;
3263
3264 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3265 if (!tsec)
3266 return -ENOMEM;
3267
3268 new->security = tsec;
3269 return 0;
3270}
3271
3272/*
3273 * commit new credentials
3274 */
3275static void selinux_cred_commit(struct cred *new, const struct cred *old)
3276{
3277 secondary_ops->cred_commit(new, old);
3278}
3279
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3281{
3282 /* Since setuid only affects the current process, and
3283 since the SELinux controls are not based on the Linux
3284 identity attributes, SELinux does not need to control
3285 this operation. However, SELinux does control the use
3286 of the CAP_SETUID and CAP_SETGID capabilities using the
3287 capable hook. */
3288 return 0;
3289}
3290
David Howellsd84f4f92008-11-14 10:39:23 +11003291static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3292 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293{
David Howellsd84f4f92008-11-14 10:39:23 +11003294 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295}
3296
3297static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3298{
3299 /* See the comment for setuid above. */
3300 return 0;
3301}
3302
3303static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3304{
David Howells3b11a1d2008-11-14 10:39:26 +11003305 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306}
3307
3308static int selinux_task_getpgid(struct task_struct *p)
3309{
David Howells3b11a1d2008-11-14 10:39:26 +11003310 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311}
3312
3313static int selinux_task_getsid(struct task_struct *p)
3314{
David Howells3b11a1d2008-11-14 10:39:26 +11003315 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316}
3317
David Quigleyf9008e42006-06-30 01:55:46 -07003318static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3319{
David Howells275bb412008-11-14 10:39:19 +11003320 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003321}
3322
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323static int selinux_task_setgroups(struct group_info *group_info)
3324{
3325 /* See the comment for setuid above. */
3326 return 0;
3327}
3328
3329static int selinux_task_setnice(struct task_struct *p, int nice)
3330{
3331 int rc;
3332
3333 rc = secondary_ops->task_setnice(p, nice);
3334 if (rc)
3335 return rc;
3336
David Howells3b11a1d2008-11-14 10:39:26 +11003337 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338}
3339
James Morris03e68062006-06-23 02:03:58 -07003340static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3341{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003342 int rc;
3343
3344 rc = secondary_ops->task_setioprio(p, ioprio);
3345 if (rc)
3346 return rc;
3347
David Howells3b11a1d2008-11-14 10:39:26 +11003348 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003349}
3350
David Quigleya1836a42006-06-30 01:55:49 -07003351static int selinux_task_getioprio(struct task_struct *p)
3352{
David Howells3b11a1d2008-11-14 10:39:26 +11003353 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003354}
3355
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3357{
3358 struct rlimit *old_rlim = current->signal->rlim + resource;
3359 int rc;
3360
3361 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3362 if (rc)
3363 return rc;
3364
3365 /* Control the ability to change the hard limit (whether
3366 lowering or raising it), so that the hard limit can
3367 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003368 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003370 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
3372 return 0;
3373}
3374
3375static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3376{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003377 int rc;
3378
3379 rc = secondary_ops->task_setscheduler(p, policy, lp);
3380 if (rc)
3381 return rc;
3382
David Howells3b11a1d2008-11-14 10:39:26 +11003383 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384}
3385
3386static int selinux_task_getscheduler(struct task_struct *p)
3387{
David Howells3b11a1d2008-11-14 10:39:26 +11003388 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389}
3390
David Quigley35601542006-06-23 02:04:01 -07003391static int selinux_task_movememory(struct task_struct *p)
3392{
David Howells3b11a1d2008-11-14 10:39:26 +11003393 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003394}
3395
David Quigleyf9008e42006-06-30 01:55:46 -07003396static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3397 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398{
3399 u32 perm;
3400 int rc;
3401
David Quigleyf9008e42006-06-30 01:55:46 -07003402 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 if (rc)
3404 return rc;
3405
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 if (!sig)
3407 perm = PROCESS__SIGNULL; /* null signal; existence test */
3408 else
3409 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003410 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003411 rc = avc_has_perm(secid, task_sid(p),
3412 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003413 else
David Howells3b11a1d2008-11-14 10:39:26 +11003414 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003415 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416}
3417
3418static int selinux_task_prctl(int option,
3419 unsigned long arg2,
3420 unsigned long arg3,
3421 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003422 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423{
3424 /* The current prctl operations do not appear to require
3425 any SELinux controls since they merely observe or modify
3426 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003427 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428}
3429
3430static int selinux_task_wait(struct task_struct *p)
3431{
Eric Paris8a535142007-10-22 16:10:31 -04003432 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433}
3434
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435static void selinux_task_to_inode(struct task_struct *p,
3436 struct inode *inode)
3437{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003439 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440
David Howells275bb412008-11-14 10:39:19 +11003441 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443}
3444
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003446static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3447 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
3449 int offset, ihlen, ret = -EINVAL;
3450 struct iphdr _iph, *ih;
3451
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003452 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3454 if (ih == NULL)
3455 goto out;
3456
3457 ihlen = ih->ihl * 4;
3458 if (ihlen < sizeof(_iph))
3459 goto out;
3460
3461 ad->u.net.v4info.saddr = ih->saddr;
3462 ad->u.net.v4info.daddr = ih->daddr;
3463 ret = 0;
3464
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003465 if (proto)
3466 *proto = ih->protocol;
3467
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003469 case IPPROTO_TCP: {
3470 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
Eric Paris828dfe12008-04-17 13:17:49 -04003472 if (ntohs(ih->frag_off) & IP_OFFSET)
3473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474
3475 offset += ihlen;
3476 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3477 if (th == NULL)
3478 break;
3479
3480 ad->u.net.sport = th->source;
3481 ad->u.net.dport = th->dest;
3482 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
Eric Paris828dfe12008-04-17 13:17:49 -04003485 case IPPROTO_UDP: {
3486 struct udphdr _udph, *uh;
3487
3488 if (ntohs(ih->frag_off) & IP_OFFSET)
3489 break;
3490
3491 offset += ihlen;
3492 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3493 if (uh == NULL)
3494 break;
3495
3496 ad->u.net.sport = uh->source;
3497 ad->u.net.dport = uh->dest;
3498 break;
3499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
James Morris2ee92d42006-11-13 16:09:01 -08003501 case IPPROTO_DCCP: {
3502 struct dccp_hdr _dccph, *dh;
3503
3504 if (ntohs(ih->frag_off) & IP_OFFSET)
3505 break;
3506
3507 offset += ihlen;
3508 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3509 if (dh == NULL)
3510 break;
3511
3512 ad->u.net.sport = dh->dccph_sport;
3513 ad->u.net.dport = dh->dccph_dport;
3514 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003515 }
James Morris2ee92d42006-11-13 16:09:01 -08003516
Eric Paris828dfe12008-04-17 13:17:49 -04003517 default:
3518 break;
3519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520out:
3521 return ret;
3522}
3523
3524#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3525
3526/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003527static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3528 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529{
3530 u8 nexthdr;
3531 int ret = -EINVAL, offset;
3532 struct ipv6hdr _ipv6h, *ip6;
3533
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003534 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3536 if (ip6 == NULL)
3537 goto out;
3538
3539 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3540 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3541 ret = 0;
3542
3543 nexthdr = ip6->nexthdr;
3544 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003545 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 if (offset < 0)
3547 goto out;
3548
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003549 if (proto)
3550 *proto = nexthdr;
3551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 switch (nexthdr) {
3553 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003554 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
3556 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3557 if (th == NULL)
3558 break;
3559
3560 ad->u.net.sport = th->source;
3561 ad->u.net.dport = th->dest;
3562 break;
3563 }
3564
3565 case IPPROTO_UDP: {
3566 struct udphdr _udph, *uh;
3567
3568 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3569 if (uh == NULL)
3570 break;
3571
3572 ad->u.net.sport = uh->source;
3573 ad->u.net.dport = uh->dest;
3574 break;
3575 }
3576
James Morris2ee92d42006-11-13 16:09:01 -08003577 case IPPROTO_DCCP: {
3578 struct dccp_hdr _dccph, *dh;
3579
3580 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3581 if (dh == NULL)
3582 break;
3583
3584 ad->u.net.sport = dh->dccph_sport;
3585 ad->u.net.dport = dh->dccph_dport;
3586 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003587 }
James Morris2ee92d42006-11-13 16:09:01 -08003588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 /* includes fragments */
3590 default:
3591 break;
3592 }
3593out:
3594 return ret;
3595}
3596
3597#endif /* IPV6 */
3598
3599static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003600 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601{
David Howellscf9481e2008-07-27 21:31:07 +10003602 char *addrp;
3603 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604
3605 switch (ad->u.net.family) {
3606 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003607 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003608 if (ret)
3609 goto parse_error;
3610 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3611 &ad->u.net.v4info.daddr);
3612 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613
3614#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3615 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003616 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003617 if (ret)
3618 goto parse_error;
3619 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3620 &ad->u.net.v6info.daddr);
3621 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622#endif /* IPV6 */
3623 default:
David Howellscf9481e2008-07-27 21:31:07 +10003624 addrp = NULL;
3625 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 }
3627
David Howellscf9481e2008-07-27 21:31:07 +10003628parse_error:
3629 printk(KERN_WARNING
3630 "SELinux: failure in selinux_parse_skb(),"
3631 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003633
3634okay:
3635 if (_addrp)
3636 *_addrp = addrp;
3637 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638}
3639
Paul Moore4f6a9932007-03-01 14:35:22 -05003640/**
Paul Moore220deb92008-01-29 08:38:23 -05003641 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003642 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003643 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003644 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003645 *
3646 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003647 * Check the various different forms of network peer labeling and determine
3648 * the peer label/SID for the packet; most of the magic actually occurs in
3649 * the security server function security_net_peersid_cmp(). The function
3650 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3651 * or -EACCES if @sid is invalid due to inconsistencies with the different
3652 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003653 *
3654 */
Paul Moore220deb92008-01-29 08:38:23 -05003655static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003656{
Paul Moore71f1cb02008-01-29 08:51:16 -05003657 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003658 u32 xfrm_sid;
3659 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003660 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003661
3662 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003663 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003664
Paul Moore71f1cb02008-01-29 08:51:16 -05003665 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3666 if (unlikely(err)) {
3667 printk(KERN_WARNING
3668 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3669 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003670 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003671 }
Paul Moore220deb92008-01-29 08:38:23 -05003672
3673 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003674}
3675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676/* socket security operations */
3677static int socket_has_perm(struct task_struct *task, struct socket *sock,
3678 u32 perms)
3679{
3680 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003682 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 int err = 0;
3684
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 isec = SOCK_INODE(sock)->i_security;
3686
3687 if (isec->sid == SECINITSID_KERNEL)
3688 goto out;
David Howells275bb412008-11-14 10:39:19 +11003689 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
Eric Paris828dfe12008-04-17 13:17:49 -04003691 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003693 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694
3695out:
3696 return err;
3697}
3698
3699static int selinux_socket_create(int family, int type,
3700 int protocol, int kern)
3701{
David Howells275bb412008-11-14 10:39:19 +11003702 const struct cred *cred = current_cred();
3703 const struct task_security_struct *tsec = cred->security;
3704 u32 sid, newsid;
3705 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707
3708 if (kern)
3709 goto out;
3710
David Howells275bb412008-11-14 10:39:19 +11003711 sid = tsec->sid;
3712 newsid = tsec->sockcreate_sid ?: sid;
3713
3714 secclass = socket_type_to_security_class(family, type, protocol);
3715 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
3717out:
3718 return err;
3719}
3720
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003721static int selinux_socket_post_create(struct socket *sock, int family,
3722 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723{
David Howells275bb412008-11-14 10:39:19 +11003724 const struct cred *cred = current_cred();
3725 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003727 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003728 u32 sid, newsid;
3729 int err = 0;
3730
3731 sid = tsec->sid;
3732 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
3734 isec = SOCK_INODE(sock)->i_security;
3735
David Howells275bb412008-11-14 10:39:19 +11003736 if (kern)
3737 isec->sid = SECINITSID_KERNEL;
3738 else if (newsid)
3739 isec->sid = newsid;
3740 else
3741 isec->sid = sid;
3742
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 isec->initialized = 1;
3745
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003746 if (sock->sk) {
3747 sksec = sock->sk->sk_security;
3748 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003749 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003750 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003751 }
3752
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003753 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754}
3755
3756/* Range of port numbers used to automatically bind.
3757 Need to determine whether we should perform a name_bind
3758 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759
3760static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3761{
3762 u16 family;
3763 int err;
3764
3765 err = socket_has_perm(current, sock, SOCKET__BIND);
3766 if (err)
3767 goto out;
3768
3769 /*
3770 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003771 * Multiple address binding for SCTP is not supported yet: we just
3772 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 */
3774 family = sock->sk->sk_family;
3775 if (family == PF_INET || family == PF_INET6) {
3776 char *addrp;
3777 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 struct avc_audit_data ad;
3779 struct sockaddr_in *addr4 = NULL;
3780 struct sockaddr_in6 *addr6 = NULL;
3781 unsigned short snum;
3782 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003783 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 isec = SOCK_INODE(sock)->i_security;
3786
3787 if (family == PF_INET) {
3788 addr4 = (struct sockaddr_in *)address;
3789 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 addrp = (char *)&addr4->sin_addr.s_addr;
3791 } else {
3792 addr6 = (struct sockaddr_in6 *)address;
3793 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 addrp = (char *)&addr6->sin6_addr.s6_addr;
3795 }
3796
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003797 if (snum) {
3798 int low, high;
3799
3800 inet_get_local_port_range(&low, &high);
3801
3802 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003803 err = sel_netport_sid(sk->sk_protocol,
3804 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003805 if (err)
3806 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003807 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003808 ad.u.net.sport = htons(snum);
3809 ad.u.net.family = family;
3810 err = avc_has_perm(isec->sid, sid,
3811 isec->sclass,
3812 SOCKET__NAME_BIND, &ad);
3813 if (err)
3814 goto out;
3815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 }
Eric Paris828dfe12008-04-17 13:17:49 -04003817
3818 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003819 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 node_perm = TCP_SOCKET__NODE_BIND;
3821 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003822
James Morris13402582005-09-30 14:24:34 -04003823 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 node_perm = UDP_SOCKET__NODE_BIND;
3825 break;
James Morris2ee92d42006-11-13 16:09:01 -08003826
3827 case SECCLASS_DCCP_SOCKET:
3828 node_perm = DCCP_SOCKET__NODE_BIND;
3829 break;
3830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 default:
3832 node_perm = RAWIP_SOCKET__NODE_BIND;
3833 break;
3834 }
Eric Paris828dfe12008-04-17 13:17:49 -04003835
Paul Moore224dfbd2008-01-29 08:38:13 -05003836 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 if (err)
3838 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003839
3840 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 ad.u.net.sport = htons(snum);
3842 ad.u.net.family = family;
3843
3844 if (family == PF_INET)
3845 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3846 else
3847 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3848
3849 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003850 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 if (err)
3852 goto out;
3853 }
3854out:
3855 return err;
3856}
3857
3858static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3859{
Paul Moore014ab192008-10-10 10:16:33 -04003860 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 struct inode_security_struct *isec;
3862 int err;
3863
3864 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3865 if (err)
3866 return err;
3867
3868 /*
James Morris2ee92d42006-11-13 16:09:01 -08003869 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 */
3871 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003872 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3873 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 struct avc_audit_data ad;
3875 struct sockaddr_in *addr4 = NULL;
3876 struct sockaddr_in6 *addr6 = NULL;
3877 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003878 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
3880 if (sk->sk_family == PF_INET) {
3881 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003882 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 return -EINVAL;
3884 snum = ntohs(addr4->sin_port);
3885 } else {
3886 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003887 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 return -EINVAL;
3889 snum = ntohs(addr6->sin6_port);
3890 }
3891
Paul Moore3e112172008-04-10 10:48:14 -04003892 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 if (err)
3894 goto out;
3895
James Morris2ee92d42006-11-13 16:09:01 -08003896 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3897 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3898
Eric Paris828dfe12008-04-17 13:17:49 -04003899 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 ad.u.net.dport = htons(snum);
3901 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003902 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 if (err)
3904 goto out;
3905 }
3906
Paul Moore014ab192008-10-10 10:16:33 -04003907 err = selinux_netlbl_socket_connect(sk, address);
3908
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909out:
3910 return err;
3911}
3912
3913static int selinux_socket_listen(struct socket *sock, int backlog)
3914{
3915 return socket_has_perm(current, sock, SOCKET__LISTEN);
3916}
3917
3918static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3919{
3920 int err;
3921 struct inode_security_struct *isec;
3922 struct inode_security_struct *newisec;
3923
3924 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3925 if (err)
3926 return err;
3927
3928 newisec = SOCK_INODE(newsock)->i_security;
3929
3930 isec = SOCK_INODE(sock)->i_security;
3931 newisec->sclass = isec->sclass;
3932 newisec->sid = isec->sid;
3933 newisec->initialized = 1;
3934
3935 return 0;
3936}
3937
3938static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003939 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003941 int rc;
3942
3943 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3944 if (rc)
3945 return rc;
3946
3947 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948}
3949
3950static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3951 int size, int flags)
3952{
3953 return socket_has_perm(current, sock, SOCKET__READ);
3954}
3955
3956static int selinux_socket_getsockname(struct socket *sock)
3957{
3958 return socket_has_perm(current, sock, SOCKET__GETATTR);
3959}
3960
3961static int selinux_socket_getpeername(struct socket *sock)
3962{
3963 return socket_has_perm(current, sock, SOCKET__GETATTR);
3964}
3965
Eric Paris828dfe12008-04-17 13:17:49 -04003966static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967{
Paul Mooref8687af2006-10-30 15:22:15 -08003968 int err;
3969
3970 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3971 if (err)
3972 return err;
3973
3974 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975}
3976
3977static int selinux_socket_getsockopt(struct socket *sock, int level,
3978 int optname)
3979{
3980 return socket_has_perm(current, sock, SOCKET__GETOPT);
3981}
3982
3983static int selinux_socket_shutdown(struct socket *sock, int how)
3984{
3985 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
3986}
3987
3988static int selinux_socket_unix_stream_connect(struct socket *sock,
3989 struct socket *other,
3990 struct sock *newsk)
3991{
3992 struct sk_security_struct *ssec;
3993 struct inode_security_struct *isec;
3994 struct inode_security_struct *other_isec;
3995 struct avc_audit_data ad;
3996 int err;
3997
3998 err = secondary_ops->unix_stream_connect(sock, other, newsk);
3999 if (err)
4000 return err;
4001
4002 isec = SOCK_INODE(sock)->i_security;
4003 other_isec = SOCK_INODE(other)->i_security;
4004
Eric Paris828dfe12008-04-17 13:17:49 -04004005 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 ad.u.net.sk = other->sk;
4007
4008 err = avc_has_perm(isec->sid, other_isec->sid,
4009 isec->sclass,
4010 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4011 if (err)
4012 return err;
4013
4014 /* connecting socket */
4015 ssec = sock->sk->sk_security;
4016 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004017
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 /* server child socket */
4019 ssec = newsk->sk_security;
4020 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004021 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4022
4023 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024}
4025
4026static int selinux_socket_unix_may_send(struct socket *sock,
4027 struct socket *other)
4028{
4029 struct inode_security_struct *isec;
4030 struct inode_security_struct *other_isec;
4031 struct avc_audit_data ad;
4032 int err;
4033
4034 isec = SOCK_INODE(sock)->i_security;
4035 other_isec = SOCK_INODE(other)->i_security;
4036
Eric Paris828dfe12008-04-17 13:17:49 -04004037 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 ad.u.net.sk = other->sk;
4039
4040 err = avc_has_perm(isec->sid, other_isec->sid,
4041 isec->sclass, SOCKET__SENDTO, &ad);
4042 if (err)
4043 return err;
4044
4045 return 0;
4046}
4047
Paul Mooreeffad8d2008-01-29 08:49:27 -05004048static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4049 u32 peer_sid,
4050 struct avc_audit_data *ad)
4051{
4052 int err;
4053 u32 if_sid;
4054 u32 node_sid;
4055
4056 err = sel_netif_sid(ifindex, &if_sid);
4057 if (err)
4058 return err;
4059 err = avc_has_perm(peer_sid, if_sid,
4060 SECCLASS_NETIF, NETIF__INGRESS, ad);
4061 if (err)
4062 return err;
4063
4064 err = sel_netnode_sid(addrp, family, &node_sid);
4065 if (err)
4066 return err;
4067 return avc_has_perm(peer_sid, node_sid,
4068 SECCLASS_NODE, NODE__RECVFROM, ad);
4069}
4070
Paul Moore220deb92008-01-29 08:38:23 -05004071static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4072 struct sk_buff *skb,
4073 struct avc_audit_data *ad,
4074 u16 family,
4075 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076{
Paul Moore220deb92008-01-29 08:38:23 -05004077 int err;
4078 struct sk_security_struct *sksec = sk->sk_security;
4079 u16 sk_class;
4080 u32 netif_perm, node_perm, recv_perm;
4081 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004082
Paul Moore220deb92008-01-29 08:38:23 -05004083 sk_sid = sksec->sid;
4084 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085
Paul Moore220deb92008-01-29 08:38:23 -05004086 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 case SECCLASS_UDP_SOCKET:
4088 netif_perm = NETIF__UDP_RECV;
4089 node_perm = NODE__UDP_RECV;
4090 recv_perm = UDP_SOCKET__RECV_MSG;
4091 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 case SECCLASS_TCP_SOCKET:
4093 netif_perm = NETIF__TCP_RECV;
4094 node_perm = NODE__TCP_RECV;
4095 recv_perm = TCP_SOCKET__RECV_MSG;
4096 break;
James Morris2ee92d42006-11-13 16:09:01 -08004097 case SECCLASS_DCCP_SOCKET:
4098 netif_perm = NETIF__DCCP_RECV;
4099 node_perm = NODE__DCCP_RECV;
4100 recv_perm = DCCP_SOCKET__RECV_MSG;
4101 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 default:
4103 netif_perm = NETIF__RAWIP_RECV;
4104 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004105 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 break;
4107 }
4108
Paul Moore220deb92008-01-29 08:38:23 -05004109 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004111 return err;
4112 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4113 if (err)
4114 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004115
Paul Moore224dfbd2008-01-29 08:38:13 -05004116 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004118 return err;
4119 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004121 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
Paul Moore220deb92008-01-29 08:38:23 -05004123 if (!recv_perm)
4124 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004125 err = sel_netport_sid(sk->sk_protocol,
4126 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004127 if (unlikely(err)) {
4128 printk(KERN_WARNING
4129 "SELinux: failure in"
4130 " selinux_sock_rcv_skb_iptables_compat(),"
4131 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004132 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004133 }
Paul Moore220deb92008-01-29 08:38:23 -05004134 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4135}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136
Paul Moore220deb92008-01-29 08:38:23 -05004137static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004138 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004139{
4140 int err;
4141 struct sk_security_struct *sksec = sk->sk_security;
4142 u32 peer_sid;
4143 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004144 struct avc_audit_data ad;
4145 char *addrp;
4146
4147 AVC_AUDIT_DATA_INIT(&ad, NET);
4148 ad.u.net.netif = skb->iif;
4149 ad.u.net.family = family;
4150 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4151 if (err)
4152 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004153
4154 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004155 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004156 family, addrp);
4157 else
4158 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004159 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004160 if (err)
4161 return err;
4162
4163 if (selinux_policycap_netpeer) {
4164 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004166 return err;
4167 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004168 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004169 if (err)
4170 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004171 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004172 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004173 if (err)
4174 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004175 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004177
James Morris4e5ab4c2006-06-09 00:33:33 -07004178 return err;
4179}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004180
James Morris4e5ab4c2006-06-09 00:33:33 -07004181static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4182{
Paul Moore220deb92008-01-29 08:38:23 -05004183 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004184 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004185 u16 family = sk->sk_family;
4186 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004187 struct avc_audit_data ad;
4188 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004189 u8 secmark_active;
4190 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004191
James Morris4e5ab4c2006-06-09 00:33:33 -07004192 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004193 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004194
4195 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004196 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004197 family = PF_INET;
4198
Paul Moored8395c82008-10-10 10:16:30 -04004199 /* If any sort of compatibility mode is enabled then handoff processing
4200 * to the selinux_sock_rcv_skb_compat() function to deal with the
4201 * special handling. We do this in an attempt to keep this function
4202 * as fast and as clean as possible. */
4203 if (selinux_compat_net || !selinux_policycap_netpeer)
4204 return selinux_sock_rcv_skb_compat(sk, skb, family);
4205
4206 secmark_active = selinux_secmark_enabled();
4207 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4208 if (!secmark_active && !peerlbl_active)
4209 return 0;
4210
James Morris4e5ab4c2006-06-09 00:33:33 -07004211 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004212 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004213 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004214 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004215 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004216 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004217
Paul Moored8395c82008-10-10 10:16:30 -04004218 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004219 u32 peer_sid;
4220
4221 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4222 if (err)
4223 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004224 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4225 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004226 if (err) {
4227 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004228 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004229 }
Paul Moored621d352008-01-29 08:43:36 -05004230 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4231 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004232 if (err)
4233 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004234 }
4235
Paul Moored8395c82008-10-10 10:16:30 -04004236 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004237 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4238 PACKET__RECV, &ad);
4239 if (err)
4240 return err;
4241 }
4242
Paul Moored621d352008-01-29 08:43:36 -05004243 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244}
4245
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004246static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4247 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248{
4249 int err = 0;
4250 char *scontext;
4251 u32 scontext_len;
4252 struct sk_security_struct *ssec;
4253 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004254 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255
4256 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004257
Paul Moore3de4bab2006-11-17 17:38:54 -05004258 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4259 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004260 ssec = sock->sk->sk_security;
4261 peer_sid = ssec->peer_sid;
4262 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004263 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 err = -ENOPROTOOPT;
4265 goto out;
4266 }
4267
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004268 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4269
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 if (err)
4271 goto out;
4272
4273 if (scontext_len > len) {
4274 err = -ERANGE;
4275 goto out_len;
4276 }
4277
4278 if (copy_to_user(optval, scontext, scontext_len))
4279 err = -EFAULT;
4280
4281out_len:
4282 if (put_user(scontext_len, optlen))
4283 err = -EFAULT;
4284
4285 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004286out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 return err;
4288}
4289
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004290static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004291{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004292 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004293 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004294
Paul Mooreaa862902008-10-10 10:16:29 -04004295 if (skb && skb->protocol == htons(ETH_P_IP))
4296 family = PF_INET;
4297 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4298 family = PF_INET6;
4299 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004300 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004301 else
4302 goto out;
4303
4304 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02004305 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004306 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004307 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004308
Paul Moore75e22912008-01-29 08:38:04 -05004309out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004310 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004311 if (peer_secid == SECSID_NULL)
4312 return -EINVAL;
4313 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004314}
4315
Al Viro7d877f32005-10-21 03:20:43 -04004316static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317{
4318 return sk_alloc_security(sk, family, priority);
4319}
4320
4321static void selinux_sk_free_security(struct sock *sk)
4322{
4323 sk_free_security(sk);
4324}
4325
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004326static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4327{
4328 struct sk_security_struct *ssec = sk->sk_security;
4329 struct sk_security_struct *newssec = newsk->sk_security;
4330
4331 newssec->sid = ssec->sid;
4332 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004333 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004334
Paul Mooref74af6e2008-02-25 11:40:33 -05004335 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004336}
4337
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004338static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004339{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004340 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004341 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004342 else {
4343 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004344
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004345 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004346 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004347}
4348
Eric Paris828dfe12008-04-17 13:17:49 -04004349static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004350{
4351 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4352 struct sk_security_struct *sksec = sk->sk_security;
4353
David Woodhouse2148ccc2006-09-29 15:50:25 -07004354 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4355 sk->sk_family == PF_UNIX)
4356 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004357 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004358}
4359
Adrian Bunk9a673e52006-08-15 00:03:53 -07004360static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4361 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004362{
4363 struct sk_security_struct *sksec = sk->sk_security;
4364 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004365 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004366 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004367 u32 peersid;
4368
Paul Mooreaa862902008-10-10 10:16:29 -04004369 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4370 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4371 family = PF_INET;
4372
4373 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004374 if (err)
4375 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004376 if (peersid == SECSID_NULL) {
4377 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004378 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004379 return 0;
4380 }
4381
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004382 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4383 if (err)
4384 return err;
4385
4386 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004387 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004388 return 0;
4389}
4390
Adrian Bunk9a673e52006-08-15 00:03:53 -07004391static void selinux_inet_csk_clone(struct sock *newsk,
4392 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004393{
4394 struct sk_security_struct *newsksec = newsk->sk_security;
4395
4396 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004397 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004398 /* NOTE: Ideally, we should also get the isec->sid for the
4399 new socket in sync, but we don't have the isec available yet.
4400 So we will wait until sock_graft to do it, by which
4401 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004402
Paul Moore9f2ad662006-11-17 17:38:53 -05004403 /* We don't need to take any sort of lock here as we are the only
4404 * thread with access to newsksec */
4405 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004406}
4407
Paul Moore014ab192008-10-10 10:16:33 -04004408static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004409{
Paul Mooreaa862902008-10-10 10:16:29 -04004410 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004411 struct sk_security_struct *sksec = sk->sk_security;
4412
Paul Mooreaa862902008-10-10 10:16:29 -04004413 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4414 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4415 family = PF_INET;
4416
4417 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004418
4419 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004420}
4421
Adrian Bunk9a673e52006-08-15 00:03:53 -07004422static void selinux_req_classify_flow(const struct request_sock *req,
4423 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004424{
4425 fl->secid = req->secid;
4426}
4427
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4429{
4430 int err = 0;
4431 u32 perm;
4432 struct nlmsghdr *nlh;
4433 struct socket *sock = sk->sk_socket;
4434 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004435
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 if (skb->len < NLMSG_SPACE(0)) {
4437 err = -EINVAL;
4438 goto out;
4439 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004440 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004441
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4443 if (err) {
4444 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004445 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 "SELinux: unrecognized netlink message"
4447 " type=%hu for sclass=%hu\n",
4448 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004449 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 err = 0;
4451 }
4452
4453 /* Ignore */
4454 if (err == -ENOENT)
4455 err = 0;
4456 goto out;
4457 }
4458
4459 err = socket_has_perm(current, sock, perm);
4460out:
4461 return err;
4462}
4463
4464#ifdef CONFIG_NETFILTER
4465
Paul Mooreeffad8d2008-01-29 08:49:27 -05004466static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4467 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468{
Paul Mooredfaebe92008-10-10 10:16:31 -04004469 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004470 char *addrp;
4471 u32 peer_sid;
4472 struct avc_audit_data ad;
4473 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004474 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004475 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004476
Paul Mooreeffad8d2008-01-29 08:49:27 -05004477 if (!selinux_policycap_netpeer)
4478 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004479
Paul Mooreeffad8d2008-01-29 08:49:27 -05004480 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004481 netlbl_active = netlbl_enabled();
4482 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004483 if (!secmark_active && !peerlbl_active)
4484 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004485
Paul Moored8395c82008-10-10 10:16:30 -04004486 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4487 return NF_DROP;
4488
Paul Mooreeffad8d2008-01-29 08:49:27 -05004489 AVC_AUDIT_DATA_INIT(&ad, NET);
4490 ad.u.net.netif = ifindex;
4491 ad.u.net.family = family;
4492 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4493 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Paul Mooredfaebe92008-10-10 10:16:31 -04004495 if (peerlbl_active) {
4496 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4497 peer_sid, &ad);
4498 if (err) {
4499 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004500 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004501 }
4502 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004503
4504 if (secmark_active)
4505 if (avc_has_perm(peer_sid, skb->secmark,
4506 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4507 return NF_DROP;
4508
Paul Moore948bf852008-10-10 10:16:32 -04004509 if (netlbl_active)
4510 /* we do this in the FORWARD path and not the POST_ROUTING
4511 * path because we want to make sure we apply the necessary
4512 * labeling before IPsec is applied so we can leverage AH
4513 * protection */
4514 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4515 return NF_DROP;
4516
Paul Mooreeffad8d2008-01-29 08:49:27 -05004517 return NF_ACCEPT;
4518}
4519
4520static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4521 struct sk_buff *skb,
4522 const struct net_device *in,
4523 const struct net_device *out,
4524 int (*okfn)(struct sk_buff *))
4525{
4526 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4527}
4528
4529#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4530static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4531 struct sk_buff *skb,
4532 const struct net_device *in,
4533 const struct net_device *out,
4534 int (*okfn)(struct sk_buff *))
4535{
4536 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4537}
4538#endif /* IPV6 */
4539
Paul Moore948bf852008-10-10 10:16:32 -04004540static unsigned int selinux_ip_output(struct sk_buff *skb,
4541 u16 family)
4542{
4543 u32 sid;
4544
4545 if (!netlbl_enabled())
4546 return NF_ACCEPT;
4547
4548 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4549 * because we want to make sure we apply the necessary labeling
4550 * before IPsec is applied so we can leverage AH protection */
4551 if (skb->sk) {
4552 struct sk_security_struct *sksec = skb->sk->sk_security;
4553 sid = sksec->sid;
4554 } else
4555 sid = SECINITSID_KERNEL;
4556 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4557 return NF_DROP;
4558
4559 return NF_ACCEPT;
4560}
4561
4562static unsigned int selinux_ipv4_output(unsigned int hooknum,
4563 struct sk_buff *skb,
4564 const struct net_device *in,
4565 const struct net_device *out,
4566 int (*okfn)(struct sk_buff *))
4567{
4568 return selinux_ip_output(skb, PF_INET);
4569}
4570
Paul Mooreeffad8d2008-01-29 08:49:27 -05004571static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4572 int ifindex,
4573 struct avc_audit_data *ad,
4574 u16 family, char *addrp)
4575{
4576 int err;
4577 struct sk_security_struct *sksec = sk->sk_security;
4578 u16 sk_class;
4579 u32 netif_perm, node_perm, send_perm;
4580 u32 port_sid, node_sid, if_sid, sk_sid;
4581
4582 sk_sid = sksec->sid;
4583 sk_class = sksec->sclass;
4584
4585 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 case SECCLASS_UDP_SOCKET:
4587 netif_perm = NETIF__UDP_SEND;
4588 node_perm = NODE__UDP_SEND;
4589 send_perm = UDP_SOCKET__SEND_MSG;
4590 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 case SECCLASS_TCP_SOCKET:
4592 netif_perm = NETIF__TCP_SEND;
4593 node_perm = NODE__TCP_SEND;
4594 send_perm = TCP_SOCKET__SEND_MSG;
4595 break;
James Morris2ee92d42006-11-13 16:09:01 -08004596 case SECCLASS_DCCP_SOCKET:
4597 netif_perm = NETIF__DCCP_SEND;
4598 node_perm = NODE__DCCP_SEND;
4599 send_perm = DCCP_SOCKET__SEND_MSG;
4600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 default:
4602 netif_perm = NETIF__RAWIP_SEND;
4603 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004604 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 break;
4606 }
4607
Paul Mooreeffad8d2008-01-29 08:49:27 -05004608 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004609 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004610 return err;
4611 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4612 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004613
Paul Moore224dfbd2008-01-29 08:38:13 -05004614 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004615 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004616 return err;
4617 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004618 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004619 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Paul Mooreeffad8d2008-01-29 08:49:27 -05004621 if (send_perm != 0)
4622 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
Paul Moore3e112172008-04-10 10:48:14 -04004624 err = sel_netport_sid(sk->sk_protocol,
4625 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004626 if (unlikely(err)) {
4627 printk(KERN_WARNING
4628 "SELinux: failure in"
4629 " selinux_ip_postroute_iptables_compat(),"
4630 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004631 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004632 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004633 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004634}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635
Paul Mooreeffad8d2008-01-29 08:49:27 -05004636static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4637 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004638 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004639{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004640 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004641 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004642 struct avc_audit_data ad;
4643 char *addrp;
4644 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004645
Paul Mooreeffad8d2008-01-29 08:49:27 -05004646 if (sk == NULL)
4647 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004648 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004649
Paul Moored8395c82008-10-10 10:16:30 -04004650 AVC_AUDIT_DATA_INIT(&ad, NET);
4651 ad.u.net.netif = ifindex;
4652 ad.u.net.family = family;
4653 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4654 return NF_DROP;
4655
Paul Mooreeffad8d2008-01-29 08:49:27 -05004656 if (selinux_compat_net) {
4657 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004658 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004659 return NF_DROP;
4660 } else {
4661 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004662 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004663 return NF_DROP;
4664 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004665
Paul Mooreeffad8d2008-01-29 08:49:27 -05004666 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004667 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004668 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004669
Paul Mooreeffad8d2008-01-29 08:49:27 -05004670 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671}
4672
Paul Mooreeffad8d2008-01-29 08:49:27 -05004673static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4674 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004676 u32 secmark_perm;
4677 u32 peer_sid;
4678 struct sock *sk;
4679 struct avc_audit_data ad;
4680 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004681 u8 secmark_active;
4682 u8 peerlbl_active;
4683
Paul Mooreeffad8d2008-01-29 08:49:27 -05004684 /* If any sort of compatibility mode is enabled then handoff processing
4685 * to the selinux_ip_postroute_compat() function to deal with the
4686 * special handling. We do this in an attempt to keep this function
4687 * as fast and as clean as possible. */
4688 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004689 return selinux_ip_postroute_compat(skb, ifindex, family);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004690
4691 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4692 * packet transformation so allow the packet to pass without any checks
4693 * since we'll have another chance to perform access control checks
4694 * when the packet is on it's final way out.
4695 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4696 * is NULL, in this case go ahead and apply access control. */
4697 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4698 return NF_ACCEPT;
4699
4700 secmark_active = selinux_secmark_enabled();
4701 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4702 if (!secmark_active && !peerlbl_active)
4703 return NF_ACCEPT;
4704
Paul Moored8395c82008-10-10 10:16:30 -04004705 /* if the packet is being forwarded then get the peer label from the
4706 * packet itself; otherwise check to see if it is from a local
4707 * application or the kernel, if from an application get the peer label
4708 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004709 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004710 if (sk == NULL) {
4711 switch (family) {
4712 case PF_INET:
4713 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4714 secmark_perm = PACKET__FORWARD_OUT;
4715 else
4716 secmark_perm = PACKET__SEND;
4717 break;
4718 case PF_INET6:
4719 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4720 secmark_perm = PACKET__FORWARD_OUT;
4721 else
4722 secmark_perm = PACKET__SEND;
4723 break;
4724 default:
4725 return NF_DROP;
4726 }
4727 if (secmark_perm == PACKET__FORWARD_OUT) {
4728 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4729 return NF_DROP;
4730 } else
4731 peer_sid = SECINITSID_KERNEL;
4732 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004733 struct sk_security_struct *sksec = sk->sk_security;
4734 peer_sid = sksec->sid;
4735 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004736 }
4737
Paul Moored8395c82008-10-10 10:16:30 -04004738 AVC_AUDIT_DATA_INIT(&ad, NET);
4739 ad.u.net.netif = ifindex;
4740 ad.u.net.family = family;
4741 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4742 return NF_DROP;
4743
Paul Mooreeffad8d2008-01-29 08:49:27 -05004744 if (secmark_active)
4745 if (avc_has_perm(peer_sid, skb->secmark,
4746 SECCLASS_PACKET, secmark_perm, &ad))
4747 return NF_DROP;
4748
4749 if (peerlbl_active) {
4750 u32 if_sid;
4751 u32 node_sid;
4752
4753 if (sel_netif_sid(ifindex, &if_sid))
4754 return NF_DROP;
4755 if (avc_has_perm(peer_sid, if_sid,
4756 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4757 return NF_DROP;
4758
4759 if (sel_netnode_sid(addrp, family, &node_sid))
4760 return NF_DROP;
4761 if (avc_has_perm(peer_sid, node_sid,
4762 SECCLASS_NODE, NODE__SENDTO, &ad))
4763 return NF_DROP;
4764 }
4765
4766 return NF_ACCEPT;
4767}
4768
4769static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4770 struct sk_buff *skb,
4771 const struct net_device *in,
4772 const struct net_device *out,
4773 int (*okfn)(struct sk_buff *))
4774{
4775 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776}
4777
4778#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004779static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4780 struct sk_buff *skb,
4781 const struct net_device *in,
4782 const struct net_device *out,
4783 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004785 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787#endif /* IPV6 */
4788
4789#endif /* CONFIG_NETFILTER */
4790
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4792{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 int err;
4794
4795 err = secondary_ops->netlink_send(sk, skb);
4796 if (err)
4797 return err;
4798
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4800 err = selinux_nlmsg_perm(sk, skb);
4801
4802 return err;
4803}
4804
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004805static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004807 int err;
4808 struct avc_audit_data ad;
4809
4810 err = secondary_ops->netlink_recv(skb, capability);
4811 if (err)
4812 return err;
4813
4814 AVC_AUDIT_DATA_INIT(&ad, CAP);
4815 ad.u.cap = capability;
4816
4817 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004818 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819}
4820
4821static int ipc_alloc_security(struct task_struct *task,
4822 struct kern_ipc_perm *perm,
4823 u16 sclass)
4824{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004826 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
James Morris89d155e2005-10-30 14:59:21 -08004828 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 if (!isec)
4830 return -ENOMEM;
4831
David Howells275bb412008-11-14 10:39:19 +11004832 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004834 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 perm->security = isec;
4836
4837 return 0;
4838}
4839
4840static void ipc_free_security(struct kern_ipc_perm *perm)
4841{
4842 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 perm->security = NULL;
4844 kfree(isec);
4845}
4846
4847static int msg_msg_alloc_security(struct msg_msg *msg)
4848{
4849 struct msg_security_struct *msec;
4850
James Morris89d155e2005-10-30 14:59:21 -08004851 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 if (!msec)
4853 return -ENOMEM;
4854
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 msec->sid = SECINITSID_UNLABELED;
4856 msg->security = msec;
4857
4858 return 0;
4859}
4860
4861static void msg_msg_free_security(struct msg_msg *msg)
4862{
4863 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
4865 msg->security = NULL;
4866 kfree(msec);
4867}
4868
4869static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004870 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 struct ipc_security_struct *isec;
4873 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004874 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 isec = ipc_perms->security;
4877
4878 AVC_AUDIT_DATA_INIT(&ad, IPC);
4879 ad.u.ipc_id = ipc_perms->key;
4880
David Howells275bb412008-11-14 10:39:19 +11004881 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882}
4883
4884static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4885{
4886 return msg_msg_alloc_security(msg);
4887}
4888
4889static void selinux_msg_msg_free_security(struct msg_msg *msg)
4890{
4891 msg_msg_free_security(msg);
4892}
4893
4894/* message queue security operations */
4895static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4896{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 struct ipc_security_struct *isec;
4898 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004899 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 int rc;
4901
4902 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4903 if (rc)
4904 return rc;
4905
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 isec = msq->q_perm.security;
4907
4908 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004909 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910
David Howells275bb412008-11-14 10:39:19 +11004911 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 MSGQ__CREATE, &ad);
4913 if (rc) {
4914 ipc_free_security(&msq->q_perm);
4915 return rc;
4916 }
4917 return 0;
4918}
4919
4920static void selinux_msg_queue_free_security(struct msg_queue *msq)
4921{
4922 ipc_free_security(&msq->q_perm);
4923}
4924
4925static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4926{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 struct ipc_security_struct *isec;
4928 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004929 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 isec = msq->q_perm.security;
4932
4933 AVC_AUDIT_DATA_INIT(&ad, IPC);
4934 ad.u.ipc_id = msq->q_perm.key;
4935
David Howells275bb412008-11-14 10:39:19 +11004936 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 MSGQ__ASSOCIATE, &ad);
4938}
4939
4940static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4941{
4942 int err;
4943 int perms;
4944
Eric Paris828dfe12008-04-17 13:17:49 -04004945 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 case IPC_INFO:
4947 case MSG_INFO:
4948 /* No specific object, just general system-wide information. */
4949 return task_has_system(current, SYSTEM__IPC_INFO);
4950 case IPC_STAT:
4951 case MSG_STAT:
4952 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4953 break;
4954 case IPC_SET:
4955 perms = MSGQ__SETATTR;
4956 break;
4957 case IPC_RMID:
4958 perms = MSGQ__DESTROY;
4959 break;
4960 default:
4961 return 0;
4962 }
4963
Stephen Smalley6af963f2005-05-01 08:58:39 -07004964 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 return err;
4966}
4967
4968static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4969{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970 struct ipc_security_struct *isec;
4971 struct msg_security_struct *msec;
4972 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004973 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 int rc;
4975
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 isec = msq->q_perm.security;
4977 msec = msg->security;
4978
4979 /*
4980 * First time through, need to assign label to the message
4981 */
4982 if (msec->sid == SECINITSID_UNLABELED) {
4983 /*
4984 * Compute new sid based on current process and
4985 * message queue this message will be stored in
4986 */
David Howells275bb412008-11-14 10:39:19 +11004987 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 &msec->sid);
4989 if (rc)
4990 return rc;
4991 }
4992
4993 AVC_AUDIT_DATA_INIT(&ad, IPC);
4994 ad.u.ipc_id = msq->q_perm.key;
4995
4996 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004997 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 MSGQ__WRITE, &ad);
4999 if (!rc)
5000 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005001 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5002 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 if (!rc)
5004 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005005 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5006 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007
5008 return rc;
5009}
5010
5011static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5012 struct task_struct *target,
5013 long type, int mode)
5014{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 struct ipc_security_struct *isec;
5016 struct msg_security_struct *msec;
5017 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005018 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 int rc;
5020
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 isec = msq->q_perm.security;
5022 msec = msg->security;
5023
5024 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005025 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026
David Howells275bb412008-11-14 10:39:19 +11005027 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 SECCLASS_MSGQ, MSGQ__READ, &ad);
5029 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005030 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 SECCLASS_MSG, MSG__RECEIVE, &ad);
5032 return rc;
5033}
5034
5035/* Shared Memory security operations */
5036static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5037{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 struct ipc_security_struct *isec;
5039 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005040 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 int rc;
5042
5043 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5044 if (rc)
5045 return rc;
5046
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 isec = shp->shm_perm.security;
5048
5049 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005050 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
David Howells275bb412008-11-14 10:39:19 +11005052 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 SHM__CREATE, &ad);
5054 if (rc) {
5055 ipc_free_security(&shp->shm_perm);
5056 return rc;
5057 }
5058 return 0;
5059}
5060
5061static void selinux_shm_free_security(struct shmid_kernel *shp)
5062{
5063 ipc_free_security(&shp->shm_perm);
5064}
5065
5066static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5067{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 struct ipc_security_struct *isec;
5069 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005070 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 isec = shp->shm_perm.security;
5073
5074 AVC_AUDIT_DATA_INIT(&ad, IPC);
5075 ad.u.ipc_id = shp->shm_perm.key;
5076
David Howells275bb412008-11-14 10:39:19 +11005077 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 SHM__ASSOCIATE, &ad);
5079}
5080
5081/* Note, at this point, shp is locked down */
5082static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5083{
5084 int perms;
5085 int err;
5086
Eric Paris828dfe12008-04-17 13:17:49 -04005087 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 case IPC_INFO:
5089 case SHM_INFO:
5090 /* No specific object, just general system-wide information. */
5091 return task_has_system(current, SYSTEM__IPC_INFO);
5092 case IPC_STAT:
5093 case SHM_STAT:
5094 perms = SHM__GETATTR | SHM__ASSOCIATE;
5095 break;
5096 case IPC_SET:
5097 perms = SHM__SETATTR;
5098 break;
5099 case SHM_LOCK:
5100 case SHM_UNLOCK:
5101 perms = SHM__LOCK;
5102 break;
5103 case IPC_RMID:
5104 perms = SHM__DESTROY;
5105 break;
5106 default:
5107 return 0;
5108 }
5109
Stephen Smalley6af963f2005-05-01 08:58:39 -07005110 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 return err;
5112}
5113
5114static int selinux_shm_shmat(struct shmid_kernel *shp,
5115 char __user *shmaddr, int shmflg)
5116{
5117 u32 perms;
5118 int rc;
5119
5120 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5121 if (rc)
5122 return rc;
5123
5124 if (shmflg & SHM_RDONLY)
5125 perms = SHM__READ;
5126 else
5127 perms = SHM__READ | SHM__WRITE;
5128
Stephen Smalley6af963f2005-05-01 08:58:39 -07005129 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130}
5131
5132/* Semaphore security operations */
5133static int selinux_sem_alloc_security(struct sem_array *sma)
5134{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 struct ipc_security_struct *isec;
5136 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005137 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 int rc;
5139
5140 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5141 if (rc)
5142 return rc;
5143
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 isec = sma->sem_perm.security;
5145
5146 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005147 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148
David Howells275bb412008-11-14 10:39:19 +11005149 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 SEM__CREATE, &ad);
5151 if (rc) {
5152 ipc_free_security(&sma->sem_perm);
5153 return rc;
5154 }
5155 return 0;
5156}
5157
5158static void selinux_sem_free_security(struct sem_array *sma)
5159{
5160 ipc_free_security(&sma->sem_perm);
5161}
5162
5163static int selinux_sem_associate(struct sem_array *sma, int semflg)
5164{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 struct ipc_security_struct *isec;
5166 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005167 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 isec = sma->sem_perm.security;
5170
5171 AVC_AUDIT_DATA_INIT(&ad, IPC);
5172 ad.u.ipc_id = sma->sem_perm.key;
5173
David Howells275bb412008-11-14 10:39:19 +11005174 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 SEM__ASSOCIATE, &ad);
5176}
5177
5178/* Note, at this point, sma is locked down */
5179static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5180{
5181 int err;
5182 u32 perms;
5183
Eric Paris828dfe12008-04-17 13:17:49 -04005184 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 case IPC_INFO:
5186 case SEM_INFO:
5187 /* No specific object, just general system-wide information. */
5188 return task_has_system(current, SYSTEM__IPC_INFO);
5189 case GETPID:
5190 case GETNCNT:
5191 case GETZCNT:
5192 perms = SEM__GETATTR;
5193 break;
5194 case GETVAL:
5195 case GETALL:
5196 perms = SEM__READ;
5197 break;
5198 case SETVAL:
5199 case SETALL:
5200 perms = SEM__WRITE;
5201 break;
5202 case IPC_RMID:
5203 perms = SEM__DESTROY;
5204 break;
5205 case IPC_SET:
5206 perms = SEM__SETATTR;
5207 break;
5208 case IPC_STAT:
5209 case SEM_STAT:
5210 perms = SEM__GETATTR | SEM__ASSOCIATE;
5211 break;
5212 default:
5213 return 0;
5214 }
5215
Stephen Smalley6af963f2005-05-01 08:58:39 -07005216 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 return err;
5218}
5219
5220static int selinux_sem_semop(struct sem_array *sma,
5221 struct sembuf *sops, unsigned nsops, int alter)
5222{
5223 u32 perms;
5224
5225 if (alter)
5226 perms = SEM__READ | SEM__WRITE;
5227 else
5228 perms = SEM__READ;
5229
Stephen Smalley6af963f2005-05-01 08:58:39 -07005230 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231}
5232
5233static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5234{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 u32 av = 0;
5236
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 av = 0;
5238 if (flag & S_IRUGO)
5239 av |= IPC__UNIX_READ;
5240 if (flag & S_IWUGO)
5241 av |= IPC__UNIX_WRITE;
5242
5243 if (av == 0)
5244 return 0;
5245
Stephen Smalley6af963f2005-05-01 08:58:39 -07005246 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247}
5248
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02005249static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5250{
5251 struct ipc_security_struct *isec = ipcp->security;
5252 *secid = isec->sid;
5253}
5254
Eric Paris828dfe12008-04-17 13:17:49 -04005255static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256{
5257 if (inode)
5258 inode_doinit_with_dentry(inode, dentry);
5259}
5260
5261static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005262 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263{
David Howells275bb412008-11-14 10:39:19 +11005264 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005265 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005267 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
5269 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005270 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 if (error)
5272 return error;
5273 }
5274
David Howells275bb412008-11-14 10:39:19 +11005275 rcu_read_lock();
5276 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
5278 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005279 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005281 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005283 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005285 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005286 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005287 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005288 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005289 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 else
David Howells275bb412008-11-14 10:39:19 +11005291 goto invalid;
5292 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293
5294 if (!sid)
5295 return 0;
5296
Al Viro04ff9702007-03-12 16:17:58 +00005297 error = security_sid_to_context(sid, value, &len);
5298 if (error)
5299 return error;
5300 return len;
David Howells275bb412008-11-14 10:39:19 +11005301
5302invalid:
5303 rcu_read_unlock();
5304 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305}
5306
5307static int selinux_setprocattr(struct task_struct *p,
5308 char *name, void *value, size_t size)
5309{
5310 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005311 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005312 struct cred *new;
5313 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 int error;
5315 char *str = value;
5316
5317 if (current != p) {
5318 /* SELinux only allows a process to change its own
5319 security attributes. */
5320 return -EACCES;
5321 }
5322
5323 /*
5324 * Basic control over ability to set these attributes at all.
5325 * current == p, but we'll pass them separately in case the
5326 * above restriction is ever removed.
5327 */
5328 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005329 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005331 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005332 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005333 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005334 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005335 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005337 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 else
5339 error = -EINVAL;
5340 if (error)
5341 return error;
5342
5343 /* Obtain a SID for the context, if one was specified. */
5344 if (size && str[1] && str[1] != '\n') {
5345 if (str[size-1] == '\n') {
5346 str[size-1] = 0;
5347 size--;
5348 }
5349 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005350 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5351 if (!capable(CAP_MAC_ADMIN))
5352 return error;
5353 error = security_context_to_sid_force(value, size,
5354 &sid);
5355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 if (error)
5357 return error;
5358 }
5359
David Howellsd84f4f92008-11-14 10:39:23 +11005360 new = prepare_creds();
5361 if (!new)
5362 return -ENOMEM;
5363
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 /* Permission checking based on the specified context is
5365 performed during the actual operation (execve,
5366 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005367 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 checks and may_create for the file creation checks. The
5369 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005370 tsec = new->security;
5371 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005373 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005375 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005376 error = may_create_key(sid, p);
5377 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005378 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005379 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005380 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005381 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005382 } else if (!strcmp(name, "current")) {
5383 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005385 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005386
David Howellsd84f4f92008-11-14 10:39:23 +11005387 /* Only allow single threaded processes to change context */
5388 error = -EPERM;
5389 if (!is_single_threaded(p)) {
5390 error = security_bounded_transition(tsec->sid, sid);
5391 if (error)
5392 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394
5395 /* Check permissions for the transition. */
5396 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005397 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005399 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
5401 /* Check for ptracing, and update the task SID if ok.
5402 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005403 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005405 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005406 if (tracer)
5407 ptsid = task_sid(tracer);
5408 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409
David Howellsd84f4f92008-11-14 10:39:23 +11005410 if (tracer) {
5411 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5412 PROCESS__PTRACE, NULL);
5413 if (error)
5414 goto abort_change;
5415 }
5416
5417 tsec->sid = sid;
5418 } else {
5419 error = -EINVAL;
5420 goto abort_change;
5421 }
5422
5423 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005425
5426abort_change:
5427 abort_creds(new);
5428 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429}
5430
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005431static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5432{
5433 return security_sid_to_context(secid, secdata, seclen);
5434}
5435
David Howells7bf570d2008-04-29 20:52:51 +01005436static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005437{
5438 return security_context_to_sid(secdata, seclen, secid);
5439}
5440
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005441static void selinux_release_secctx(char *secdata, u32 seclen)
5442{
Paul Moore088999e2007-08-01 11:12:58 -04005443 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005444}
5445
Michael LeMayd7200242006-06-22 14:47:17 -07005446#ifdef CONFIG_KEYS
5447
David Howellsd84f4f92008-11-14 10:39:23 +11005448static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005449 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005450{
David Howellsd84f4f92008-11-14 10:39:23 +11005451 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005452 struct key_security_struct *ksec;
5453
5454 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5455 if (!ksec)
5456 return -ENOMEM;
5457
David Howellsd84f4f92008-11-14 10:39:23 +11005458 tsec = cred->security;
5459 if (tsec->keycreate_sid)
5460 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005461 else
David Howellsd84f4f92008-11-14 10:39:23 +11005462 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005463
David Howells275bb412008-11-14 10:39:19 +11005464 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005465 return 0;
5466}
5467
5468static void selinux_key_free(struct key *k)
5469{
5470 struct key_security_struct *ksec = k->security;
5471
5472 k->security = NULL;
5473 kfree(ksec);
5474}
5475
5476static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005477 const struct cred *cred,
5478 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005479{
5480 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005481 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005482 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005483
5484 /* if no specific permissions are requested, we skip the
5485 permission check. No serious, additional covert channels
5486 appear to be created. */
5487 if (perm == 0)
5488 return 0;
5489
David Howellsd84f4f92008-11-14 10:39:23 +11005490 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005491
5492 key = key_ref_to_ptr(key_ref);
5493 ksec = key->security;
5494
5495 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005496}
5497
David Howells70a5bb72008-04-29 01:01:26 -07005498static int selinux_key_getsecurity(struct key *key, char **_buffer)
5499{
5500 struct key_security_struct *ksec = key->security;
5501 char *context = NULL;
5502 unsigned len;
5503 int rc;
5504
5505 rc = security_sid_to_context(ksec->sid, &context, &len);
5506 if (!rc)
5507 rc = len;
5508 *_buffer = context;
5509 return rc;
5510}
5511
Michael LeMayd7200242006-06-22 14:47:17 -07005512#endif
5513
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005515 .name = "selinux",
5516
David Howells5cd9c582008-08-14 11:37:28 +01005517 .ptrace_may_access = selinux_ptrace_may_access,
5518 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005520 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 .sysctl = selinux_sysctl,
5522 .capable = selinux_capable,
5523 .quotactl = selinux_quotactl,
5524 .quota_on = selinux_quota_on,
5525 .syslog = selinux_syslog,
5526 .vm_enough_memory = selinux_vm_enough_memory,
5527
5528 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005529 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530
David Howellsa6f76f22008-11-14 10:39:24 +11005531 .bprm_set_creds = selinux_bprm_set_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 .bprm_check_security = selinux_bprm_check_security,
David Howellsa6f76f22008-11-14 10:39:24 +11005533 .bprm_committing_creds = selinux_bprm_committing_creds,
5534 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 .bprm_secureexec = selinux_bprm_secureexec,
5536
5537 .sb_alloc_security = selinux_sb_alloc_security,
5538 .sb_free_security = selinux_sb_free_security,
5539 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005540 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005541 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 .sb_statfs = selinux_sb_statfs,
5543 .sb_mount = selinux_mount,
5544 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005545 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005546 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005547 .sb_parse_opts_str = selinux_parse_opts_str,
5548
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549
5550 .inode_alloc_security = selinux_inode_alloc_security,
5551 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005552 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 .inode_unlink = selinux_inode_unlink,
5556 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 .inode_rmdir = selinux_inode_rmdir,
5559 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 .inode_readlink = selinux_inode_readlink,
5562 .inode_follow_link = selinux_inode_follow_link,
5563 .inode_permission = selinux_inode_permission,
5564 .inode_setattr = selinux_inode_setattr,
5565 .inode_getattr = selinux_inode_getattr,
5566 .inode_setxattr = selinux_inode_setxattr,
5567 .inode_post_setxattr = selinux_inode_post_setxattr,
5568 .inode_getxattr = selinux_inode_getxattr,
5569 .inode_listxattr = selinux_inode_listxattr,
5570 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005571 .inode_getsecurity = selinux_inode_getsecurity,
5572 .inode_setsecurity = selinux_inode_setsecurity,
5573 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005574 .inode_need_killpriv = selinux_inode_need_killpriv,
5575 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005576 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
5578 .file_permission = selinux_file_permission,
5579 .file_alloc_security = selinux_file_alloc_security,
5580 .file_free_security = selinux_file_free_security,
5581 .file_ioctl = selinux_file_ioctl,
5582 .file_mmap = selinux_file_mmap,
5583 .file_mprotect = selinux_file_mprotect,
5584 .file_lock = selinux_file_lock,
5585 .file_fcntl = selinux_file_fcntl,
5586 .file_set_fowner = selinux_file_set_fowner,
5587 .file_send_sigiotask = selinux_file_send_sigiotask,
5588 .file_receive = selinux_file_receive,
5589
Eric Paris828dfe12008-04-17 13:17:49 -04005590 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005591
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005593 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005594 .cred_prepare = selinux_cred_prepare,
5595 .cred_commit = selinux_cred_commit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005597 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 .task_setgid = selinux_task_setgid,
5599 .task_setpgid = selinux_task_setpgid,
5600 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005601 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005602 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 .task_setgroups = selinux_task_setgroups,
5604 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005605 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005606 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 .task_setrlimit = selinux_task_setrlimit,
5608 .task_setscheduler = selinux_task_setscheduler,
5609 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005610 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 .task_kill = selinux_task_kill,
5612 .task_wait = selinux_task_wait,
5613 .task_prctl = selinux_task_prctl,
Eric Paris828dfe12008-04-17 13:17:49 -04005614 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615
5616 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005617 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618
5619 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5620 .msg_msg_free_security = selinux_msg_msg_free_security,
5621
5622 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5623 .msg_queue_free_security = selinux_msg_queue_free_security,
5624 .msg_queue_associate = selinux_msg_queue_associate,
5625 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5626 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5627 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5628
5629 .shm_alloc_security = selinux_shm_alloc_security,
5630 .shm_free_security = selinux_shm_free_security,
5631 .shm_associate = selinux_shm_associate,
5632 .shm_shmctl = selinux_shm_shmctl,
5633 .shm_shmat = selinux_shm_shmat,
5634
Eric Paris828dfe12008-04-17 13:17:49 -04005635 .sem_alloc_security = selinux_sem_alloc_security,
5636 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .sem_associate = selinux_sem_associate,
5638 .sem_semctl = selinux_sem_semctl,
5639 .sem_semop = selinux_sem_semop,
5640
Eric Paris828dfe12008-04-17 13:17:49 -04005641 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642
Eric Paris828dfe12008-04-17 13:17:49 -04005643 .getprocattr = selinux_getprocattr,
5644 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005646 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005647 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005648 .release_secctx = selinux_release_secctx,
5649
Eric Paris828dfe12008-04-17 13:17:49 -04005650 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 .unix_may_send = selinux_socket_unix_may_send,
5652
5653 .socket_create = selinux_socket_create,
5654 .socket_post_create = selinux_socket_post_create,
5655 .socket_bind = selinux_socket_bind,
5656 .socket_connect = selinux_socket_connect,
5657 .socket_listen = selinux_socket_listen,
5658 .socket_accept = selinux_socket_accept,
5659 .socket_sendmsg = selinux_socket_sendmsg,
5660 .socket_recvmsg = selinux_socket_recvmsg,
5661 .socket_getsockname = selinux_socket_getsockname,
5662 .socket_getpeername = selinux_socket_getpeername,
5663 .socket_getsockopt = selinux_socket_getsockopt,
5664 .socket_setsockopt = selinux_socket_setsockopt,
5665 .socket_shutdown = selinux_socket_shutdown,
5666 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005667 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5668 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 .sk_alloc_security = selinux_sk_alloc_security,
5670 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005671 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005672 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005673 .sock_graft = selinux_sock_graft,
5674 .inet_conn_request = selinux_inet_conn_request,
5675 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005676 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005677 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005678
5679#ifdef CONFIG_SECURITY_NETWORK_XFRM
5680 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5681 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5682 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005683 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005684 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5685 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005686 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005687 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005688 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005689 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005691
5692#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005693 .key_alloc = selinux_key_alloc,
5694 .key_free = selinux_key_free,
5695 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005696 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005697#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005698
5699#ifdef CONFIG_AUDIT
5700 .audit_rule_init = selinux_audit_rule_init,
5701 .audit_rule_known = selinux_audit_rule_known,
5702 .audit_rule_match = selinux_audit_rule_match,
5703 .audit_rule_free = selinux_audit_rule_free,
5704#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705};
5706
5707static __init int selinux_init(void)
5708{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005709 if (!security_module_enable(&selinux_ops)) {
5710 selinux_enabled = 0;
5711 return 0;
5712 }
5713
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 if (!selinux_enabled) {
5715 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5716 return 0;
5717 }
5718
5719 printk(KERN_INFO "SELinux: Initializing.\n");
5720
5721 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005722 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
James Morris7cae7e22006-03-22 00:09:22 -08005724 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5725 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005726 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 avc_init();
5728
James Morris6f0f0fd2008-07-10 17:02:07 +09005729 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005731 panic("SELinux: No initial security operations\n");
5732 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 panic("SELinux: Unable to register with kernel.\n");
5734
Eric Paris828dfe12008-04-17 13:17:49 -04005735 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005736 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005737 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005738 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005739
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 return 0;
5741}
5742
5743void selinux_complete_init(void)
5744{
Eric Parisfadcdb42007-02-22 18:11:31 -05005745 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746
5747 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005748 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005749 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 spin_lock(&sb_security_lock);
5751next_sb:
5752 if (!list_empty(&superblock_security_head)) {
5753 struct superblock_security_struct *sbsec =
5754 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005755 struct superblock_security_struct,
5756 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005760 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 down_read(&sb->s_umount);
5762 if (sb->s_root)
5763 superblock_doinit(sb, NULL);
5764 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005765 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 spin_lock(&sb_security_lock);
5767 list_del_init(&sbsec->list);
5768 goto next_sb;
5769 }
5770 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005771 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772}
5773
5774/* SELinux requires early initialization in order to label
5775 all processes and objects when they are created. */
5776security_initcall(selinux_init);
5777
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005778#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779
Paul Mooreeffad8d2008-01-29 08:49:27 -05005780static struct nf_hook_ops selinux_ipv4_ops[] = {
5781 {
5782 .hook = selinux_ipv4_postroute,
5783 .owner = THIS_MODULE,
5784 .pf = PF_INET,
5785 .hooknum = NF_INET_POST_ROUTING,
5786 .priority = NF_IP_PRI_SELINUX_LAST,
5787 },
5788 {
5789 .hook = selinux_ipv4_forward,
5790 .owner = THIS_MODULE,
5791 .pf = PF_INET,
5792 .hooknum = NF_INET_FORWARD,
5793 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005794 },
5795 {
5796 .hook = selinux_ipv4_output,
5797 .owner = THIS_MODULE,
5798 .pf = PF_INET,
5799 .hooknum = NF_INET_LOCAL_OUT,
5800 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802};
5803
5804#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5805
Paul Mooreeffad8d2008-01-29 08:49:27 -05005806static struct nf_hook_ops selinux_ipv6_ops[] = {
5807 {
5808 .hook = selinux_ipv6_postroute,
5809 .owner = THIS_MODULE,
5810 .pf = PF_INET6,
5811 .hooknum = NF_INET_POST_ROUTING,
5812 .priority = NF_IP6_PRI_SELINUX_LAST,
5813 },
5814 {
5815 .hook = selinux_ipv6_forward,
5816 .owner = THIS_MODULE,
5817 .pf = PF_INET6,
5818 .hooknum = NF_INET_FORWARD,
5819 .priority = NF_IP6_PRI_SELINUX_FIRST,
5820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821};
5822
5823#endif /* IPV6 */
5824
5825static int __init selinux_nf_ip_init(void)
5826{
5827 int err = 0;
5828
5829 if (!selinux_enabled)
5830 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005831
5832 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5833
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005834 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5835 if (err)
5836 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837
5838#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005839 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5840 if (err)
5841 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005843
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844out:
5845 return err;
5846}
5847
5848__initcall(selinux_nf_ip_init);
5849
5850#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5851static void selinux_nf_ip_exit(void)
5852{
Eric Parisfadcdb42007-02-22 18:11:31 -05005853 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005855 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005857 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858#endif /* IPV6 */
5859}
5860#endif
5861
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005862#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863
5864#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5865#define selinux_nf_ip_exit()
5866#endif
5867
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005868#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
5870#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005871static int selinux_disabled;
5872
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873int selinux_disable(void)
5874{
5875 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
5877 if (ss_initialized) {
5878 /* Not permitted after initial policy load. */
5879 return -EINVAL;
5880 }
5881
5882 if (selinux_disabled) {
5883 /* Only do this once. */
5884 return -EINVAL;
5885 }
5886
5887 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5888
5889 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005890 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891
5892 /* Reset security_ops to the secondary module, dummy or capability. */
5893 security_ops = secondary_ops;
5894
5895 /* Unregister netfilter hooks. */
5896 selinux_nf_ip_exit();
5897
5898 /* Unregister selinuxfs. */
5899 exit_sel_fs();
5900
5901 return 0;
5902}
5903#endif