blob: 08b506846a1f007af9b8c260da39e46ee00492b8 [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
David P. Quigley11689d42009-01-16 09:22:03 -050092#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050093
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,
David P. Quigley11689d42009-01-16 09:22:03 -0500356 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357};
358
Steven Whitehousea447c092008-10-13 10:46:57 +0100359static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400360 {Opt_context, CONTEXT_STR "%s"},
361 {Opt_fscontext, FSCONTEXT_STR "%s"},
362 {Opt_defcontext, DEFCONTEXT_STR "%s"},
363 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500364 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400365 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366};
367
368#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
369
Eric Parisc312feb2006-07-10 04:43:53 -0700370static int may_context_mount_sb_relabel(u32 sid,
371 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100372 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700373{
David Howells275bb412008-11-14 10:39:19 +1100374 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700375 int rc;
376
377 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
378 FILESYSTEM__RELABELFROM, NULL);
379 if (rc)
380 return rc;
381
382 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
383 FILESYSTEM__RELABELTO, NULL);
384 return rc;
385}
386
Eric Paris08089252006-07-10 04:43:55 -0700387static int may_context_mount_inode_relabel(u32 sid,
388 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100389 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700390{
David Howells275bb412008-11-14 10:39:19 +1100391 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700392 int rc;
393 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
394 FILESYSTEM__RELABELFROM, NULL);
395 if (rc)
396 return rc;
397
398 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
399 FILESYSTEM__ASSOCIATE, NULL);
400 return rc;
401}
402
Eric Parisc9180a52007-11-30 13:00:35 -0500403static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 struct superblock_security_struct *sbsec = sb->s_security;
406 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500407 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 int rc = 0;
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
411 /* Make sure that the xattr handler exists and that no
412 error other than -ENODATA is returned by getxattr on
413 the root directory. -ENODATA is ok, as this may be
414 the first boot of the SELinux kernel before we have
415 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500416 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
418 "xattr support\n", sb->s_id, sb->s_type->name);
419 rc = -EOPNOTSUPP;
420 goto out;
421 }
Eric Parisc9180a52007-11-30 13:00:35 -0500422 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 if (rc < 0 && rc != -ENODATA) {
424 if (rc == -EOPNOTSUPP)
425 printk(KERN_WARNING "SELinux: (dev %s, type "
426 "%s) has no security xattr handler\n",
427 sb->s_id, sb->s_type->name);
428 else
429 printk(KERN_WARNING "SELinux: (dev %s, type "
430 "%s) getxattr errno %d\n", sb->s_id,
431 sb->s_type->name, -rc);
432 goto out;
433 }
434 }
435
David P. Quigley11689d42009-01-16 09:22:03 -0500436 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Eric Parisc9180a52007-11-30 13:00:35 -0500438 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500439 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500441 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500442 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sb->s_id, sb->s_type->name,
444 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
David P. Quigley11689d42009-01-16 09:22:03 -0500446 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
447 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
448 sbsec->behavior == SECURITY_FS_USE_NONE ||
449 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
450 sbsec->flags &= ~SE_SBLABELSUPP;
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500453 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 /* Initialize any other inodes associated with the superblock, e.g.
456 inodes created prior to initial policy load or inodes created
457 during get_sb by a pseudo filesystem that directly
458 populates itself. */
459 spin_lock(&sbsec->isec_lock);
460next_inode:
461 if (!list_empty(&sbsec->isec_head)) {
462 struct inode_security_struct *isec =
463 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500464 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 struct inode *inode = isec->inode;
466 spin_unlock(&sbsec->isec_lock);
467 inode = igrab(inode);
468 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500469 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 inode_doinit(inode);
471 iput(inode);
472 }
473 spin_lock(&sbsec->isec_lock);
474 list_del_init(&isec->list);
475 goto next_inode;
476 }
477 spin_unlock(&sbsec->isec_lock);
478out:
Eric Parisc9180a52007-11-30 13:00:35 -0500479 return rc;
480}
481
482/*
483 * This function should allow an FS to ask what it's mount security
484 * options were so it can use those later for submounts, displaying
485 * mount options, or whatever.
486 */
487static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500488 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500489{
490 int rc = 0, i;
491 struct superblock_security_struct *sbsec = sb->s_security;
492 char *context = NULL;
493 u32 len;
494 char tmp;
495
Eric Parise0007522008-03-05 10:31:54 -0500496 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500497
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500498 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500499 return -EINVAL;
500
501 if (!ss_initialized)
502 return -EINVAL;
503
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500504 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500505 /* count the number of mount options for this sb */
506 for (i = 0; i < 8; i++) {
507 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500508 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500509 tmp >>= 1;
510 }
David P. Quigley11689d42009-01-16 09:22:03 -0500511 /* Check if the Label support flag is set */
512 if (sbsec->flags & SE_SBLABELSUPP)
513 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500514
Eric Parise0007522008-03-05 10:31:54 -0500515 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
516 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500517 rc = -ENOMEM;
518 goto out_free;
519 }
520
Eric Parise0007522008-03-05 10:31:54 -0500521 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
522 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500523 rc = -ENOMEM;
524 goto out_free;
525 }
526
527 i = 0;
528 if (sbsec->flags & FSCONTEXT_MNT) {
529 rc = security_sid_to_context(sbsec->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++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500534 }
535 if (sbsec->flags & CONTEXT_MNT) {
536 rc = security_sid_to_context(sbsec->mntpoint_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++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500541 }
542 if (sbsec->flags & DEFCONTEXT_MNT) {
543 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
544 if (rc)
545 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500546 opts->mnt_opts[i] = context;
547 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500548 }
549 if (sbsec->flags & ROOTCONTEXT_MNT) {
550 struct inode *root = sbsec->sb->s_root->d_inode;
551 struct inode_security_struct *isec = root->i_security;
552
553 rc = security_sid_to_context(isec->sid, &context, &len);
554 if (rc)
555 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500556 opts->mnt_opts[i] = context;
557 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500558 }
David P. Quigley11689d42009-01-16 09:22:03 -0500559 if (sbsec->flags & SE_SBLABELSUPP) {
560 opts->mnt_opts[i] = NULL;
561 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
562 }
Eric Parisc9180a52007-11-30 13:00:35 -0500563
Eric Parise0007522008-03-05 10:31:54 -0500564 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500565
566 return 0;
567
568out_free:
Eric Parise0007522008-03-05 10:31:54 -0500569 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500570 return rc;
571}
572
573static int bad_option(struct superblock_security_struct *sbsec, char flag,
574 u32 old_sid, u32 new_sid)
575{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500576 char mnt_flags = sbsec->flags & SE_MNTMASK;
577
Eric Parisc9180a52007-11-30 13:00:35 -0500578 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500579 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500580 if (!(sbsec->flags & flag) ||
581 (old_sid != new_sid))
582 return 1;
583
584 /* check if we were passed the same options twice,
585 * aka someone passed context=a,context=b
586 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500587 if (!(sbsec->flags & SE_SBINITIALIZED))
588 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500589 return 1;
590 return 0;
591}
Eric Parise0007522008-03-05 10:31:54 -0500592
Eric Parisc9180a52007-11-30 13:00:35 -0500593/*
594 * Allow filesystems with binary mount data to explicitly set mount point
595 * labeling information.
596 */
Eric Parise0007522008-03-05 10:31:54 -0500597static int selinux_set_mnt_opts(struct super_block *sb,
598 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500599{
David Howells275bb412008-11-14 10:39:19 +1100600 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500601 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500602 struct superblock_security_struct *sbsec = sb->s_security;
603 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000604 struct inode *inode = sbsec->sb->s_root->d_inode;
605 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500606 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
607 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500608 char **mount_options = opts->mnt_opts;
609 int *flags = opts->mnt_opts_flags;
610 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500611
612 mutex_lock(&sbsec->lock);
613
614 if (!ss_initialized) {
615 if (!num_opts) {
616 /* Defer initialization until selinux_complete_init,
617 after the initial policy is loaded and the security
618 server is ready to handle calls. */
619 spin_lock(&sb_security_lock);
620 if (list_empty(&sbsec->list))
621 list_add(&sbsec->list, &superblock_security_head);
622 spin_unlock(&sb_security_lock);
623 goto out;
624 }
625 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400626 printk(KERN_WARNING "SELinux: Unable to set superblock options "
627 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500628 goto out;
629 }
630
631 /*
Eric Parise0007522008-03-05 10:31:54 -0500632 * Binary mount data FS will come through this function twice. Once
633 * from an explicit call and once from the generic calls from the vfs.
634 * Since the generic VFS calls will not contain any security mount data
635 * we need to skip the double mount verification.
636 *
637 * This does open a hole in which we will not notice if the first
638 * mount using this sb set explict options and a second mount using
639 * this sb does not set any security options. (The first options
640 * will be used for both mounts)
641 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500642 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500643 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400644 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500645
646 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500647 * parse the mount options, check if they are valid sids.
648 * also check if someone is trying to mount the same sb more
649 * than once with different security options.
650 */
651 for (i = 0; i < num_opts; i++) {
652 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500653
654 if (flags[i] == SE_SBLABELSUPP)
655 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500656 rc = security_context_to_sid(mount_options[i],
657 strlen(mount_options[i]), &sid);
658 if (rc) {
659 printk(KERN_WARNING "SELinux: security_context_to_sid"
660 "(%s) failed for (dev %s, type %s) errno=%d\n",
661 mount_options[i], sb->s_id, name, rc);
662 goto out;
663 }
664 switch (flags[i]) {
665 case FSCONTEXT_MNT:
666 fscontext_sid = sid;
667
668 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
669 fscontext_sid))
670 goto out_double_mount;
671
672 sbsec->flags |= FSCONTEXT_MNT;
673 break;
674 case CONTEXT_MNT:
675 context_sid = sid;
676
677 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
678 context_sid))
679 goto out_double_mount;
680
681 sbsec->flags |= CONTEXT_MNT;
682 break;
683 case ROOTCONTEXT_MNT:
684 rootcontext_sid = sid;
685
686 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
687 rootcontext_sid))
688 goto out_double_mount;
689
690 sbsec->flags |= ROOTCONTEXT_MNT;
691
692 break;
693 case DEFCONTEXT_MNT:
694 defcontext_sid = sid;
695
696 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
697 defcontext_sid))
698 goto out_double_mount;
699
700 sbsec->flags |= DEFCONTEXT_MNT;
701
702 break;
703 default:
704 rc = -EINVAL;
705 goto out;
706 }
707 }
708
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500709 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500710 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500711 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500712 goto out_double_mount;
713 rc = 0;
714 goto out;
715 }
716
James Morris089be432008-07-15 18:32:49 +1000717 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500718 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500719
720 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500721 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500722 if (rc) {
723 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000724 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500725 goto out;
726 }
727
728 /* sets the context of the superblock for the fs being mounted. */
729 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100730 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500731 if (rc)
732 goto out;
733
734 sbsec->sid = fscontext_sid;
735 }
736
737 /*
738 * Switch to using mount point labeling behavior.
739 * sets the label used on all file below the mountpoint, and will set
740 * the superblock context if not already set.
741 */
742 if (context_sid) {
743 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100744 rc = may_context_mount_sb_relabel(context_sid, sbsec,
745 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500746 if (rc)
747 goto out;
748 sbsec->sid = context_sid;
749 } else {
David Howells275bb412008-11-14 10:39:19 +1100750 rc = may_context_mount_inode_relabel(context_sid, sbsec,
751 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500752 if (rc)
753 goto out;
754 }
755 if (!rootcontext_sid)
756 rootcontext_sid = context_sid;
757
758 sbsec->mntpoint_sid = context_sid;
759 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
760 }
761
762 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100763 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
764 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500765 if (rc)
766 goto out;
767
768 root_isec->sid = rootcontext_sid;
769 root_isec->initialized = 1;
770 }
771
772 if (defcontext_sid) {
773 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
774 rc = -EINVAL;
775 printk(KERN_WARNING "SELinux: defcontext option is "
776 "invalid for this filesystem type\n");
777 goto out;
778 }
779
780 if (defcontext_sid != sbsec->def_sid) {
781 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100782 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500783 if (rc)
784 goto out;
785 }
786
787 sbsec->def_sid = defcontext_sid;
788 }
789
790 rc = sb_finish_set_opts(sb);
791out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700792 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500794out_double_mount:
795 rc = -EINVAL;
796 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
797 "security settings for (dev %s, type %s)\n", sb->s_id, name);
798 goto out;
799}
800
801static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
802 struct super_block *newsb)
803{
804 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
805 struct superblock_security_struct *newsbsec = newsb->s_security;
806
807 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
808 int set_context = (oldsbsec->flags & CONTEXT_MNT);
809 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
810
Eric Paris0f5e6422008-04-21 16:24:11 -0400811 /*
812 * if the parent was able to be mounted it clearly had no special lsm
813 * mount options. thus we can safely put this sb on the list and deal
814 * with it later
815 */
816 if (!ss_initialized) {
817 spin_lock(&sb_security_lock);
818 if (list_empty(&newsbsec->list))
819 list_add(&newsbsec->list, &superblock_security_head);
820 spin_unlock(&sb_security_lock);
821 return;
822 }
Eric Parisc9180a52007-11-30 13:00:35 -0500823
Eric Parisc9180a52007-11-30 13:00:35 -0500824 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500825 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500826
Eric Paris5a552612008-04-09 14:08:35 -0400827 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500828 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400829 return;
830
Eric Parisc9180a52007-11-30 13:00:35 -0500831 mutex_lock(&newsbsec->lock);
832
833 newsbsec->flags = oldsbsec->flags;
834
835 newsbsec->sid = oldsbsec->sid;
836 newsbsec->def_sid = oldsbsec->def_sid;
837 newsbsec->behavior = oldsbsec->behavior;
838
839 if (set_context) {
840 u32 sid = oldsbsec->mntpoint_sid;
841
842 if (!set_fscontext)
843 newsbsec->sid = sid;
844 if (!set_rootcontext) {
845 struct inode *newinode = newsb->s_root->d_inode;
846 struct inode_security_struct *newisec = newinode->i_security;
847 newisec->sid = sid;
848 }
849 newsbsec->mntpoint_sid = sid;
850 }
851 if (set_rootcontext) {
852 const struct inode *oldinode = oldsb->s_root->d_inode;
853 const struct inode_security_struct *oldisec = oldinode->i_security;
854 struct inode *newinode = newsb->s_root->d_inode;
855 struct inode_security_struct *newisec = newinode->i_security;
856
857 newisec->sid = oldisec->sid;
858 }
859
860 sb_finish_set_opts(newsb);
861 mutex_unlock(&newsbsec->lock);
862}
863
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200864static int selinux_parse_opts_str(char *options,
865 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500866{
Eric Parise0007522008-03-05 10:31:54 -0500867 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500868 char *context = NULL, *defcontext = NULL;
869 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500870 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500871
Eric Parise0007522008-03-05 10:31:54 -0500872 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500873
874 /* Standard string-based options. */
875 while ((p = strsep(&options, "|")) != NULL) {
876 int token;
877 substring_t args[MAX_OPT_ARGS];
878
879 if (!*p)
880 continue;
881
882 token = match_token(p, tokens, args);
883
884 switch (token) {
885 case Opt_context:
886 if (context || defcontext) {
887 rc = -EINVAL;
888 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
889 goto out_err;
890 }
891 context = match_strdup(&args[0]);
892 if (!context) {
893 rc = -ENOMEM;
894 goto out_err;
895 }
896 break;
897
898 case Opt_fscontext:
899 if (fscontext) {
900 rc = -EINVAL;
901 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
902 goto out_err;
903 }
904 fscontext = match_strdup(&args[0]);
905 if (!fscontext) {
906 rc = -ENOMEM;
907 goto out_err;
908 }
909 break;
910
911 case Opt_rootcontext:
912 if (rootcontext) {
913 rc = -EINVAL;
914 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
915 goto out_err;
916 }
917 rootcontext = match_strdup(&args[0]);
918 if (!rootcontext) {
919 rc = -ENOMEM;
920 goto out_err;
921 }
922 break;
923
924 case Opt_defcontext:
925 if (context || defcontext) {
926 rc = -EINVAL;
927 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
928 goto out_err;
929 }
930 defcontext = match_strdup(&args[0]);
931 if (!defcontext) {
932 rc = -ENOMEM;
933 goto out_err;
934 }
935 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500936 case Opt_labelsupport:
937 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500938 default:
939 rc = -EINVAL;
940 printk(KERN_WARNING "SELinux: unknown mount option\n");
941 goto out_err;
942
943 }
944 }
945
Eric Parise0007522008-03-05 10:31:54 -0500946 rc = -ENOMEM;
947 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
948 if (!opts->mnt_opts)
949 goto out_err;
950
951 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
952 if (!opts->mnt_opts_flags) {
953 kfree(opts->mnt_opts);
954 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500955 }
956
Eric Parise0007522008-03-05 10:31:54 -0500957 if (fscontext) {
958 opts->mnt_opts[num_mnt_opts] = fscontext;
959 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
960 }
961 if (context) {
962 opts->mnt_opts[num_mnt_opts] = context;
963 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
964 }
965 if (rootcontext) {
966 opts->mnt_opts[num_mnt_opts] = rootcontext;
967 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
968 }
969 if (defcontext) {
970 opts->mnt_opts[num_mnt_opts] = defcontext;
971 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
972 }
973
974 opts->num_mnt_opts = num_mnt_opts;
975 return 0;
976
Eric Parisc9180a52007-11-30 13:00:35 -0500977out_err:
978 kfree(context);
979 kfree(defcontext);
980 kfree(fscontext);
981 kfree(rootcontext);
982 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
Eric Parise0007522008-03-05 10:31:54 -0500984/*
985 * string mount options parsing and call set the sbsec
986 */
987static int superblock_doinit(struct super_block *sb, void *data)
988{
989 int rc = 0;
990 char *options = data;
991 struct security_mnt_opts opts;
992
993 security_init_mnt_opts(&opts);
994
995 if (!data)
996 goto out;
997
998 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
999
1000 rc = selinux_parse_opts_str(options, &opts);
1001 if (rc)
1002 goto out_err;
1003
1004out:
1005 rc = selinux_set_mnt_opts(sb, &opts);
1006
1007out_err:
1008 security_free_mnt_opts(&opts);
1009 return rc;
1010}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Adrian Bunk3583a712008-07-22 20:21:23 +03001012static void selinux_write_opts(struct seq_file *m,
1013 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +10001014{
1015 int i;
1016 char *prefix;
1017
1018 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -05001019 char *has_comma;
1020
1021 if (opts->mnt_opts[i])
1022 has_comma = strchr(opts->mnt_opts[i], ',');
1023 else
1024 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +10001025
1026 switch (opts->mnt_opts_flags[i]) {
1027 case CONTEXT_MNT:
1028 prefix = CONTEXT_STR;
1029 break;
1030 case FSCONTEXT_MNT:
1031 prefix = FSCONTEXT_STR;
1032 break;
1033 case ROOTCONTEXT_MNT:
1034 prefix = ROOTCONTEXT_STR;
1035 break;
1036 case DEFCONTEXT_MNT:
1037 prefix = DEFCONTEXT_STR;
1038 break;
David P. Quigley11689d42009-01-16 09:22:03 -05001039 case SE_SBLABELSUPP:
1040 seq_putc(m, ',');
1041 seq_puts(m, LABELSUPP_STR);
1042 continue;
Eric Paris2069f452008-07-04 09:47:13 +10001043 default:
1044 BUG();
1045 };
1046 /* we need a comma before each option */
1047 seq_putc(m, ',');
1048 seq_puts(m, prefix);
1049 if (has_comma)
1050 seq_putc(m, '\"');
1051 seq_puts(m, opts->mnt_opts[i]);
1052 if (has_comma)
1053 seq_putc(m, '\"');
1054 }
1055}
1056
1057static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1058{
1059 struct security_mnt_opts opts;
1060 int rc;
1061
1062 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001063 if (rc) {
1064 /* before policy load we may get EINVAL, don't show anything */
1065 if (rc == -EINVAL)
1066 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001067 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001068 }
Eric Paris2069f452008-07-04 09:47:13 +10001069
1070 selinux_write_opts(m, &opts);
1071
1072 security_free_mnt_opts(&opts);
1073
1074 return rc;
1075}
1076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077static inline u16 inode_mode_to_security_class(umode_t mode)
1078{
1079 switch (mode & S_IFMT) {
1080 case S_IFSOCK:
1081 return SECCLASS_SOCK_FILE;
1082 case S_IFLNK:
1083 return SECCLASS_LNK_FILE;
1084 case S_IFREG:
1085 return SECCLASS_FILE;
1086 case S_IFBLK:
1087 return SECCLASS_BLK_FILE;
1088 case S_IFDIR:
1089 return SECCLASS_DIR;
1090 case S_IFCHR:
1091 return SECCLASS_CHR_FILE;
1092 case S_IFIFO:
1093 return SECCLASS_FIFO_FILE;
1094
1095 }
1096
1097 return SECCLASS_FILE;
1098}
1099
James Morris13402582005-09-30 14:24:34 -04001100static inline int default_protocol_stream(int protocol)
1101{
1102 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1103}
1104
1105static inline int default_protocol_dgram(int protocol)
1106{
1107 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1108}
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1111{
1112 switch (family) {
1113 case PF_UNIX:
1114 switch (type) {
1115 case SOCK_STREAM:
1116 case SOCK_SEQPACKET:
1117 return SECCLASS_UNIX_STREAM_SOCKET;
1118 case SOCK_DGRAM:
1119 return SECCLASS_UNIX_DGRAM_SOCKET;
1120 }
1121 break;
1122 case PF_INET:
1123 case PF_INET6:
1124 switch (type) {
1125 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001126 if (default_protocol_stream(protocol))
1127 return SECCLASS_TCP_SOCKET;
1128 else
1129 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001131 if (default_protocol_dgram(protocol))
1132 return SECCLASS_UDP_SOCKET;
1133 else
1134 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001135 case SOCK_DCCP:
1136 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001137 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 return SECCLASS_RAWIP_SOCKET;
1139 }
1140 break;
1141 case PF_NETLINK:
1142 switch (protocol) {
1143 case NETLINK_ROUTE:
1144 return SECCLASS_NETLINK_ROUTE_SOCKET;
1145 case NETLINK_FIREWALL:
1146 return SECCLASS_NETLINK_FIREWALL_SOCKET;
James Morris216efaa2005-08-15 20:34:48 -07001147 case NETLINK_INET_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1149 case NETLINK_NFLOG:
1150 return SECCLASS_NETLINK_NFLOG_SOCKET;
1151 case NETLINK_XFRM:
1152 return SECCLASS_NETLINK_XFRM_SOCKET;
1153 case NETLINK_SELINUX:
1154 return SECCLASS_NETLINK_SELINUX_SOCKET;
1155 case NETLINK_AUDIT:
1156 return SECCLASS_NETLINK_AUDIT_SOCKET;
1157 case NETLINK_IP6_FW:
1158 return SECCLASS_NETLINK_IP6FW_SOCKET;
1159 case NETLINK_DNRTMSG:
1160 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001161 case NETLINK_KOBJECT_UEVENT:
1162 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 default:
1164 return SECCLASS_NETLINK_SOCKET;
1165 }
1166 case PF_PACKET:
1167 return SECCLASS_PACKET_SOCKET;
1168 case PF_KEY:
1169 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001170 case PF_APPLETALK:
1171 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173
1174 return SECCLASS_SOCKET;
1175}
1176
1177#ifdef CONFIG_PROC_FS
1178static int selinux_proc_get_sid(struct proc_dir_entry *de,
1179 u16 tclass,
1180 u32 *sid)
1181{
1182 int buflen, rc;
1183 char *buffer, *path, *end;
1184
Eric Paris828dfe12008-04-17 13:17:49 -04001185 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 if (!buffer)
1187 return -ENOMEM;
1188
1189 buflen = PAGE_SIZE;
1190 end = buffer+buflen;
1191 *--end = '\0';
1192 buflen--;
1193 path = end-1;
1194 *path = '/';
1195 while (de && de != de->parent) {
1196 buflen -= de->namelen + 1;
1197 if (buflen < 0)
1198 break;
1199 end -= de->namelen;
1200 memcpy(end, de->name, de->namelen);
1201 *--end = '/';
1202 path = end;
1203 de = de->parent;
1204 }
1205 rc = security_genfs_sid("proc", path, tclass, sid);
1206 free_page((unsigned long)buffer);
1207 return rc;
1208}
1209#else
1210static int selinux_proc_get_sid(struct proc_dir_entry *de,
1211 u16 tclass,
1212 u32 *sid)
1213{
1214 return -EINVAL;
1215}
1216#endif
1217
1218/* The inode's security attributes must be initialized before first use. */
1219static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1220{
1221 struct superblock_security_struct *sbsec = NULL;
1222 struct inode_security_struct *isec = inode->i_security;
1223 u32 sid;
1224 struct dentry *dentry;
1225#define INITCONTEXTLEN 255
1226 char *context = NULL;
1227 unsigned len = 0;
1228 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 if (isec->initialized)
1231 goto out;
1232
Eric Paris23970742006-09-25 23:32:01 -07001233 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001235 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001238 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 /* Defer initialization until selinux_complete_init,
1240 after the initial policy is loaded and the security
1241 server is ready to handle calls. */
1242 spin_lock(&sbsec->isec_lock);
1243 if (list_empty(&isec->list))
1244 list_add(&isec->list, &sbsec->isec_head);
1245 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001246 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 }
1248
1249 switch (sbsec->behavior) {
1250 case SECURITY_FS_USE_XATTR:
1251 if (!inode->i_op->getxattr) {
1252 isec->sid = sbsec->def_sid;
1253 break;
1254 }
1255
1256 /* Need a dentry, since the xattr API requires one.
1257 Life would be simpler if we could just pass the inode. */
1258 if (opt_dentry) {
1259 /* Called from d_instantiate or d_splice_alias. */
1260 dentry = dget(opt_dentry);
1261 } else {
1262 /* Called from selinux_complete_init, try to find a dentry. */
1263 dentry = d_find_alias(inode);
1264 }
1265 if (!dentry) {
Eric Paris744ba352008-04-17 11:52:44 -04001266 printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001267 "ino=%ld\n", __func__, inode->i_sb->s_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 inode->i_ino);
Eric Paris23970742006-09-25 23:32:01 -07001269 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
1271
1272 len = INITCONTEXTLEN;
Stephen Smalley869ab512008-04-04 08:46:05 -04001273 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (!context) {
1275 rc = -ENOMEM;
1276 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001277 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 }
1279 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1280 context, len);
1281 if (rc == -ERANGE) {
1282 /* Need a larger buffer. Query for the right size. */
1283 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1284 NULL, 0);
1285 if (rc < 0) {
1286 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001287 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 }
1289 kfree(context);
1290 len = rc;
Stephen Smalley869ab512008-04-04 08:46:05 -04001291 context = kmalloc(len, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 if (!context) {
1293 rc = -ENOMEM;
1294 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001295 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
1297 rc = inode->i_op->getxattr(dentry,
1298 XATTR_NAME_SELINUX,
1299 context, len);
1300 }
1301 dput(dentry);
1302 if (rc < 0) {
1303 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001304 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001305 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 -rc, inode->i_sb->s_id, inode->i_ino);
1307 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001308 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 }
1310 /* Map ENODATA to the default file SID */
1311 sid = sbsec->def_sid;
1312 rc = 0;
1313 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001314 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001315 sbsec->def_sid,
1316 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (rc) {
Eric Paris744ba352008-04-17 11:52:44 -04001318 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 "returned %d for dev=%s ino=%ld\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001320 __func__, context, -rc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 inode->i_sb->s_id, inode->i_ino);
1322 kfree(context);
1323 /* Leave with the unlabeled SID */
1324 rc = 0;
1325 break;
1326 }
1327 }
1328 kfree(context);
1329 isec->sid = sid;
1330 break;
1331 case SECURITY_FS_USE_TASK:
1332 isec->sid = isec->task_sid;
1333 break;
1334 case SECURITY_FS_USE_TRANS:
1335 /* Default to the fs SID. */
1336 isec->sid = sbsec->sid;
1337
1338 /* Try to obtain a transition SID. */
1339 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1340 rc = security_transition_sid(isec->task_sid,
1341 sbsec->sid,
1342 isec->sclass,
1343 &sid);
1344 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001345 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 isec->sid = sid;
1347 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001348 case SECURITY_FS_USE_MNTPOINT:
1349 isec->sid = sbsec->mntpoint_sid;
1350 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001352 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 isec->sid = sbsec->sid;
1354
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001355 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 struct proc_inode *proci = PROC_I(inode);
1357 if (proci->pde) {
1358 isec->sclass = inode_mode_to_security_class(inode->i_mode);
1359 rc = selinux_proc_get_sid(proci->pde,
1360 isec->sclass,
1361 &sid);
1362 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001363 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 isec->sid = sid;
1365 }
1366 }
1367 break;
1368 }
1369
1370 isec->initialized = 1;
1371
Eric Paris23970742006-09-25 23:32:01 -07001372out_unlock:
1373 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374out:
1375 if (isec->sclass == SECCLASS_FILE)
1376 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return rc;
1378}
1379
1380/* Convert a Linux signal to an access vector. */
1381static inline u32 signal_to_av(int sig)
1382{
1383 u32 perm = 0;
1384
1385 switch (sig) {
1386 case SIGCHLD:
1387 /* Commonly granted from child to parent. */
1388 perm = PROCESS__SIGCHLD;
1389 break;
1390 case SIGKILL:
1391 /* Cannot be caught or ignored */
1392 perm = PROCESS__SIGKILL;
1393 break;
1394 case SIGSTOP:
1395 /* Cannot be caught or ignored */
1396 perm = PROCESS__SIGSTOP;
1397 break;
1398 default:
1399 /* All other signals. */
1400 perm = PROCESS__SIGNAL;
1401 break;
1402 }
1403
1404 return perm;
1405}
1406
David Howells275bb412008-11-14 10:39:19 +11001407/*
David Howellsd84f4f92008-11-14 10:39:23 +11001408 * Check permission between a pair of credentials
1409 * fork check, ptrace check, etc.
1410 */
1411static int cred_has_perm(const struct cred *actor,
1412 const struct cred *target,
1413 u32 perms)
1414{
1415 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1416
1417 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1418}
1419
1420/*
David Howells88e67f32008-11-14 10:39:21 +11001421 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001422 * fork check, ptrace check, etc.
1423 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001424 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001425 */
1426static int task_has_perm(const struct task_struct *tsk1,
1427 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 u32 perms)
1429{
David Howells275bb412008-11-14 10:39:19 +11001430 const struct task_security_struct *__tsec1, *__tsec2;
1431 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
David Howells275bb412008-11-14 10:39:19 +11001433 rcu_read_lock();
1434 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1435 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1436 rcu_read_unlock();
1437 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438}
1439
David Howells3b11a1d2008-11-14 10:39:26 +11001440/*
1441 * Check permission between current and another task, e.g. signal checks,
1442 * fork check, ptrace check, etc.
1443 * current is the actor and tsk2 is the target
1444 * - this uses current's subjective creds
1445 */
1446static int current_has_perm(const struct task_struct *tsk,
1447 u32 perms)
1448{
1449 u32 sid, tsid;
1450
1451 sid = current_sid();
1452 tsid = task_sid(tsk);
1453 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1454}
1455
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001456#if CAP_LAST_CAP > 63
1457#error Fix SELinux to handle capabilities > 63.
1458#endif
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460/* Check whether a task is allowed to use a capability. */
1461static int task_has_capability(struct task_struct *tsk,
David Howells3699c532009-01-06 22:27:01 +00001462 const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001463 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 struct avc_audit_data ad;
Eric Paris06112162008-11-11 22:02:50 +11001466 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001467 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001468 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001469 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001470 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Eric Paris828dfe12008-04-17 13:17:49 -04001472 AVC_AUDIT_DATA_INIT(&ad, CAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 ad.tsk = tsk;
1474 ad.u.cap = cap;
1475
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001476 switch (CAP_TO_INDEX(cap)) {
1477 case 0:
1478 sclass = SECCLASS_CAPABILITY;
1479 break;
1480 case 1:
1481 sclass = SECCLASS_CAPABILITY2;
1482 break;
1483 default:
1484 printk(KERN_ERR
1485 "SELinux: out of range capability %d\n", cap);
1486 BUG();
1487 }
Eric Paris06112162008-11-11 22:02:50 +11001488
David Howells275bb412008-11-14 10:39:19 +11001489 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris06112162008-11-11 22:02:50 +11001490 if (audit == SECURITY_CAP_AUDIT)
David Howells275bb412008-11-14 10:39:19 +11001491 avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
Eric Paris06112162008-11-11 22:02:50 +11001492 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493}
1494
1495/* Check whether a task is allowed to use a system operation. */
1496static int task_has_system(struct task_struct *tsk,
1497 u32 perms)
1498{
David Howells275bb412008-11-14 10:39:19 +11001499 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
David Howells275bb412008-11-14 10:39:19 +11001501 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 SECCLASS_SYSTEM, perms, NULL);
1503}
1504
1505/* Check whether a task has a particular permission to an inode.
1506 The 'adp' parameter is optional and allows other audit
1507 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001508static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 struct inode *inode,
1510 u32 perms,
1511 struct avc_audit_data *adp)
1512{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 struct inode_security_struct *isec;
1514 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001515 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Eric Paris828dfe12008-04-17 13:17:49 -04001517 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001518 return 0;
1519
David Howells88e67f32008-11-14 10:39:21 +11001520 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 isec = inode->i_security;
1522
1523 if (!adp) {
1524 adp = &ad;
1525 AVC_AUDIT_DATA_INIT(&ad, FS);
1526 ad.u.fs.inode = inode;
1527 }
1528
David Howells275bb412008-11-14 10:39:19 +11001529 return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530}
1531
1532/* Same as inode_has_perm, but pass explicit audit data containing
1533 the dentry to help the auditing code to more easily generate the
1534 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001535static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 struct vfsmount *mnt,
1537 struct dentry *dentry,
1538 u32 av)
1539{
1540 struct inode *inode = dentry->d_inode;
1541 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001542
Eric Paris828dfe12008-04-17 13:17:49 -04001543 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001544 ad.u.fs.path.mnt = mnt;
1545 ad.u.fs.path.dentry = dentry;
David Howells88e67f32008-11-14 10:39:21 +11001546 return inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547}
1548
1549/* Check whether a task can use an open file descriptor to
1550 access an inode in a given way. Check access to the
1551 descriptor itself, and then use dentry_has_perm to
1552 check a particular permission to the file.
1553 Access to the descriptor is implicitly granted if it
1554 has the same SID as the process. If av is zero, then
1555 access to the file is not checked, e.g. for cases
1556 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001557static int file_has_perm(const struct cred *cred,
1558 struct file *file,
1559 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001562 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 struct avc_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001564 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 int rc;
1566
1567 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001568 ad.u.fs.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
David Howells275bb412008-11-14 10:39:19 +11001570 if (sid != fsec->sid) {
1571 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 SECCLASS_FD,
1573 FD__USE,
1574 &ad);
1575 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001576 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
1578
1579 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001580 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (av)
David Howells88e67f32008-11-14 10:39:21 +11001582 rc = inode_has_perm(cred, inode, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
David Howells88e67f32008-11-14 10:39:21 +11001584out:
1585 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586}
1587
1588/* Check whether a task can create a file. */
1589static int may_create(struct inode *dir,
1590 struct dentry *dentry,
1591 u16 tclass)
1592{
David Howells275bb412008-11-14 10:39:19 +11001593 const struct cred *cred = current_cred();
1594 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 struct inode_security_struct *dsec;
1596 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001597 u32 sid, newsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 struct avc_audit_data ad;
1599 int rc;
1600
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 dsec = dir->i_security;
1602 sbsec = dir->i_sb->s_security;
1603
David Howells275bb412008-11-14 10:39:19 +11001604 sid = tsec->sid;
1605 newsid = tsec->create_sid;
1606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001608 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
David Howells275bb412008-11-14 10:39:19 +11001610 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 DIR__ADD_NAME | DIR__SEARCH,
1612 &ad);
1613 if (rc)
1614 return rc;
1615
David P. Quigleycd895962009-01-16 09:22:04 -05001616 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11001617 rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (rc)
1619 return rc;
1620 }
1621
David Howells275bb412008-11-14 10:39:19 +11001622 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (rc)
1624 return rc;
1625
1626 return avc_has_perm(newsid, sbsec->sid,
1627 SECCLASS_FILESYSTEM,
1628 FILESYSTEM__ASSOCIATE, &ad);
1629}
1630
Michael LeMay4eb582c2006-06-26 00:24:57 -07001631/* Check whether a task can create a key. */
1632static int may_create_key(u32 ksid,
1633 struct task_struct *ctx)
1634{
David Howells275bb412008-11-14 10:39:19 +11001635 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001636
David Howells275bb412008-11-14 10:39:19 +11001637 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001638}
1639
Eric Paris828dfe12008-04-17 13:17:49 -04001640#define MAY_LINK 0
1641#define MAY_UNLINK 1
1642#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644/* Check whether a task can link, unlink, or rmdir a file/directory. */
1645static int may_link(struct inode *dir,
1646 struct dentry *dentry,
1647 int kind)
1648
1649{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 struct inode_security_struct *dsec, *isec;
1651 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001652 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 u32 av;
1654 int rc;
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 dsec = dir->i_security;
1657 isec = dentry->d_inode->i_security;
1658
1659 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08001660 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 av = DIR__SEARCH;
1663 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001664 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 if (rc)
1666 return rc;
1667
1668 switch (kind) {
1669 case MAY_LINK:
1670 av = FILE__LINK;
1671 break;
1672 case MAY_UNLINK:
1673 av = FILE__UNLINK;
1674 break;
1675 case MAY_RMDIR:
1676 av = DIR__RMDIR;
1677 break;
1678 default:
Eric Paris744ba352008-04-17 11:52:44 -04001679 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1680 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 return 0;
1682 }
1683
David Howells275bb412008-11-14 10:39:19 +11001684 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return rc;
1686}
1687
1688static inline int may_rename(struct inode *old_dir,
1689 struct dentry *old_dentry,
1690 struct inode *new_dir,
1691 struct dentry *new_dentry)
1692{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
1694 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001695 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 u32 av;
1697 int old_is_dir, new_is_dir;
1698 int rc;
1699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 old_dsec = old_dir->i_security;
1701 old_isec = old_dentry->d_inode->i_security;
1702 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1703 new_dsec = new_dir->i_security;
1704
1705 AVC_AUDIT_DATA_INIT(&ad, FS);
1706
Jan Blunck44707fd2008-02-14 19:38:33 -08001707 ad.u.fs.path.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001708 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1710 if (rc)
1711 return rc;
David Howells275bb412008-11-14 10:39:19 +11001712 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 old_isec->sclass, FILE__RENAME, &ad);
1714 if (rc)
1715 return rc;
1716 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001717 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 old_isec->sclass, DIR__REPARENT, &ad);
1719 if (rc)
1720 return rc;
1721 }
1722
Jan Blunck44707fd2008-02-14 19:38:33 -08001723 ad.u.fs.path.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 av = DIR__ADD_NAME | DIR__SEARCH;
1725 if (new_dentry->d_inode)
1726 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001727 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (rc)
1729 return rc;
1730 if (new_dentry->d_inode) {
1731 new_isec = new_dentry->d_inode->i_security;
1732 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001733 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 new_isec->sclass,
1735 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1736 if (rc)
1737 return rc;
1738 }
1739
1740 return 0;
1741}
1742
1743/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001744static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 struct super_block *sb,
1746 u32 perms,
1747 struct avc_audit_data *ad)
1748{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001750 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001753 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754}
1755
1756/* Convert a Linux mode and permission mask to an access vector. */
1757static inline u32 file_mask_to_av(int mode, int mask)
1758{
1759 u32 av = 0;
1760
1761 if ((mode & S_IFMT) != S_IFDIR) {
1762 if (mask & MAY_EXEC)
1763 av |= FILE__EXECUTE;
1764 if (mask & MAY_READ)
1765 av |= FILE__READ;
1766
1767 if (mask & MAY_APPEND)
1768 av |= FILE__APPEND;
1769 else if (mask & MAY_WRITE)
1770 av |= FILE__WRITE;
1771
1772 } else {
1773 if (mask & MAY_EXEC)
1774 av |= DIR__SEARCH;
1775 if (mask & MAY_WRITE)
1776 av |= DIR__WRITE;
1777 if (mask & MAY_READ)
1778 av |= DIR__READ;
1779 }
1780
1781 return av;
1782}
1783
1784/* Convert a Linux file to an access vector. */
1785static inline u32 file_to_av(struct file *file)
1786{
1787 u32 av = 0;
1788
1789 if (file->f_mode & FMODE_READ)
1790 av |= FILE__READ;
1791 if (file->f_mode & FMODE_WRITE) {
1792 if (file->f_flags & O_APPEND)
1793 av |= FILE__APPEND;
1794 else
1795 av |= FILE__WRITE;
1796 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001797 if (!av) {
1798 /*
1799 * Special file opened with flags 3 for ioctl-only use.
1800 */
1801 av = FILE__IOCTL;
1802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 return av;
1805}
1806
Eric Paris8b6a5a32008-10-29 17:06:46 -04001807/*
1808 * Convert a file to an access vector and include the correct open
1809 * open permission.
1810 */
1811static inline u32 open_file_to_av(struct file *file)
1812{
1813 u32 av = file_to_av(file);
1814
1815 if (selinux_policycap_openperm) {
1816 mode_t mode = file->f_path.dentry->d_inode->i_mode;
1817 /*
1818 * lnk files and socks do not really have an 'open'
1819 */
1820 if (S_ISREG(mode))
1821 av |= FILE__OPEN;
1822 else if (S_ISCHR(mode))
1823 av |= CHR_FILE__OPEN;
1824 else if (S_ISBLK(mode))
1825 av |= BLK_FILE__OPEN;
1826 else if (S_ISFIFO(mode))
1827 av |= FIFO_FILE__OPEN;
1828 else if (S_ISDIR(mode))
1829 av |= DIR__OPEN;
1830 else
1831 printk(KERN_ERR "SELinux: WARNING: inside %s with "
1832 "unknown mode:%o\n", __func__, mode);
1833 }
1834 return av;
1835}
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837/* Hook functions begin here. */
1838
David Howells5cd9c582008-08-14 11:37:28 +01001839static int selinux_ptrace_may_access(struct task_struct *child,
1840 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 int rc;
1843
David Howells5cd9c582008-08-14 11:37:28 +01001844 rc = secondary_ops->ptrace_may_access(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if (rc)
1846 return rc;
1847
Stephen Smalley006ebb42008-05-19 08:32:49 -04001848 if (mode == PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001849 u32 sid = current_sid();
1850 u32 csid = task_sid(child);
1851 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001852 }
1853
David Howells3b11a1d2008-11-14 10:39:26 +11001854 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001855}
1856
1857static int selinux_ptrace_traceme(struct task_struct *parent)
1858{
1859 int rc;
1860
1861 rc = secondary_ops->ptrace_traceme(parent);
1862 if (rc)
1863 return rc;
1864
1865 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001869 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870{
1871 int error;
1872
David Howells3b11a1d2008-11-14 10:39:26 +11001873 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (error)
1875 return error;
1876
1877 return secondary_ops->capget(target, effective, inheritable, permitted);
1878}
1879
David Howellsd84f4f92008-11-14 10:39:23 +11001880static int selinux_capset(struct cred *new, const struct cred *old,
1881 const kernel_cap_t *effective,
1882 const kernel_cap_t *inheritable,
1883 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
1885 int error;
1886
David Howellsd84f4f92008-11-14 10:39:23 +11001887 error = secondary_ops->capset(new, old,
1888 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (error)
1890 return error;
1891
David Howellsd84f4f92008-11-14 10:39:23 +11001892 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893}
1894
David Howells3699c532009-01-06 22:27:01 +00001895static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
1896 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897{
1898 int rc;
1899
David Howells3699c532009-01-06 22:27:01 +00001900 rc = secondary_ops->capable(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (rc)
1902 return rc;
1903
David Howells3699c532009-01-06 22:27:01 +00001904 return task_has_capability(tsk, cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905}
1906
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001907static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
1908{
1909 int buflen, rc;
1910 char *buffer, *path, *end;
1911
1912 rc = -ENOMEM;
Eric Paris828dfe12008-04-17 13:17:49 -04001913 buffer = (char *)__get_free_page(GFP_KERNEL);
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001914 if (!buffer)
1915 goto out;
1916
1917 buflen = PAGE_SIZE;
1918 end = buffer+buflen;
1919 *--end = '\0';
1920 buflen--;
1921 path = end-1;
1922 *path = '/';
1923 while (table) {
1924 const char *name = table->procname;
1925 size_t namelen = strlen(name);
1926 buflen -= namelen + 1;
1927 if (buflen < 0)
1928 goto out_free;
1929 end -= namelen;
1930 memcpy(end, name, namelen);
1931 *--end = '/';
1932 path = end;
1933 table = table->parent;
1934 }
Eric W. Biedermanb599fdf2007-02-14 00:34:15 -08001935 buflen -= 4;
1936 if (buflen < 0)
1937 goto out_free;
1938 end -= 4;
1939 memcpy(end, "/sys", 4);
1940 path = end;
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001941 rc = security_genfs_sid("proc", path, tclass, sid);
1942out_free:
1943 free_page((unsigned long)buffer);
1944out:
1945 return rc;
1946}
1947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948static int selinux_sysctl(ctl_table *table, int op)
1949{
1950 int error = 0;
1951 u32 av;
David Howells275bb412008-11-14 10:39:19 +11001952 u32 tsid, sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 int rc;
1954
1955 rc = secondary_ops->sysctl(table, op);
1956 if (rc)
1957 return rc;
1958
David Howells275bb412008-11-14 10:39:19 +11001959 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Eric W. Biederman3fbfa982007-02-14 00:34:14 -08001961 rc = selinux_sysctl_get_sid(table, (op == 0001) ?
1962 SECCLASS_DIR : SECCLASS_FILE, &tsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
1964 /* Default to the well-defined sysctl SID. */
1965 tsid = SECINITSID_SYSCTL;
1966 }
1967
1968 /* The op values are "defined" in sysctl.c, thereby creating
1969 * a bad coupling between this module and sysctl.c */
Eric Paris828dfe12008-04-17 13:17:49 -04001970 if (op == 001) {
David Howells275bb412008-11-14 10:39:19 +11001971 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 SECCLASS_DIR, DIR__SEARCH, NULL);
1973 } else {
1974 av = 0;
1975 if (op & 004)
1976 av |= FILE__READ;
1977 if (op & 002)
1978 av |= FILE__WRITE;
1979 if (av)
David Howells275bb412008-11-14 10:39:19 +11001980 error = avc_has_perm(sid, tsid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 SECCLASS_FILE, av, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984 return error;
1985}
1986
1987static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1988{
David Howells88e67f32008-11-14 10:39:21 +11001989 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 int rc = 0;
1991
1992 if (!sb)
1993 return 0;
1994
1995 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001996 case Q_SYNC:
1997 case Q_QUOTAON:
1998 case Q_QUOTAOFF:
1999 case Q_SETINFO:
2000 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11002001 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002002 break;
2003 case Q_GETFMT:
2004 case Q_GETINFO:
2005 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11002006 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04002007 break;
2008 default:
2009 rc = 0; /* let the kernel handle invalid cmds */
2010 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 }
2012 return rc;
2013}
2014
2015static int selinux_quota_on(struct dentry *dentry)
2016{
David Howells88e67f32008-11-14 10:39:21 +11002017 const struct cred *cred = current_cred();
2018
2019 return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020}
2021
2022static int selinux_syslog(int type)
2023{
2024 int rc;
2025
2026 rc = secondary_ops->syslog(type);
2027 if (rc)
2028 return rc;
2029
2030 switch (type) {
Eric Paris828dfe12008-04-17 13:17:49 -04002031 case 3: /* Read last kernel messages */
2032 case 10: /* Return size of the log buffer */
2033 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
2034 break;
2035 case 6: /* Disable logging to console */
2036 case 7: /* Enable logging to console */
2037 case 8: /* Set level of messages printed to console */
2038 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
2039 break;
2040 case 0: /* Close log */
2041 case 1: /* Open log */
2042 case 2: /* Read from log */
2043 case 4: /* Read/clear last kernel messages */
2044 case 5: /* Clear ring buffer */
2045 default:
2046 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2047 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 }
2049 return rc;
2050}
2051
2052/*
2053 * Check that a process has enough memory to allocate a new virtual
2054 * mapping. 0 means there is enough memory for the allocation to
2055 * succeed and -ENOMEM implies there is not.
2056 *
2057 * Note that secondary_ops->capable and task_has_perm_noaudit return 0
2058 * if the capability is granted, but __vm_enough_memory requires 1 if
2059 * the capability is granted.
2060 *
2061 * Do not audit the selinux permission check, as this is applied to all
2062 * processes that allocate mappings.
2063 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002064static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
2066 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
David Howells3699c532009-01-06 22:27:01 +00002068 rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
2069 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (rc == 0)
2071 cap_sys_admin = 1;
2072
Alan Cox34b4e4a2007-08-22 14:01:28 -07002073 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074}
2075
2076/* binprm security operations */
2077
David Howellsa6f76f22008-11-14 10:39:24 +11002078static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
David Howellsa6f76f22008-11-14 10:39:24 +11002080 const struct task_security_struct *old_tsec;
2081 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 struct avc_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11002084 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 int rc;
2086
David Howellsa6f76f22008-11-14 10:39:24 +11002087 rc = secondary_ops->bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 if (rc)
2089 return rc;
2090
David Howellsa6f76f22008-11-14 10:39:24 +11002091 /* SELinux context only depends on initial program or script and not
2092 * the script interpreter */
2093 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 return 0;
2095
David Howellsa6f76f22008-11-14 10:39:24 +11002096 old_tsec = current_security();
2097 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 isec = inode->i_security;
2099
2100 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002101 new_tsec->sid = old_tsec->sid;
2102 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Michael LeMay28eba5b2006-06-27 02:53:42 -07002104 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002105 new_tsec->create_sid = 0;
2106 new_tsec->keycreate_sid = 0;
2107 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
David Howellsa6f76f22008-11-14 10:39:24 +11002109 if (old_tsec->exec_sid) {
2110 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002112 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 } else {
2114 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002115 rc = security_transition_sid(old_tsec->sid, isec->sid,
2116 SECCLASS_PROCESS, &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 if (rc)
2118 return rc;
2119 }
2120
2121 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002122 ad.u.fs.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Josef Sipek3d5ff522006-12-08 02:37:38 -08002124 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002125 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
David Howellsa6f76f22008-11-14 10:39:24 +11002127 if (new_tsec->sid == old_tsec->sid) {
2128 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2130 if (rc)
2131 return rc;
2132 } else {
2133 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002134 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2136 if (rc)
2137 return rc;
2138
David Howellsa6f76f22008-11-14 10:39:24 +11002139 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2141 if (rc)
2142 return rc;
2143
David Howellsa6f76f22008-11-14 10:39:24 +11002144 /* Check for shared state */
2145 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2146 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2147 SECCLASS_PROCESS, PROCESS__SHARE,
2148 NULL);
2149 if (rc)
2150 return -EPERM;
2151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
David Howellsa6f76f22008-11-14 10:39:24 +11002153 /* Make sure that anyone attempting to ptrace over a task that
2154 * changes its SID has the appropriate permit */
2155 if (bprm->unsafe &
2156 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2157 struct task_struct *tracer;
2158 struct task_security_struct *sec;
2159 u32 ptsid = 0;
2160
2161 rcu_read_lock();
2162 tracer = tracehook_tracer_task(current);
2163 if (likely(tracer != NULL)) {
2164 sec = __task_cred(tracer)->security;
2165 ptsid = sec->sid;
2166 }
2167 rcu_read_unlock();
2168
2169 if (ptsid != 0) {
2170 rc = avc_has_perm(ptsid, new_tsec->sid,
2171 SECCLASS_PROCESS,
2172 PROCESS__PTRACE, NULL);
2173 if (rc)
2174 return -EPERM;
2175 }
2176 }
2177
2178 /* Clear any possibly unsafe personality bits on exec: */
2179 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 }
2181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return 0;
2183}
2184
Eric Paris828dfe12008-04-17 13:17:49 -04002185static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
David Howells275bb412008-11-14 10:39:19 +11002187 const struct cred *cred = current_cred();
2188 const struct task_security_struct *tsec = cred->security;
2189 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 int atsecure = 0;
2191
David Howells275bb412008-11-14 10:39:19 +11002192 sid = tsec->sid;
2193 osid = tsec->osid;
2194
2195 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 /* Enable secure mode for SIDs transitions unless
2197 the noatsecure permission is granted between
2198 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002199 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002200 SECCLASS_PROCESS,
2201 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 }
2203
2204 return (atsecure || secondary_ops->bprm_secureexec(bprm));
2205}
2206
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207extern struct vfsmount *selinuxfs_mount;
2208extern struct dentry *selinux_null;
2209
2210/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002211static inline void flush_unauthorized_files(const struct cred *cred,
2212 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213{
2214 struct avc_audit_data ad;
2215 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002216 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002217 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002219 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002221 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 if (tty) {
2223 file_list_lock();
Eric Paris37dd0bd2008-10-31 17:40:00 -04002224 if (!list_empty(&tty->tty_files)) {
2225 struct inode *inode;
2226
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 /* Revalidate access to controlling tty.
2228 Use inode_has_perm on the tty inode directly rather
2229 than using file_has_perm, as this particular open
2230 file may belong to another process and we are only
2231 interested in the inode-based check here. */
Eric Paris37dd0bd2008-10-31 17:40:00 -04002232 file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
2233 inode = file->f_path.dentry->d_inode;
David Howells88e67f32008-11-14 10:39:21 +11002234 if (inode_has_perm(cred, inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 FILE__READ | FILE__WRITE, NULL)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002236 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 }
2238 }
2239 file_list_unlock();
Alan Cox452a00d2008-10-13 10:39:13 +01002240 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002242 /* Reset controlling tty. */
2243 if (drop_tty)
2244 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245
2246 /* Revalidate access to inherited open files. */
2247
Eric Paris828dfe12008-04-17 13:17:49 -04002248 AVC_AUDIT_DATA_INIT(&ad, FS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250 spin_lock(&files->file_lock);
2251 for (;;) {
2252 unsigned long set, i;
2253 int fd;
2254
2255 j++;
2256 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002257 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002258 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 break;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002260 set = fdt->open_fds->fds_bits[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 if (!set)
2262 continue;
2263 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002264 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 if (set & 1) {
2266 file = fget(i);
2267 if (!file)
2268 continue;
David Howells88e67f32008-11-14 10:39:21 +11002269 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 file,
2271 file_to_av(file))) {
2272 sys_close(i);
2273 fd = get_unused_fd();
2274 if (fd != i) {
2275 if (fd >= 0)
2276 put_unused_fd(fd);
2277 fput(file);
2278 continue;
2279 }
2280 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002281 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 } else {
David Howells745ca242008-11-14 10:39:22 +11002283 devnull = dentry_open(
2284 dget(selinux_null),
2285 mntget(selinuxfs_mount),
2286 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002287 if (IS_ERR(devnull)) {
2288 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 put_unused_fd(fd);
2290 fput(file);
2291 continue;
2292 }
2293 }
2294 fd_install(fd, devnull);
2295 }
2296 fput(file);
2297 }
2298 }
2299 spin_lock(&files->file_lock);
2300
2301 }
2302 spin_unlock(&files->file_lock);
2303}
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305/*
David Howellsa6f76f22008-11-14 10:39:24 +11002306 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 */
David Howellsa6f76f22008-11-14 10:39:24 +11002308static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309{
David Howellsa6f76f22008-11-14 10:39:24 +11002310 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 int rc, i;
2313
David Howellsa6f76f22008-11-14 10:39:24 +11002314 new_tsec = bprm->cred->security;
2315 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 return;
2317
2318 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002319 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
David Howellsa6f76f22008-11-14 10:39:24 +11002321 /* Always clear parent death signal on SID transitions. */
2322 current->pdeath_signal = 0;
2323
2324 /* Check whether the new SID can inherit resource limits from the old
2325 * SID. If not, reset all soft limits to the lower of the current
2326 * task's hard limit and the init task's soft limit.
2327 *
2328 * Note that the setting of hard limits (even to lower them) can be
2329 * controlled by the setrlimit check. The inclusion of the init task's
2330 * soft limit into the computation is to avoid resetting soft limits
2331 * higher than the default soft limit for cases where the default is
2332 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2333 */
2334 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2335 PROCESS__RLIMITINH, NULL);
2336 if (rc) {
2337 for (i = 0; i < RLIM_NLIMITS; i++) {
2338 rlim = current->signal->rlim + i;
2339 initrlim = init_task.signal->rlim + i;
2340 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2341 }
2342 update_rlimit_cpu(rlim->rlim_cur);
2343 }
2344}
2345
2346/*
2347 * Clean up the process immediately after the installation of new credentials
2348 * due to exec
2349 */
2350static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2351{
2352 const struct task_security_struct *tsec = current_security();
2353 struct itimerval itimer;
2354 struct sighand_struct *psig;
2355 u32 osid, sid;
2356 int rc, i;
2357 unsigned long flags;
2358
David Howellsa6f76f22008-11-14 10:39:24 +11002359 osid = tsec->osid;
2360 sid = tsec->sid;
2361
2362 if (sid == osid)
2363 return;
2364
2365 /* Check whether the new SID can inherit signal state from the old SID.
2366 * If not, clear itimers to avoid subsequent signal generation and
2367 * flush and unblock signals.
2368 *
2369 * This must occur _after_ the task SID has been updated so that any
2370 * kill done after the flush will be checked against the new SID.
2371 */
2372 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 if (rc) {
2374 memset(&itimer, 0, sizeof itimer);
2375 for (i = 0; i < 3; i++)
2376 do_setitimer(i, &itimer, NULL);
2377 flush_signals(current);
2378 spin_lock_irq(&current->sighand->siglock);
2379 flush_signal_handlers(current, 1);
2380 sigemptyset(&current->blocked);
2381 recalc_sigpending();
2382 spin_unlock_irq(&current->sighand->siglock);
2383 }
2384
David Howellsa6f76f22008-11-14 10:39:24 +11002385 /* Wake up the parent if it is waiting so that it can recheck
2386 * wait permission to the new task SID. */
Eric Paris41d9f9c2008-11-04 15:18:26 -05002387 read_lock_irq(&tasklist_lock);
2388 psig = current->parent->sighand;
2389 spin_lock_irqsave(&psig->siglock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 wake_up_interruptible(&current->parent->signal->wait_chldexit);
Eric Paris41d9f9c2008-11-04 15:18:26 -05002391 spin_unlock_irqrestore(&psig->siglock, flags);
2392 read_unlock_irq(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393}
2394
2395/* superblock security operations */
2396
2397static int selinux_sb_alloc_security(struct super_block *sb)
2398{
2399 return superblock_alloc_security(sb);
2400}
2401
2402static void selinux_sb_free_security(struct super_block *sb)
2403{
2404 superblock_free_security(sb);
2405}
2406
2407static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2408{
2409 if (plen > olen)
2410 return 0;
2411
2412 return !memcmp(prefix, option, plen);
2413}
2414
2415static inline int selinux_option(char *option, int len)
2416{
Eric Paris832cbd92008-04-01 13:24:09 -04002417 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2418 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2419 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002420 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2421 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422}
2423
2424static inline void take_option(char **to, char *from, int *first, int len)
2425{
2426 if (!*first) {
2427 **to = ',';
2428 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002429 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 *first = 0;
2431 memcpy(*to, from, len);
2432 *to += len;
2433}
2434
Eric Paris828dfe12008-04-17 13:17:49 -04002435static inline void take_selinux_option(char **to, char *from, int *first,
2436 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002437{
2438 int current_size = 0;
2439
2440 if (!*first) {
2441 **to = '|';
2442 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002443 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002444 *first = 0;
2445
2446 while (current_size < len) {
2447 if (*from != '"') {
2448 **to = *from;
2449 *to += 1;
2450 }
2451 from += 1;
2452 current_size += 1;
2453 }
2454}
2455
Eric Parise0007522008-03-05 10:31:54 -05002456static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457{
2458 int fnosec, fsec, rc = 0;
2459 char *in_save, *in_curr, *in_end;
2460 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002461 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
2463 in_curr = orig;
2464 sec_curr = copy;
2465
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2467 if (!nosec) {
2468 rc = -ENOMEM;
2469 goto out;
2470 }
2471
2472 nosec_save = nosec;
2473 fnosec = fsec = 1;
2474 in_save = in_end = orig;
2475
2476 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002477 if (*in_end == '"')
2478 open_quote = !open_quote;
2479 if ((*in_end == ',' && open_quote == 0) ||
2480 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 int len = in_end - in_curr;
2482
2483 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002484 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 else
2486 take_option(&nosec, in_curr, &fnosec, len);
2487
2488 in_curr = in_end + 1;
2489 }
2490 } while (*in_end++);
2491
Eric Paris6931dfc2005-06-30 02:58:51 -07002492 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002493 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494out:
2495 return rc;
2496}
2497
James Morris12204e22008-12-19 10:44:42 +11002498static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499{
David Howells88e67f32008-11-14 10:39:21 +11002500 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 struct avc_audit_data ad;
2502 int rc;
2503
2504 rc = superblock_doinit(sb, data);
2505 if (rc)
2506 return rc;
2507
James Morris74192242008-12-19 11:41:10 +11002508 /* Allow all mounts performed by the kernel */
2509 if (flags & MS_KERNMOUNT)
2510 return 0;
2511
Eric Paris828dfe12008-04-17 13:17:49 -04002512 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002513 ad.u.fs.path.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002514 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515}
2516
David Howells726c3342006-06-23 02:02:58 -07002517static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518{
David Howells88e67f32008-11-14 10:39:21 +11002519 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 struct avc_audit_data ad;
2521
Eric Paris828dfe12008-04-17 13:17:49 -04002522 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002523 ad.u.fs.path.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002524 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525}
2526
Eric Paris828dfe12008-04-17 13:17:49 -04002527static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002528 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002529 char *type,
2530 unsigned long flags,
2531 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532{
David Howells88e67f32008-11-14 10:39:21 +11002533 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
2535 if (flags & MS_REMOUNT)
David Howells88e67f32008-11-14 10:39:21 +11002536 return superblock_has_perm(cred, path->mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002537 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 else
David Howells88e67f32008-11-14 10:39:21 +11002539 return dentry_has_perm(cred, path->mnt, path->dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002540 FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541}
2542
2543static int selinux_umount(struct vfsmount *mnt, int flags)
2544{
David Howells88e67f32008-11-14 10:39:21 +11002545 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
David Howells88e67f32008-11-14 10:39:21 +11002547 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002548 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549}
2550
2551/* inode security operations */
2552
2553static int selinux_inode_alloc_security(struct inode *inode)
2554{
2555 return inode_alloc_security(inode);
2556}
2557
2558static void selinux_inode_free_security(struct inode *inode)
2559{
2560 inode_free_security(inode);
2561}
2562
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002563static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2564 char **name, void **value,
2565 size_t *len)
2566{
David Howells275bb412008-11-14 10:39:19 +11002567 const struct cred *cred = current_cred();
2568 const struct task_security_struct *tsec = cred->security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002569 struct inode_security_struct *dsec;
2570 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002571 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002572 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002573 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002574
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002575 dsec = dir->i_security;
2576 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002577
David Howells275bb412008-11-14 10:39:19 +11002578 sid = tsec->sid;
2579 newsid = tsec->create_sid;
2580
David P. Quigleycd895962009-01-16 09:22:04 -05002581 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002582 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002583 inode_mode_to_security_class(inode->i_mode),
2584 &newsid);
2585 if (rc) {
2586 printk(KERN_WARNING "%s: "
2587 "security_transition_sid failed, rc=%d (dev=%s "
2588 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002589 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002590 -rc, inode->i_sb->s_id, inode->i_ino);
2591 return rc;
2592 }
2593 }
2594
Eric Paris296fddf2006-09-25 23:32:00 -07002595 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002596 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002597 struct inode_security_struct *isec = inode->i_security;
2598 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2599 isec->sid = newsid;
2600 isec->initialized = 1;
2601 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002602
David P. Quigleycd895962009-01-16 09:22:04 -05002603 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002604 return -EOPNOTSUPP;
2605
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002606 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002607 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002608 if (!namep)
2609 return -ENOMEM;
2610 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002611 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002612
2613 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002614 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002615 if (rc) {
2616 kfree(namep);
2617 return rc;
2618 }
2619 *value = context;
2620 *len = clen;
2621 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002622
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002623 return 0;
2624}
2625
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
2627{
2628 return may_create(dir, dentry, SECCLASS_FILE);
2629}
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2632{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return may_link(dir, old_dentry, MAY_LINK);
2634}
2635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2637{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 return may_link(dir, dentry, MAY_UNLINK);
2639}
2640
2641static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2642{
2643 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2644}
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
2647{
2648 return may_create(dir, dentry, SECCLASS_DIR);
2649}
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2652{
2653 return may_link(dir, dentry, MAY_RMDIR);
2654}
2655
2656static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
2657{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2659}
2660
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002662 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663{
2664 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2665}
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667static int selinux_inode_readlink(struct dentry *dentry)
2668{
David Howells88e67f32008-11-14 10:39:21 +11002669 const struct cred *cred = current_cred();
2670
2671 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672}
2673
2674static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2675{
David Howells88e67f32008-11-14 10:39:21 +11002676 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
David Howells88e67f32008-11-14 10:39:21 +11002678 return dentry_has_perm(cred, NULL, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679}
2680
Al Virob77b0642008-07-17 09:37:02 -04002681static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
David Howells88e67f32008-11-14 10:39:21 +11002683 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
2685 if (!mask) {
2686 /* No permission to check. Existence test. */
2687 return 0;
2688 }
2689
David Howells88e67f32008-11-14 10:39:21 +11002690 return inode_has_perm(cred, inode,
Eric Paris8b6a5a32008-10-29 17:06:46 -04002691 file_mask_to_av(inode->i_mode, mask), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692}
2693
2694static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2695{
David Howells88e67f32008-11-14 10:39:21 +11002696 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
2698 if (iattr->ia_valid & ATTR_FORCE)
2699 return 0;
2700
2701 if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2702 ATTR_ATIME_SET | ATTR_MTIME_SET))
David Howells88e67f32008-11-14 10:39:21 +11002703 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
David Howells88e67f32008-11-14 10:39:21 +11002705 return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706}
2707
2708static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2709{
David Howells88e67f32008-11-14 10:39:21 +11002710 const struct cred *cred = current_cred();
2711
2712 return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713}
2714
David Howells8f0cfa52008-04-29 00:59:41 -07002715static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002716{
David Howells88e67f32008-11-14 10:39:21 +11002717 const struct cred *cred = current_cred();
2718
Serge E. Hallynb5376772007-10-16 23:31:36 -07002719 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2720 sizeof XATTR_SECURITY_PREFIX - 1)) {
2721 if (!strcmp(name, XATTR_NAME_CAPS)) {
2722 if (!capable(CAP_SETFCAP))
2723 return -EPERM;
2724 } else if (!capable(CAP_SYS_ADMIN)) {
2725 /* A different attribute in the security namespace.
2726 Restrict to administrator. */
2727 return -EPERM;
2728 }
2729 }
2730
2731 /* Not an attribute we recognize, so just check the
2732 ordinary setattr permission. */
David Howells88e67f32008-11-14 10:39:21 +11002733 return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002734}
2735
David Howells8f0cfa52008-04-29 00:59:41 -07002736static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2737 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 struct inode *inode = dentry->d_inode;
2740 struct inode_security_struct *isec = inode->i_security;
2741 struct superblock_security_struct *sbsec;
2742 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002743 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 int rc = 0;
2745
Serge E. Hallynb5376772007-10-16 23:31:36 -07002746 if (strcmp(name, XATTR_NAME_SELINUX))
2747 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
2749 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002750 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return -EOPNOTSUPP;
2752
Satyam Sharma3bd858ab2007-07-17 15:00:08 +05302753 if (!is_owner_or_cap(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 return -EPERM;
2755
Eric Paris828dfe12008-04-17 13:17:49 -04002756 AVC_AUDIT_DATA_INIT(&ad, FS);
Jan Blunck44707fd2008-02-14 19:38:33 -08002757 ad.u.fs.path.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
David Howells275bb412008-11-14 10:39:19 +11002759 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 FILE__RELABELFROM, &ad);
2761 if (rc)
2762 return rc;
2763
2764 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002765 if (rc == -EINVAL) {
2766 if (!capable(CAP_MAC_ADMIN))
2767 return rc;
2768 rc = security_context_to_sid_force(value, size, &newsid);
2769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 if (rc)
2771 return rc;
2772
David Howells275bb412008-11-14 10:39:19 +11002773 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 FILE__RELABELTO, &ad);
2775 if (rc)
2776 return rc;
2777
David Howells275bb412008-11-14 10:39:19 +11002778 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002779 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 if (rc)
2781 return rc;
2782
2783 return avc_has_perm(newsid,
2784 sbsec->sid,
2785 SECCLASS_FILESYSTEM,
2786 FILESYSTEM__ASSOCIATE,
2787 &ad);
2788}
2789
David Howells8f0cfa52008-04-29 00:59:41 -07002790static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002791 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002792 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793{
2794 struct inode *inode = dentry->d_inode;
2795 struct inode_security_struct *isec = inode->i_security;
2796 u32 newsid;
2797 int rc;
2798
2799 if (strcmp(name, XATTR_NAME_SELINUX)) {
2800 /* Not an attribute we recognize, so nothing to do. */
2801 return;
2802 }
2803
Stephen Smalley12b29f32008-05-07 13:03:20 -04002804 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002806 printk(KERN_ERR "SELinux: unable to map context to SID"
2807 "for (%s, %lu), rc=%d\n",
2808 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 return;
2810 }
2811
2812 isec->sid = newsid;
2813 return;
2814}
2815
David Howells8f0cfa52008-04-29 00:59:41 -07002816static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817{
David Howells88e67f32008-11-14 10:39:21 +11002818 const struct cred *cred = current_cred();
2819
2820 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821}
2822
Eric Paris828dfe12008-04-17 13:17:49 -04002823static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824{
David Howells88e67f32008-11-14 10:39:21 +11002825 const struct cred *cred = current_cred();
2826
2827 return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828}
2829
David Howells8f0cfa52008-04-29 00:59:41 -07002830static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002832 if (strcmp(name, XATTR_NAME_SELINUX))
2833 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834
2835 /* No one is allowed to remove a SELinux security label.
2836 You can change the label, but all data must be labeled. */
2837 return -EACCES;
2838}
2839
James Morrisd381d8a2005-10-30 14:59:22 -08002840/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002841 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002842 *
2843 * Permission check is handled by selinux_inode_getxattr hook.
2844 */
David P. Quigley42492592008-02-04 22:29:39 -08002845static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
David P. Quigley42492592008-02-04 22:29:39 -08002847 u32 size;
2848 int error;
2849 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002852 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2853 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002855 /*
2856 * If the caller has CAP_MAC_ADMIN, then get the raw context
2857 * value even if it is not defined by current policy; otherwise,
2858 * use the in-core value under current policy.
2859 * Use the non-auditing forms of the permission checks since
2860 * getxattr may be called by unprivileged processes commonly
2861 * and lack of permission just means that we fall back to the
2862 * in-core context value, not a denial.
2863 */
David Howells3699c532009-01-06 22:27:01 +00002864 error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
2865 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002866 if (!error)
2867 error = security_sid_to_context_force(isec->sid, &context,
2868 &size);
2869 else
2870 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002871 if (error)
2872 return error;
2873 error = size;
2874 if (alloc) {
2875 *buffer = context;
2876 goto out_nofree;
2877 }
2878 kfree(context);
2879out_nofree:
2880 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881}
2882
2883static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002884 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885{
2886 struct inode_security_struct *isec = inode->i_security;
2887 u32 newsid;
2888 int rc;
2889
2890 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2891 return -EOPNOTSUPP;
2892
2893 if (!value || !size)
2894 return -EACCES;
2895
Eric Paris828dfe12008-04-17 13:17:49 -04002896 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 if (rc)
2898 return rc;
2899
2900 isec->sid = newsid;
2901 return 0;
2902}
2903
2904static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2905{
2906 const int len = sizeof(XATTR_NAME_SELINUX);
2907 if (buffer && len <= buffer_size)
2908 memcpy(buffer, XATTR_NAME_SELINUX, len);
2909 return len;
2910}
2911
Serge E. Hallynb5376772007-10-16 23:31:36 -07002912static int selinux_inode_need_killpriv(struct dentry *dentry)
2913{
2914 return secondary_ops->inode_need_killpriv(dentry);
2915}
2916
2917static int selinux_inode_killpriv(struct dentry *dentry)
2918{
2919 return secondary_ops->inode_killpriv(dentry);
2920}
2921
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02002922static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2923{
2924 struct inode_security_struct *isec = inode->i_security;
2925 *secid = isec->sid;
2926}
2927
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928/* file security operations */
2929
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002930static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
David Howells88e67f32008-11-14 10:39:21 +11002932 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002933 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002934 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 if (!mask) {
2937 /* No permission to check. Existence test. */
2938 return 0;
2939 }
2940
2941 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2942 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2943 mask |= MAY_APPEND;
2944
David Howells88e67f32008-11-14 10:39:21 +11002945 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002946 file_mask_to_av(inode->i_mode, mask));
2947 if (rc)
2948 return rc;
2949
2950 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951}
2952
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002953static int selinux_file_permission(struct file *file, int mask)
2954{
2955 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002956 struct file_security_struct *fsec = file->f_security;
2957 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11002958 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002959
2960 if (!mask) {
2961 /* No permission to check. Existence test. */
2962 return 0;
2963 }
2964
David Howells275bb412008-11-14 10:39:19 +11002965 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002966 && fsec->pseqno == avc_policy_seqno())
2967 return selinux_netlbl_inode_permission(inode, mask);
2968
2969 return selinux_revalidate_file_permission(file, mask);
2970}
2971
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972static int selinux_file_alloc_security(struct file *file)
2973{
2974 return file_alloc_security(file);
2975}
2976
2977static void selinux_file_free_security(struct file *file)
2978{
2979 file_free_security(file);
2980}
2981
2982static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2983 unsigned long arg)
2984{
David Howells88e67f32008-11-14 10:39:21 +11002985 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04002986 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Stephen Smalley242631c2008-06-05 09:21:28 -04002988 if (_IOC_DIR(cmd) & _IOC_WRITE)
2989 av |= FILE__WRITE;
2990 if (_IOC_DIR(cmd) & _IOC_READ)
2991 av |= FILE__READ;
2992 if (!av)
2993 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
David Howells88e67f32008-11-14 10:39:21 +11002995 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996}
2997
2998static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
2999{
David Howells88e67f32008-11-14 10:39:21 +11003000 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003001 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003#ifndef CONFIG_PPC32
3004 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3005 /*
3006 * We are making executable an anonymous mapping or a
3007 * private file mapping that will also be writable.
3008 * This has an additional check.
3009 */
David Howellsd84f4f92008-11-14 10:39:23 +11003010 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003012 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 }
3014#endif
3015
3016 if (file) {
3017 /* read access is always possible with a mapping */
3018 u32 av = FILE__READ;
3019
3020 /* write access only matters if the mapping is shared */
3021 if (shared && (prot & PROT_WRITE))
3022 av |= FILE__WRITE;
3023
3024 if (prot & PROT_EXEC)
3025 av |= FILE__EXECUTE;
3026
David Howells88e67f32008-11-14 10:39:21 +11003027 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 }
David Howellsd84f4f92008-11-14 10:39:23 +11003029
3030error:
3031 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032}
3033
3034static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003035 unsigned long prot, unsigned long flags,
3036 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037{
Eric Parised032182007-06-28 15:55:21 -04003038 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003039 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
Eric Parised032182007-06-28 15:55:21 -04003041 if (addr < mmap_min_addr)
3042 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3043 MEMPROTECT__MMAP_ZERO, NULL);
3044 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 return rc;
3046
3047 if (selinux_checkreqprot)
3048 prot = reqprot;
3049
3050 return file_map_prot_check(file, prot,
3051 (flags & MAP_TYPE) == MAP_SHARED);
3052}
3053
3054static int selinux_file_mprotect(struct vm_area_struct *vma,
3055 unsigned long reqprot,
3056 unsigned long prot)
3057{
David Howells88e67f32008-11-14 10:39:21 +11003058 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 int rc;
3060
3061 rc = secondary_ops->file_mprotect(vma, reqprot, prot);
3062 if (rc)
3063 return rc;
3064
3065 if (selinux_checkreqprot)
3066 prot = reqprot;
3067
3068#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003069 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3070 rc = 0;
3071 if (vma->vm_start >= vma->vm_mm->start_brk &&
3072 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003073 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003074 } else if (!vma->vm_file &&
3075 vma->vm_start <= vma->vm_mm->start_stack &&
3076 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003077 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003078 } else if (vma->vm_file && vma->anon_vma) {
3079 /*
3080 * We are making executable a file mapping that has
3081 * had some COW done. Since pages might have been
3082 * written, check ability to execute the possibly
3083 * modified content. This typically should only
3084 * occur for text relocations.
3085 */
David Howellsd84f4f92008-11-14 10:39:23 +11003086 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003087 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003088 if (rc)
3089 return rc;
3090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091#endif
3092
3093 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3094}
3095
3096static int selinux_file_lock(struct file *file, unsigned int cmd)
3097{
David Howells88e67f32008-11-14 10:39:21 +11003098 const struct cred *cred = current_cred();
3099
3100 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101}
3102
3103static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3104 unsigned long arg)
3105{
David Howells88e67f32008-11-14 10:39:21 +11003106 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 int err = 0;
3108
3109 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003110 case F_SETFL:
3111 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3112 err = -EINVAL;
3113 break;
3114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
Eric Paris828dfe12008-04-17 13:17:49 -04003116 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003117 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003119 }
3120 /* fall through */
3121 case F_SETOWN:
3122 case F_SETSIG:
3123 case F_GETFL:
3124 case F_GETOWN:
3125 case F_GETSIG:
3126 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003127 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003128 break;
3129 case F_GETLK:
3130 case F_SETLK:
3131 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003133 case F_GETLK64:
3134 case F_SETLK64:
3135 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003137 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3138 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003140 }
David Howells88e67f32008-11-14 10:39:21 +11003141 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003142 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 }
3144
3145 return err;
3146}
3147
3148static int selinux_file_set_fowner(struct file *file)
3149{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 struct file_security_struct *fsec;
3151
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003153 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154
3155 return 0;
3156}
3157
3158static int selinux_file_send_sigiotask(struct task_struct *tsk,
3159 struct fown_struct *fown, int signum)
3160{
Eric Paris828dfe12008-04-17 13:17:49 -04003161 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003162 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 struct file_security_struct *fsec;
3165
3166 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003167 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 fsec = file->f_security;
3170
3171 if (!signum)
3172 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3173 else
3174 perm = signal_to_av(signum);
3175
David Howells275bb412008-11-14 10:39:19 +11003176 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 SECCLASS_PROCESS, perm, NULL);
3178}
3179
3180static int selinux_file_receive(struct file *file)
3181{
David Howells88e67f32008-11-14 10:39:21 +11003182 const struct cred *cred = current_cred();
3183
3184 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185}
3186
David Howells745ca242008-11-14 10:39:22 +11003187static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003188{
3189 struct file_security_struct *fsec;
3190 struct inode *inode;
3191 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003192
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003193 inode = file->f_path.dentry->d_inode;
3194 fsec = file->f_security;
3195 isec = inode->i_security;
3196 /*
3197 * Save inode label and policy sequence number
3198 * at open-time so that selinux_file_permission
3199 * can determine whether revalidation is necessary.
3200 * Task label is already saved in the file security
3201 * struct as its SID.
3202 */
3203 fsec->isid = isec->sid;
3204 fsec->pseqno = avc_policy_seqno();
3205 /*
3206 * Since the inode label or policy seqno may have changed
3207 * between the selinux_inode_permission check and the saving
3208 * of state above, recheck that access is still permitted.
3209 * Otherwise, access might never be revalidated against the
3210 * new inode label or new policy.
3211 * This check is not redundant - do not remove.
3212 */
David Howells88e67f32008-11-14 10:39:21 +11003213 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003214}
3215
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216/* task security operations */
3217
3218static int selinux_task_create(unsigned long clone_flags)
3219{
3220 int rc;
3221
3222 rc = secondary_ops->task_create(clone_flags);
3223 if (rc)
3224 return rc;
3225
David Howells3b11a1d2008-11-14 10:39:26 +11003226 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227}
3228
David Howellsf1752ee2008-11-14 10:39:17 +11003229/*
3230 * detach and free the LSM part of a set of credentials
3231 */
3232static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
David Howellsf1752ee2008-11-14 10:39:17 +11003234 struct task_security_struct *tsec = cred->security;
3235 cred->security = NULL;
3236 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237}
3238
David Howellsd84f4f92008-11-14 10:39:23 +11003239/*
3240 * prepare a new set of credentials for modification
3241 */
3242static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3243 gfp_t gfp)
3244{
3245 const struct task_security_struct *old_tsec;
3246 struct task_security_struct *tsec;
3247
3248 old_tsec = old->security;
3249
3250 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3251 if (!tsec)
3252 return -ENOMEM;
3253
3254 new->security = tsec;
3255 return 0;
3256}
3257
3258/*
3259 * commit new credentials
3260 */
3261static void selinux_cred_commit(struct cred *new, const struct cred *old)
3262{
3263 secondary_ops->cred_commit(new, old);
3264}
3265
David Howells3a3b7ce2008-11-14 10:39:28 +11003266/*
3267 * set the security data for a kernel service
3268 * - all the creation contexts are set to unlabelled
3269 */
3270static int selinux_kernel_act_as(struct cred *new, u32 secid)
3271{
3272 struct task_security_struct *tsec = new->security;
3273 u32 sid = current_sid();
3274 int ret;
3275
3276 ret = avc_has_perm(sid, secid,
3277 SECCLASS_KERNEL_SERVICE,
3278 KERNEL_SERVICE__USE_AS_OVERRIDE,
3279 NULL);
3280 if (ret == 0) {
3281 tsec->sid = secid;
3282 tsec->create_sid = 0;
3283 tsec->keycreate_sid = 0;
3284 tsec->sockcreate_sid = 0;
3285 }
3286 return ret;
3287}
3288
3289/*
3290 * set the file creation context in a security record to the same as the
3291 * objective context of the specified inode
3292 */
3293static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3294{
3295 struct inode_security_struct *isec = inode->i_security;
3296 struct task_security_struct *tsec = new->security;
3297 u32 sid = current_sid();
3298 int ret;
3299
3300 ret = avc_has_perm(sid, isec->sid,
3301 SECCLASS_KERNEL_SERVICE,
3302 KERNEL_SERVICE__CREATE_FILES_AS,
3303 NULL);
3304
3305 if (ret == 0)
3306 tsec->create_sid = isec->sid;
3307 return 0;
3308}
3309
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3311{
3312 /* Since setuid only affects the current process, and
3313 since the SELinux controls are not based on the Linux
3314 identity attributes, SELinux does not need to control
3315 this operation. However, SELinux does control the use
3316 of the CAP_SETUID and CAP_SETGID capabilities using the
3317 capable hook. */
3318 return 0;
3319}
3320
David Howellsd84f4f92008-11-14 10:39:23 +11003321static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3322 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323{
David Howellsd84f4f92008-11-14 10:39:23 +11003324 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325}
3326
3327static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3328{
3329 /* See the comment for setuid above. */
3330 return 0;
3331}
3332
3333static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3334{
David Howells3b11a1d2008-11-14 10:39:26 +11003335 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336}
3337
3338static int selinux_task_getpgid(struct task_struct *p)
3339{
David Howells3b11a1d2008-11-14 10:39:26 +11003340 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341}
3342
3343static int selinux_task_getsid(struct task_struct *p)
3344{
David Howells3b11a1d2008-11-14 10:39:26 +11003345 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346}
3347
David Quigleyf9008e4c2006-06-30 01:55:46 -07003348static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3349{
David Howells275bb412008-11-14 10:39:19 +11003350 *secid = task_sid(p);
David Quigleyf9008e4c2006-06-30 01:55:46 -07003351}
3352
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353static int selinux_task_setgroups(struct group_info *group_info)
3354{
3355 /* See the comment for setuid above. */
3356 return 0;
3357}
3358
3359static int selinux_task_setnice(struct task_struct *p, int nice)
3360{
3361 int rc;
3362
3363 rc = secondary_ops->task_setnice(p, nice);
3364 if (rc)
3365 return rc;
3366
David Howells3b11a1d2008-11-14 10:39:26 +11003367 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368}
3369
James Morris03e68062006-06-23 02:03:58 -07003370static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3371{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003372 int rc;
3373
3374 rc = secondary_ops->task_setioprio(p, ioprio);
3375 if (rc)
3376 return rc;
3377
David Howells3b11a1d2008-11-14 10:39:26 +11003378 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003379}
3380
David Quigleya1836a42006-06-30 01:55:49 -07003381static int selinux_task_getioprio(struct task_struct *p)
3382{
David Howells3b11a1d2008-11-14 10:39:26 +11003383 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003384}
3385
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3387{
3388 struct rlimit *old_rlim = current->signal->rlim + resource;
3389 int rc;
3390
3391 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3392 if (rc)
3393 return rc;
3394
3395 /* Control the ability to change the hard limit (whether
3396 lowering or raising it), so that the hard limit can
3397 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003398 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003400 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
3402 return 0;
3403}
3404
3405static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3406{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003407 int rc;
3408
3409 rc = secondary_ops->task_setscheduler(p, policy, lp);
3410 if (rc)
3411 return rc;
3412
David Howells3b11a1d2008-11-14 10:39:26 +11003413 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414}
3415
3416static int selinux_task_getscheduler(struct task_struct *p)
3417{
David Howells3b11a1d2008-11-14 10:39:26 +11003418 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419}
3420
David Quigley35601542006-06-23 02:04:01 -07003421static int selinux_task_movememory(struct task_struct *p)
3422{
David Howells3b11a1d2008-11-14 10:39:26 +11003423 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003424}
3425
David Quigleyf9008e4c2006-06-30 01:55:46 -07003426static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3427 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428{
3429 u32 perm;
3430 int rc;
3431
David Quigleyf9008e4c2006-06-30 01:55:46 -07003432 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 if (rc)
3434 return rc;
3435
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 if (!sig)
3437 perm = PROCESS__SIGNULL; /* null signal; existence test */
3438 else
3439 perm = signal_to_av(sig);
David Quigleyf9008e4c2006-06-30 01:55:46 -07003440 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003441 rc = avc_has_perm(secid, task_sid(p),
3442 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e4c2006-06-30 01:55:46 -07003443 else
David Howells3b11a1d2008-11-14 10:39:26 +11003444 rc = current_has_perm(p, perm);
David Quigleyf9008e4c2006-06-30 01:55:46 -07003445 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446}
3447
3448static int selinux_task_prctl(int option,
3449 unsigned long arg2,
3450 unsigned long arg3,
3451 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003452 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453{
3454 /* The current prctl operations do not appear to require
3455 any SELinux controls since they merely observe or modify
3456 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003457 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458}
3459
3460static int selinux_task_wait(struct task_struct *p)
3461{
Eric Paris8a535142007-10-22 16:10:31 -04003462 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463}
3464
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465static void selinux_task_to_inode(struct task_struct *p,
3466 struct inode *inode)
3467{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003469 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470
David Howells275bb412008-11-14 10:39:19 +11003471 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473}
3474
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003476static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3477 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478{
3479 int offset, ihlen, ret = -EINVAL;
3480 struct iphdr _iph, *ih;
3481
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003482 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3484 if (ih == NULL)
3485 goto out;
3486
3487 ihlen = ih->ihl * 4;
3488 if (ihlen < sizeof(_iph))
3489 goto out;
3490
3491 ad->u.net.v4info.saddr = ih->saddr;
3492 ad->u.net.v4info.daddr = ih->daddr;
3493 ret = 0;
3494
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003495 if (proto)
3496 *proto = ih->protocol;
3497
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003499 case IPPROTO_TCP: {
3500 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
Eric Paris828dfe12008-04-17 13:17:49 -04003502 if (ntohs(ih->frag_off) & IP_OFFSET)
3503 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
3505 offset += ihlen;
3506 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3507 if (th == NULL)
3508 break;
3509
3510 ad->u.net.sport = th->source;
3511 ad->u.net.dport = th->dest;
3512 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
Eric Paris828dfe12008-04-17 13:17:49 -04003515 case IPPROTO_UDP: {
3516 struct udphdr _udph, *uh;
3517
3518 if (ntohs(ih->frag_off) & IP_OFFSET)
3519 break;
3520
3521 offset += ihlen;
3522 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3523 if (uh == NULL)
3524 break;
3525
3526 ad->u.net.sport = uh->source;
3527 ad->u.net.dport = uh->dest;
3528 break;
3529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
James Morris2ee92d42006-11-13 16:09:01 -08003531 case IPPROTO_DCCP: {
3532 struct dccp_hdr _dccph, *dh;
3533
3534 if (ntohs(ih->frag_off) & IP_OFFSET)
3535 break;
3536
3537 offset += ihlen;
3538 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3539 if (dh == NULL)
3540 break;
3541
3542 ad->u.net.sport = dh->dccph_sport;
3543 ad->u.net.dport = dh->dccph_dport;
3544 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003545 }
James Morris2ee92d42006-11-13 16:09:01 -08003546
Eric Paris828dfe12008-04-17 13:17:49 -04003547 default:
3548 break;
3549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550out:
3551 return ret;
3552}
3553
3554#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3555
3556/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003557static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3558 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559{
3560 u8 nexthdr;
3561 int ret = -EINVAL, offset;
3562 struct ipv6hdr _ipv6h, *ip6;
3563
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003564 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3566 if (ip6 == NULL)
3567 goto out;
3568
3569 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3570 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3571 ret = 0;
3572
3573 nexthdr = ip6->nexthdr;
3574 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003575 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 if (offset < 0)
3577 goto out;
3578
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003579 if (proto)
3580 *proto = nexthdr;
3581
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 switch (nexthdr) {
3583 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003584 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585
3586 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3587 if (th == NULL)
3588 break;
3589
3590 ad->u.net.sport = th->source;
3591 ad->u.net.dport = th->dest;
3592 break;
3593 }
3594
3595 case IPPROTO_UDP: {
3596 struct udphdr _udph, *uh;
3597
3598 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3599 if (uh == NULL)
3600 break;
3601
3602 ad->u.net.sport = uh->source;
3603 ad->u.net.dport = uh->dest;
3604 break;
3605 }
3606
James Morris2ee92d42006-11-13 16:09:01 -08003607 case IPPROTO_DCCP: {
3608 struct dccp_hdr _dccph, *dh;
3609
3610 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3611 if (dh == NULL)
3612 break;
3613
3614 ad->u.net.sport = dh->dccph_sport;
3615 ad->u.net.dport = dh->dccph_dport;
3616 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003617 }
James Morris2ee92d42006-11-13 16:09:01 -08003618
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 /* includes fragments */
3620 default:
3621 break;
3622 }
3623out:
3624 return ret;
3625}
3626
3627#endif /* IPV6 */
3628
3629static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003630 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631{
David Howellscf9481e2008-07-27 21:31:07 +10003632 char *addrp;
3633 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634
3635 switch (ad->u.net.family) {
3636 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003637 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003638 if (ret)
3639 goto parse_error;
3640 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3641 &ad->u.net.v4info.daddr);
3642 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643
3644#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3645 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003646 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003647 if (ret)
3648 goto parse_error;
3649 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3650 &ad->u.net.v6info.daddr);
3651 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652#endif /* IPV6 */
3653 default:
David Howellscf9481e2008-07-27 21:31:07 +10003654 addrp = NULL;
3655 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 }
3657
David Howellscf9481e2008-07-27 21:31:07 +10003658parse_error:
3659 printk(KERN_WARNING
3660 "SELinux: failure in selinux_parse_skb(),"
3661 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003663
3664okay:
3665 if (_addrp)
3666 *_addrp = addrp;
3667 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668}
3669
Paul Moore4f6a9932007-03-01 14:35:22 -05003670/**
Paul Moore220deb92008-01-29 08:38:23 -05003671 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003672 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003673 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003674 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003675 *
3676 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003677 * Check the various different forms of network peer labeling and determine
3678 * the peer label/SID for the packet; most of the magic actually occurs in
3679 * the security server function security_net_peersid_cmp(). The function
3680 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3681 * or -EACCES if @sid is invalid due to inconsistencies with the different
3682 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003683 *
3684 */
Paul Moore220deb92008-01-29 08:38:23 -05003685static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003686{
Paul Moore71f1cb02008-01-29 08:51:16 -05003687 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003688 u32 xfrm_sid;
3689 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003690 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003691
3692 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003693 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003694
Paul Moore71f1cb02008-01-29 08:51:16 -05003695 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3696 if (unlikely(err)) {
3697 printk(KERN_WARNING
3698 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3699 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003700 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003701 }
Paul Moore220deb92008-01-29 08:38:23 -05003702
3703 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003704}
3705
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706/* socket security operations */
3707static int socket_has_perm(struct task_struct *task, struct socket *sock,
3708 u32 perms)
3709{
3710 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003712 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 int err = 0;
3714
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 isec = SOCK_INODE(sock)->i_security;
3716
3717 if (isec->sid == SECINITSID_KERNEL)
3718 goto out;
David Howells275bb412008-11-14 10:39:19 +11003719 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
Eric Paris828dfe12008-04-17 13:17:49 -04003721 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003723 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
3725out:
3726 return err;
3727}
3728
3729static int selinux_socket_create(int family, int type,
3730 int protocol, int kern)
3731{
David Howells275bb412008-11-14 10:39:19 +11003732 const struct cred *cred = current_cred();
3733 const struct task_security_struct *tsec = cred->security;
3734 u32 sid, newsid;
3735 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737
3738 if (kern)
3739 goto out;
3740
David Howells275bb412008-11-14 10:39:19 +11003741 sid = tsec->sid;
3742 newsid = tsec->sockcreate_sid ?: sid;
3743
3744 secclass = socket_type_to_security_class(family, type, protocol);
3745 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
3747out:
3748 return err;
3749}
3750
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003751static int selinux_socket_post_create(struct socket *sock, int family,
3752 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753{
David Howells275bb412008-11-14 10:39:19 +11003754 const struct cred *cred = current_cred();
3755 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003757 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003758 u32 sid, newsid;
3759 int err = 0;
3760
3761 sid = tsec->sid;
3762 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
3764 isec = SOCK_INODE(sock)->i_security;
3765
David Howells275bb412008-11-14 10:39:19 +11003766 if (kern)
3767 isec->sid = SECINITSID_KERNEL;
3768 else if (newsid)
3769 isec->sid = newsid;
3770 else
3771 isec->sid = sid;
3772
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 isec->initialized = 1;
3775
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003776 if (sock->sk) {
3777 sksec = sock->sk->sk_security;
3778 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003779 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003780 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003781 }
3782
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003783 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784}
3785
3786/* Range of port numbers used to automatically bind.
3787 Need to determine whether we should perform a name_bind
3788 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
3790static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3791{
3792 u16 family;
3793 int err;
3794
3795 err = socket_has_perm(current, sock, SOCKET__BIND);
3796 if (err)
3797 goto out;
3798
3799 /*
3800 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003801 * Multiple address binding for SCTP is not supported yet: we just
3802 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 */
3804 family = sock->sk->sk_family;
3805 if (family == PF_INET || family == PF_INET6) {
3806 char *addrp;
3807 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 struct avc_audit_data ad;
3809 struct sockaddr_in *addr4 = NULL;
3810 struct sockaddr_in6 *addr6 = NULL;
3811 unsigned short snum;
3812 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003813 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 isec = SOCK_INODE(sock)->i_security;
3816
3817 if (family == PF_INET) {
3818 addr4 = (struct sockaddr_in *)address;
3819 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 addrp = (char *)&addr4->sin_addr.s_addr;
3821 } else {
3822 addr6 = (struct sockaddr_in6 *)address;
3823 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 addrp = (char *)&addr6->sin6_addr.s6_addr;
3825 }
3826
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003827 if (snum) {
3828 int low, high;
3829
3830 inet_get_local_port_range(&low, &high);
3831
3832 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003833 err = sel_netport_sid(sk->sk_protocol,
3834 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003835 if (err)
3836 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003837 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003838 ad.u.net.sport = htons(snum);
3839 ad.u.net.family = family;
3840 err = avc_has_perm(isec->sid, sid,
3841 isec->sclass,
3842 SOCKET__NAME_BIND, &ad);
3843 if (err)
3844 goto out;
3845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 }
Eric Paris828dfe12008-04-17 13:17:49 -04003847
3848 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003849 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 node_perm = TCP_SOCKET__NODE_BIND;
3851 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003852
James Morris13402582005-09-30 14:24:34 -04003853 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 node_perm = UDP_SOCKET__NODE_BIND;
3855 break;
James Morris2ee92d42006-11-13 16:09:01 -08003856
3857 case SECCLASS_DCCP_SOCKET:
3858 node_perm = DCCP_SOCKET__NODE_BIND;
3859 break;
3860
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 default:
3862 node_perm = RAWIP_SOCKET__NODE_BIND;
3863 break;
3864 }
Eric Paris828dfe12008-04-17 13:17:49 -04003865
Paul Moore224dfbd2008-01-29 08:38:13 -05003866 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 if (err)
3868 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003869
3870 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 ad.u.net.sport = htons(snum);
3872 ad.u.net.family = family;
3873
3874 if (family == PF_INET)
3875 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3876 else
3877 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3878
3879 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003880 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 if (err)
3882 goto out;
3883 }
3884out:
3885 return err;
3886}
3887
3888static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3889{
Paul Moore014ab192008-10-10 10:16:33 -04003890 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 struct inode_security_struct *isec;
3892 int err;
3893
3894 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3895 if (err)
3896 return err;
3897
3898 /*
James Morris2ee92d42006-11-13 16:09:01 -08003899 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 */
3901 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003902 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3903 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 struct avc_audit_data ad;
3905 struct sockaddr_in *addr4 = NULL;
3906 struct sockaddr_in6 *addr6 = NULL;
3907 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003908 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
3910 if (sk->sk_family == PF_INET) {
3911 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003912 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 return -EINVAL;
3914 snum = ntohs(addr4->sin_port);
3915 } else {
3916 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003917 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 return -EINVAL;
3919 snum = ntohs(addr6->sin6_port);
3920 }
3921
Paul Moore3e112172008-04-10 10:48:14 -04003922 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 if (err)
3924 goto out;
3925
James Morris2ee92d42006-11-13 16:09:01 -08003926 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3927 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3928
Eric Paris828dfe12008-04-17 13:17:49 -04003929 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 ad.u.net.dport = htons(snum);
3931 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003932 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 if (err)
3934 goto out;
3935 }
3936
Paul Moore014ab192008-10-10 10:16:33 -04003937 err = selinux_netlbl_socket_connect(sk, address);
3938
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939out:
3940 return err;
3941}
3942
3943static int selinux_socket_listen(struct socket *sock, int backlog)
3944{
3945 return socket_has_perm(current, sock, SOCKET__LISTEN);
3946}
3947
3948static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3949{
3950 int err;
3951 struct inode_security_struct *isec;
3952 struct inode_security_struct *newisec;
3953
3954 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3955 if (err)
3956 return err;
3957
3958 newisec = SOCK_INODE(newsock)->i_security;
3959
3960 isec = SOCK_INODE(sock)->i_security;
3961 newisec->sclass = isec->sclass;
3962 newisec->sid = isec->sid;
3963 newisec->initialized = 1;
3964
3965 return 0;
3966}
3967
3968static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003969 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003971 int rc;
3972
3973 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3974 if (rc)
3975 return rc;
3976
3977 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978}
3979
3980static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3981 int size, int flags)
3982{
3983 return socket_has_perm(current, sock, SOCKET__READ);
3984}
3985
3986static int selinux_socket_getsockname(struct socket *sock)
3987{
3988 return socket_has_perm(current, sock, SOCKET__GETATTR);
3989}
3990
3991static int selinux_socket_getpeername(struct socket *sock)
3992{
3993 return socket_has_perm(current, sock, SOCKET__GETATTR);
3994}
3995
Eric Paris828dfe12008-04-17 13:17:49 -04003996static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997{
Paul Mooref8687af2006-10-30 15:22:15 -08003998 int err;
3999
4000 err = socket_has_perm(current, sock, SOCKET__SETOPT);
4001 if (err)
4002 return err;
4003
4004 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005}
4006
4007static int selinux_socket_getsockopt(struct socket *sock, int level,
4008 int optname)
4009{
4010 return socket_has_perm(current, sock, SOCKET__GETOPT);
4011}
4012
4013static int selinux_socket_shutdown(struct socket *sock, int how)
4014{
4015 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
4016}
4017
4018static int selinux_socket_unix_stream_connect(struct socket *sock,
4019 struct socket *other,
4020 struct sock *newsk)
4021{
4022 struct sk_security_struct *ssec;
4023 struct inode_security_struct *isec;
4024 struct inode_security_struct *other_isec;
4025 struct avc_audit_data ad;
4026 int err;
4027
4028 err = secondary_ops->unix_stream_connect(sock, other, newsk);
4029 if (err)
4030 return err;
4031
4032 isec = SOCK_INODE(sock)->i_security;
4033 other_isec = SOCK_INODE(other)->i_security;
4034
Eric Paris828dfe12008-04-17 13:17:49 -04004035 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 ad.u.net.sk = other->sk;
4037
4038 err = avc_has_perm(isec->sid, other_isec->sid,
4039 isec->sclass,
4040 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4041 if (err)
4042 return err;
4043
4044 /* connecting socket */
4045 ssec = sock->sk->sk_security;
4046 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004047
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 /* server child socket */
4049 ssec = newsk->sk_security;
4050 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004051 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4052
4053 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054}
4055
4056static int selinux_socket_unix_may_send(struct socket *sock,
4057 struct socket *other)
4058{
4059 struct inode_security_struct *isec;
4060 struct inode_security_struct *other_isec;
4061 struct avc_audit_data ad;
4062 int err;
4063
4064 isec = SOCK_INODE(sock)->i_security;
4065 other_isec = SOCK_INODE(other)->i_security;
4066
Eric Paris828dfe12008-04-17 13:17:49 -04004067 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 ad.u.net.sk = other->sk;
4069
4070 err = avc_has_perm(isec->sid, other_isec->sid,
4071 isec->sclass, SOCKET__SENDTO, &ad);
4072 if (err)
4073 return err;
4074
4075 return 0;
4076}
4077
Paul Mooreeffad8d2008-01-29 08:49:27 -05004078static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4079 u32 peer_sid,
4080 struct avc_audit_data *ad)
4081{
4082 int err;
4083 u32 if_sid;
4084 u32 node_sid;
4085
4086 err = sel_netif_sid(ifindex, &if_sid);
4087 if (err)
4088 return err;
4089 err = avc_has_perm(peer_sid, if_sid,
4090 SECCLASS_NETIF, NETIF__INGRESS, ad);
4091 if (err)
4092 return err;
4093
4094 err = sel_netnode_sid(addrp, family, &node_sid);
4095 if (err)
4096 return err;
4097 return avc_has_perm(peer_sid, node_sid,
4098 SECCLASS_NODE, NODE__RECVFROM, ad);
4099}
4100
Paul Moore220deb92008-01-29 08:38:23 -05004101static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4102 struct sk_buff *skb,
4103 struct avc_audit_data *ad,
4104 u16 family,
4105 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106{
Paul Moore220deb92008-01-29 08:38:23 -05004107 int err;
4108 struct sk_security_struct *sksec = sk->sk_security;
4109 u16 sk_class;
4110 u32 netif_perm, node_perm, recv_perm;
4111 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004112
Paul Moore220deb92008-01-29 08:38:23 -05004113 sk_sid = sksec->sid;
4114 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
Paul Moore220deb92008-01-29 08:38:23 -05004116 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 case SECCLASS_UDP_SOCKET:
4118 netif_perm = NETIF__UDP_RECV;
4119 node_perm = NODE__UDP_RECV;
4120 recv_perm = UDP_SOCKET__RECV_MSG;
4121 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 case SECCLASS_TCP_SOCKET:
4123 netif_perm = NETIF__TCP_RECV;
4124 node_perm = NODE__TCP_RECV;
4125 recv_perm = TCP_SOCKET__RECV_MSG;
4126 break;
James Morris2ee92d42006-11-13 16:09:01 -08004127 case SECCLASS_DCCP_SOCKET:
4128 netif_perm = NETIF__DCCP_RECV;
4129 node_perm = NODE__DCCP_RECV;
4130 recv_perm = DCCP_SOCKET__RECV_MSG;
4131 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 default:
4133 netif_perm = NETIF__RAWIP_RECV;
4134 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004135 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 break;
4137 }
4138
Paul Moore220deb92008-01-29 08:38:23 -05004139 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004141 return err;
4142 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4143 if (err)
4144 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004145
Paul Moore224dfbd2008-01-29 08:38:13 -05004146 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004148 return err;
4149 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004151 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
Paul Moore220deb92008-01-29 08:38:23 -05004153 if (!recv_perm)
4154 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004155 err = sel_netport_sid(sk->sk_protocol,
4156 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004157 if (unlikely(err)) {
4158 printk(KERN_WARNING
4159 "SELinux: failure in"
4160 " selinux_sock_rcv_skb_iptables_compat(),"
4161 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004162 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004163 }
Paul Moore220deb92008-01-29 08:38:23 -05004164 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4165}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166
Paul Moore220deb92008-01-29 08:38:23 -05004167static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004168 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004169{
Paul Moore277d3422008-12-31 12:54:11 -05004170 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004171 struct sk_security_struct *sksec = sk->sk_security;
4172 u32 peer_sid;
4173 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004174 struct avc_audit_data ad;
4175 char *addrp;
4176
4177 AVC_AUDIT_DATA_INIT(&ad, NET);
4178 ad.u.net.netif = skb->iif;
4179 ad.u.net.family = family;
4180 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4181 if (err)
4182 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004183
4184 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004185 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004186 family, addrp);
Paul Moore277d3422008-12-31 12:54:11 -05004187 else if (selinux_secmark_enabled())
Paul Moore220deb92008-01-29 08:38:23 -05004188 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004189 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004190 if (err)
4191 return err;
4192
4193 if (selinux_policycap_netpeer) {
4194 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004196 return err;
4197 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004198 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004199 if (err)
4200 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004201 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004202 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004203 if (err)
4204 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004205 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004207
James Morris4e5ab4c2006-06-09 00:33:33 -07004208 return err;
4209}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004210
James Morris4e5ab4c2006-06-09 00:33:33 -07004211static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4212{
Paul Moore220deb92008-01-29 08:38:23 -05004213 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004214 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004215 u16 family = sk->sk_family;
4216 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004217 struct avc_audit_data ad;
4218 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004219 u8 secmark_active;
4220 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004221
James Morris4e5ab4c2006-06-09 00:33:33 -07004222 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004223 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004224
4225 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004226 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004227 family = PF_INET;
4228
Paul Moored8395c82008-10-10 10:16:30 -04004229 /* If any sort of compatibility mode is enabled then handoff processing
4230 * to the selinux_sock_rcv_skb_compat() function to deal with the
4231 * special handling. We do this in an attempt to keep this function
4232 * as fast and as clean as possible. */
4233 if (selinux_compat_net || !selinux_policycap_netpeer)
4234 return selinux_sock_rcv_skb_compat(sk, skb, family);
4235
4236 secmark_active = selinux_secmark_enabled();
4237 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4238 if (!secmark_active && !peerlbl_active)
4239 return 0;
4240
James Morris4e5ab4c2006-06-09 00:33:33 -07004241 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a22008-01-29 08:38:10 -05004242 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004243 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004244 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004245 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004246 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004247
Paul Moored8395c82008-10-10 10:16:30 -04004248 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004249 u32 peer_sid;
4250
4251 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4252 if (err)
4253 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004254 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4255 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004256 if (err) {
4257 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004258 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004259 }
Paul Moored621d352008-01-29 08:43:36 -05004260 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4261 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004262 if (err)
4263 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004264 }
4265
Paul Moored8395c82008-10-10 10:16:30 -04004266 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004267 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4268 PACKET__RECV, &ad);
4269 if (err)
4270 return err;
4271 }
4272
Paul Moored621d352008-01-29 08:43:36 -05004273 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274}
4275
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004276static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4277 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278{
4279 int err = 0;
4280 char *scontext;
4281 u32 scontext_len;
4282 struct sk_security_struct *ssec;
4283 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004284 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285
4286 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004287
Paul Moore3de4bab2006-11-17 17:38:54 -05004288 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4289 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004290 ssec = sock->sk->sk_security;
4291 peer_sid = ssec->peer_sid;
4292 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004293 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 err = -ENOPROTOOPT;
4295 goto out;
4296 }
4297
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004298 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4299
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 if (err)
4301 goto out;
4302
4303 if (scontext_len > len) {
4304 err = -ERANGE;
4305 goto out_len;
4306 }
4307
4308 if (copy_to_user(optval, scontext, scontext_len))
4309 err = -EFAULT;
4310
4311out_len:
4312 if (put_user(scontext_len, optlen))
4313 err = -EFAULT;
4314
4315 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004316out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 return err;
4318}
4319
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004320static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004321{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004322 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004323 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004324
Paul Mooreaa862902008-10-10 10:16:29 -04004325 if (skb && skb->protocol == htons(ETH_P_IP))
4326 family = PF_INET;
4327 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4328 family = PF_INET6;
4329 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004330 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004331 else
4332 goto out;
4333
4334 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02004335 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004336 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004337 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004338
Paul Moore75e22912008-01-29 08:38:04 -05004339out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004340 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004341 if (peer_secid == SECSID_NULL)
4342 return -EINVAL;
4343 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004344}
4345
Al Viro7d877f32005-10-21 03:20:43 -04004346static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347{
4348 return sk_alloc_security(sk, family, priority);
4349}
4350
4351static void selinux_sk_free_security(struct sock *sk)
4352{
4353 sk_free_security(sk);
4354}
4355
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004356static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4357{
4358 struct sk_security_struct *ssec = sk->sk_security;
4359 struct sk_security_struct *newssec = newsk->sk_security;
4360
4361 newssec->sid = ssec->sid;
4362 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004363 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004364
Paul Mooref74af6e2008-02-25 11:40:33 -05004365 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004366}
4367
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004368static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004369{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004370 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004371 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004372 else {
4373 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004374
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004375 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004376 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004377}
4378
Eric Paris828dfe12008-04-17 13:17:49 -04004379static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004380{
4381 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4382 struct sk_security_struct *sksec = sk->sk_security;
4383
David Woodhouse2148ccc2006-09-29 15:50:25 -07004384 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4385 sk->sk_family == PF_UNIX)
4386 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004387 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004388}
4389
Adrian Bunk9a673e52006-08-15 00:03:53 -07004390static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4391 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004392{
4393 struct sk_security_struct *sksec = sk->sk_security;
4394 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004395 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004396 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004397 u32 peersid;
4398
Paul Mooreaa862902008-10-10 10:16:29 -04004399 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4400 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4401 family = PF_INET;
4402
4403 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004404 if (err)
4405 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004406 if (peersid == SECSID_NULL) {
4407 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004408 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004409 return 0;
4410 }
4411
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004412 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4413 if (err)
4414 return err;
4415
4416 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004417 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004418 return 0;
4419}
4420
Adrian Bunk9a673e52006-08-15 00:03:53 -07004421static void selinux_inet_csk_clone(struct sock *newsk,
4422 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004423{
4424 struct sk_security_struct *newsksec = newsk->sk_security;
4425
4426 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004427 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004428 /* NOTE: Ideally, we should also get the isec->sid for the
4429 new socket in sync, but we don't have the isec available yet.
4430 So we will wait until sock_graft to do it, by which
4431 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004432
Paul Moore9f2ad662006-11-17 17:38:53 -05004433 /* We don't need to take any sort of lock here as we are the only
4434 * thread with access to newsksec */
4435 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004436}
4437
Paul Moore014ab192008-10-10 10:16:33 -04004438static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004439{
Paul Mooreaa862902008-10-10 10:16:29 -04004440 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004441 struct sk_security_struct *sksec = sk->sk_security;
4442
Paul Mooreaa862902008-10-10 10:16:29 -04004443 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4444 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4445 family = PF_INET;
4446
4447 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004448
4449 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004450}
4451
Adrian Bunk9a673e52006-08-15 00:03:53 -07004452static void selinux_req_classify_flow(const struct request_sock *req,
4453 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004454{
4455 fl->secid = req->secid;
4456}
4457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4459{
4460 int err = 0;
4461 u32 perm;
4462 struct nlmsghdr *nlh;
4463 struct socket *sock = sk->sk_socket;
4464 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004465
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 if (skb->len < NLMSG_SPACE(0)) {
4467 err = -EINVAL;
4468 goto out;
4469 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004470 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004471
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4473 if (err) {
4474 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004475 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 "SELinux: unrecognized netlink message"
4477 " type=%hu for sclass=%hu\n",
4478 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004479 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 err = 0;
4481 }
4482
4483 /* Ignore */
4484 if (err == -ENOENT)
4485 err = 0;
4486 goto out;
4487 }
4488
4489 err = socket_has_perm(current, sock, perm);
4490out:
4491 return err;
4492}
4493
4494#ifdef CONFIG_NETFILTER
4495
Paul Mooreeffad8d2008-01-29 08:49:27 -05004496static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4497 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498{
Paul Mooredfaebe92008-10-10 10:16:31 -04004499 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004500 char *addrp;
4501 u32 peer_sid;
4502 struct avc_audit_data ad;
4503 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004504 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004505 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004506
Paul Mooreeffad8d2008-01-29 08:49:27 -05004507 if (!selinux_policycap_netpeer)
4508 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004509
Paul Mooreeffad8d2008-01-29 08:49:27 -05004510 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004511 netlbl_active = netlbl_enabled();
4512 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004513 if (!secmark_active && !peerlbl_active)
4514 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004515
Paul Moored8395c82008-10-10 10:16:30 -04004516 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4517 return NF_DROP;
4518
Paul Mooreeffad8d2008-01-29 08:49:27 -05004519 AVC_AUDIT_DATA_INIT(&ad, NET);
4520 ad.u.net.netif = ifindex;
4521 ad.u.net.family = family;
4522 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4523 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
Paul Mooredfaebe92008-10-10 10:16:31 -04004525 if (peerlbl_active) {
4526 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4527 peer_sid, &ad);
4528 if (err) {
4529 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004530 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004531 }
4532 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004533
4534 if (secmark_active)
4535 if (avc_has_perm(peer_sid, skb->secmark,
4536 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4537 return NF_DROP;
4538
Paul Moore948bf852008-10-10 10:16:32 -04004539 if (netlbl_active)
4540 /* we do this in the FORWARD path and not the POST_ROUTING
4541 * path because we want to make sure we apply the necessary
4542 * labeling before IPsec is applied so we can leverage AH
4543 * protection */
4544 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4545 return NF_DROP;
4546
Paul Mooreeffad8d2008-01-29 08:49:27 -05004547 return NF_ACCEPT;
4548}
4549
4550static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4551 struct sk_buff *skb,
4552 const struct net_device *in,
4553 const struct net_device *out,
4554 int (*okfn)(struct sk_buff *))
4555{
4556 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4557}
4558
4559#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4560static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4561 struct sk_buff *skb,
4562 const struct net_device *in,
4563 const struct net_device *out,
4564 int (*okfn)(struct sk_buff *))
4565{
4566 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4567}
4568#endif /* IPV6 */
4569
Paul Moore948bf852008-10-10 10:16:32 -04004570static unsigned int selinux_ip_output(struct sk_buff *skb,
4571 u16 family)
4572{
4573 u32 sid;
4574
4575 if (!netlbl_enabled())
4576 return NF_ACCEPT;
4577
4578 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4579 * because we want to make sure we apply the necessary labeling
4580 * before IPsec is applied so we can leverage AH protection */
4581 if (skb->sk) {
4582 struct sk_security_struct *sksec = skb->sk->sk_security;
4583 sid = sksec->sid;
4584 } else
4585 sid = SECINITSID_KERNEL;
4586 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4587 return NF_DROP;
4588
4589 return NF_ACCEPT;
4590}
4591
4592static unsigned int selinux_ipv4_output(unsigned int hooknum,
4593 struct sk_buff *skb,
4594 const struct net_device *in,
4595 const struct net_device *out,
4596 int (*okfn)(struct sk_buff *))
4597{
4598 return selinux_ip_output(skb, PF_INET);
4599}
4600
Paul Mooreeffad8d2008-01-29 08:49:27 -05004601static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4602 int ifindex,
4603 struct avc_audit_data *ad,
4604 u16 family, char *addrp)
4605{
4606 int err;
4607 struct sk_security_struct *sksec = sk->sk_security;
4608 u16 sk_class;
4609 u32 netif_perm, node_perm, send_perm;
4610 u32 port_sid, node_sid, if_sid, sk_sid;
4611
4612 sk_sid = sksec->sid;
4613 sk_class = sksec->sclass;
4614
4615 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 case SECCLASS_UDP_SOCKET:
4617 netif_perm = NETIF__UDP_SEND;
4618 node_perm = NODE__UDP_SEND;
4619 send_perm = UDP_SOCKET__SEND_MSG;
4620 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 case SECCLASS_TCP_SOCKET:
4622 netif_perm = NETIF__TCP_SEND;
4623 node_perm = NODE__TCP_SEND;
4624 send_perm = TCP_SOCKET__SEND_MSG;
4625 break;
James Morris2ee92d42006-11-13 16:09:01 -08004626 case SECCLASS_DCCP_SOCKET:
4627 netif_perm = NETIF__DCCP_SEND;
4628 node_perm = NODE__DCCP_SEND;
4629 send_perm = DCCP_SOCKET__SEND_MSG;
4630 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 default:
4632 netif_perm = NETIF__RAWIP_SEND;
4633 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004634 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 break;
4636 }
4637
Paul Mooreeffad8d2008-01-29 08:49:27 -05004638 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004639 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004640 return err;
4641 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4642 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004643
Paul Moore224dfbd2008-01-29 08:38:13 -05004644 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004645 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004646 return err;
4647 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004648 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004649 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650
Paul Mooreeffad8d2008-01-29 08:49:27 -05004651 if (send_perm != 0)
4652 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653
Paul Moore3e112172008-04-10 10:48:14 -04004654 err = sel_netport_sid(sk->sk_protocol,
4655 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004656 if (unlikely(err)) {
4657 printk(KERN_WARNING
4658 "SELinux: failure in"
4659 " selinux_ip_postroute_iptables_compat(),"
4660 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004661 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004662 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004663 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004664}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665
Paul Mooreeffad8d2008-01-29 08:49:27 -05004666static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4667 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004668 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004669{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004670 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004671 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004672 struct avc_audit_data ad;
4673 char *addrp;
4674 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004675
Paul Mooreeffad8d2008-01-29 08:49:27 -05004676 if (sk == NULL)
4677 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004678 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004679
Paul Moored8395c82008-10-10 10:16:30 -04004680 AVC_AUDIT_DATA_INIT(&ad, NET);
4681 ad.u.net.netif = ifindex;
4682 ad.u.net.family = family;
4683 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4684 return NF_DROP;
4685
Paul Mooreeffad8d2008-01-29 08:49:27 -05004686 if (selinux_compat_net) {
4687 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004688 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004689 return NF_DROP;
Paul Moore277d3422008-12-31 12:54:11 -05004690 } else if (selinux_secmark_enabled()) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004691 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004692 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004693 return NF_DROP;
4694 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004695
Paul Mooreeffad8d2008-01-29 08:49:27 -05004696 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004697 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004698 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004699
Paul Mooreeffad8d2008-01-29 08:49:27 -05004700 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701}
4702
Paul Mooreeffad8d2008-01-29 08:49:27 -05004703static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4704 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706 u32 secmark_perm;
4707 u32 peer_sid;
4708 struct sock *sk;
4709 struct avc_audit_data ad;
4710 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004711 u8 secmark_active;
4712 u8 peerlbl_active;
4713
Paul Mooreeffad8d2008-01-29 08:49:27 -05004714 /* If any sort of compatibility mode is enabled then handoff processing
4715 * to the selinux_ip_postroute_compat() function to deal with the
4716 * special handling. We do this in an attempt to keep this function
4717 * as fast and as clean as possible. */
4718 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004719 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004720#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004721 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4722 * packet transformation so allow the packet to pass without any checks
4723 * since we'll have another chance to perform access control checks
4724 * when the packet is on it's final way out.
4725 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4726 * is NULL, in this case go ahead and apply access control. */
4727 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4728 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004729#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004730 secmark_active = selinux_secmark_enabled();
4731 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4732 if (!secmark_active && !peerlbl_active)
4733 return NF_ACCEPT;
4734
Paul Moored8395c82008-10-10 10:16:30 -04004735 /* if the packet is being forwarded then get the peer label from the
4736 * packet itself; otherwise check to see if it is from a local
4737 * application or the kernel, if from an application get the peer label
4738 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004739 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004740 if (sk == NULL) {
4741 switch (family) {
4742 case PF_INET:
4743 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4744 secmark_perm = PACKET__FORWARD_OUT;
4745 else
4746 secmark_perm = PACKET__SEND;
4747 break;
4748 case PF_INET6:
4749 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4750 secmark_perm = PACKET__FORWARD_OUT;
4751 else
4752 secmark_perm = PACKET__SEND;
4753 break;
4754 default:
4755 return NF_DROP;
4756 }
4757 if (secmark_perm == PACKET__FORWARD_OUT) {
4758 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4759 return NF_DROP;
4760 } else
4761 peer_sid = SECINITSID_KERNEL;
4762 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004763 struct sk_security_struct *sksec = sk->sk_security;
4764 peer_sid = sksec->sid;
4765 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004766 }
4767
Paul Moored8395c82008-10-10 10:16:30 -04004768 AVC_AUDIT_DATA_INIT(&ad, NET);
4769 ad.u.net.netif = ifindex;
4770 ad.u.net.family = family;
4771 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4772 return NF_DROP;
4773
Paul Mooreeffad8d2008-01-29 08:49:27 -05004774 if (secmark_active)
4775 if (avc_has_perm(peer_sid, skb->secmark,
4776 SECCLASS_PACKET, secmark_perm, &ad))
4777 return NF_DROP;
4778
4779 if (peerlbl_active) {
4780 u32 if_sid;
4781 u32 node_sid;
4782
4783 if (sel_netif_sid(ifindex, &if_sid))
4784 return NF_DROP;
4785 if (avc_has_perm(peer_sid, if_sid,
4786 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4787 return NF_DROP;
4788
4789 if (sel_netnode_sid(addrp, family, &node_sid))
4790 return NF_DROP;
4791 if (avc_has_perm(peer_sid, node_sid,
4792 SECCLASS_NODE, NODE__SENDTO, &ad))
4793 return NF_DROP;
4794 }
4795
4796 return NF_ACCEPT;
4797}
4798
4799static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4800 struct sk_buff *skb,
4801 const struct net_device *in,
4802 const struct net_device *out,
4803 int (*okfn)(struct sk_buff *))
4804{
4805 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806}
4807
4808#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004809static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4810 struct sk_buff *skb,
4811 const struct net_device *in,
4812 const struct net_device *out,
4813 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004815 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817#endif /* IPV6 */
4818
4819#endif /* CONFIG_NETFILTER */
4820
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4822{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 int err;
4824
4825 err = secondary_ops->netlink_send(sk, skb);
4826 if (err)
4827 return err;
4828
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4830 err = selinux_nlmsg_perm(sk, skb);
4831
4832 return err;
4833}
4834
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004835static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004837 int err;
4838 struct avc_audit_data ad;
4839
4840 err = secondary_ops->netlink_recv(skb, capability);
4841 if (err)
4842 return err;
4843
4844 AVC_AUDIT_DATA_INIT(&ad, CAP);
4845 ad.u.cap = capability;
4846
4847 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004848 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849}
4850
4851static int ipc_alloc_security(struct task_struct *task,
4852 struct kern_ipc_perm *perm,
4853 u16 sclass)
4854{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004856 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
James Morris89d155e2005-10-30 14:59:21 -08004858 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 if (!isec)
4860 return -ENOMEM;
4861
David Howells275bb412008-11-14 10:39:19 +11004862 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004864 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 perm->security = isec;
4866
4867 return 0;
4868}
4869
4870static void ipc_free_security(struct kern_ipc_perm *perm)
4871{
4872 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 perm->security = NULL;
4874 kfree(isec);
4875}
4876
4877static int msg_msg_alloc_security(struct msg_msg *msg)
4878{
4879 struct msg_security_struct *msec;
4880
James Morris89d155e2005-10-30 14:59:21 -08004881 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 if (!msec)
4883 return -ENOMEM;
4884
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 msec->sid = SECINITSID_UNLABELED;
4886 msg->security = msec;
4887
4888 return 0;
4889}
4890
4891static void msg_msg_free_security(struct msg_msg *msg)
4892{
4893 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894
4895 msg->security = NULL;
4896 kfree(msec);
4897}
4898
4899static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004900 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 struct ipc_security_struct *isec;
4903 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004904 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 isec = ipc_perms->security;
4907
4908 AVC_AUDIT_DATA_INIT(&ad, IPC);
4909 ad.u.ipc_id = ipc_perms->key;
4910
David Howells275bb412008-11-14 10:39:19 +11004911 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912}
4913
4914static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4915{
4916 return msg_msg_alloc_security(msg);
4917}
4918
4919static void selinux_msg_msg_free_security(struct msg_msg *msg)
4920{
4921 msg_msg_free_security(msg);
4922}
4923
4924/* message queue security operations */
4925static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
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 int rc;
4931
4932 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4933 if (rc)
4934 return rc;
4935
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 isec = msq->q_perm.security;
4937
4938 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004939 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940
David Howells275bb412008-11-14 10:39:19 +11004941 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 MSGQ__CREATE, &ad);
4943 if (rc) {
4944 ipc_free_security(&msq->q_perm);
4945 return rc;
4946 }
4947 return 0;
4948}
4949
4950static void selinux_msg_queue_free_security(struct msg_queue *msq)
4951{
4952 ipc_free_security(&msq->q_perm);
4953}
4954
4955static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4956{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 struct ipc_security_struct *isec;
4958 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004959 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 isec = msq->q_perm.security;
4962
4963 AVC_AUDIT_DATA_INIT(&ad, IPC);
4964 ad.u.ipc_id = msq->q_perm.key;
4965
David Howells275bb412008-11-14 10:39:19 +11004966 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 MSGQ__ASSOCIATE, &ad);
4968}
4969
4970static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4971{
4972 int err;
4973 int perms;
4974
Eric Paris828dfe12008-04-17 13:17:49 -04004975 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 case IPC_INFO:
4977 case MSG_INFO:
4978 /* No specific object, just general system-wide information. */
4979 return task_has_system(current, SYSTEM__IPC_INFO);
4980 case IPC_STAT:
4981 case MSG_STAT:
4982 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4983 break;
4984 case IPC_SET:
4985 perms = MSGQ__SETATTR;
4986 break;
4987 case IPC_RMID:
4988 perms = MSGQ__DESTROY;
4989 break;
4990 default:
4991 return 0;
4992 }
4993
Stephen Smalley6af963f2005-05-01 08:58:39 -07004994 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 return err;
4996}
4997
4998static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4999{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 struct ipc_security_struct *isec;
5001 struct msg_security_struct *msec;
5002 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005003 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 int rc;
5005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 isec = msq->q_perm.security;
5007 msec = msg->security;
5008
5009 /*
5010 * First time through, need to assign label to the message
5011 */
5012 if (msec->sid == SECINITSID_UNLABELED) {
5013 /*
5014 * Compute new sid based on current process and
5015 * message queue this message will be stored in
5016 */
David Howells275bb412008-11-14 10:39:19 +11005017 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 &msec->sid);
5019 if (rc)
5020 return rc;
5021 }
5022
5023 AVC_AUDIT_DATA_INIT(&ad, IPC);
5024 ad.u.ipc_id = msq->q_perm.key;
5025
5026 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005027 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 MSGQ__WRITE, &ad);
5029 if (!rc)
5030 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005031 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5032 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 if (!rc)
5034 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005035 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5036 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
5038 return rc;
5039}
5040
5041static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5042 struct task_struct *target,
5043 long type, int mode)
5044{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 struct ipc_security_struct *isec;
5046 struct msg_security_struct *msec;
5047 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005048 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 int rc;
5050
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 isec = msq->q_perm.security;
5052 msec = msg->security;
5053
5054 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005055 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
David Howells275bb412008-11-14 10:39:19 +11005057 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 SECCLASS_MSGQ, MSGQ__READ, &ad);
5059 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005060 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 SECCLASS_MSG, MSG__RECEIVE, &ad);
5062 return rc;
5063}
5064
5065/* Shared Memory security operations */
5066static int selinux_shm_alloc_security(struct shmid_kernel *shp)
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 int rc;
5072
5073 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5074 if (rc)
5075 return rc;
5076
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 isec = shp->shm_perm.security;
5078
5079 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005080 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081
David Howells275bb412008-11-14 10:39:19 +11005082 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 SHM__CREATE, &ad);
5084 if (rc) {
5085 ipc_free_security(&shp->shm_perm);
5086 return rc;
5087 }
5088 return 0;
5089}
5090
5091static void selinux_shm_free_security(struct shmid_kernel *shp)
5092{
5093 ipc_free_security(&shp->shm_perm);
5094}
5095
5096static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5097{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 struct ipc_security_struct *isec;
5099 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005100 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 isec = shp->shm_perm.security;
5103
5104 AVC_AUDIT_DATA_INIT(&ad, IPC);
5105 ad.u.ipc_id = shp->shm_perm.key;
5106
David Howells275bb412008-11-14 10:39:19 +11005107 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 SHM__ASSOCIATE, &ad);
5109}
5110
5111/* Note, at this point, shp is locked down */
5112static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5113{
5114 int perms;
5115 int err;
5116
Eric Paris828dfe12008-04-17 13:17:49 -04005117 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 case IPC_INFO:
5119 case SHM_INFO:
5120 /* No specific object, just general system-wide information. */
5121 return task_has_system(current, SYSTEM__IPC_INFO);
5122 case IPC_STAT:
5123 case SHM_STAT:
5124 perms = SHM__GETATTR | SHM__ASSOCIATE;
5125 break;
5126 case IPC_SET:
5127 perms = SHM__SETATTR;
5128 break;
5129 case SHM_LOCK:
5130 case SHM_UNLOCK:
5131 perms = SHM__LOCK;
5132 break;
5133 case IPC_RMID:
5134 perms = SHM__DESTROY;
5135 break;
5136 default:
5137 return 0;
5138 }
5139
Stephen Smalley6af963f2005-05-01 08:58:39 -07005140 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 return err;
5142}
5143
5144static int selinux_shm_shmat(struct shmid_kernel *shp,
5145 char __user *shmaddr, int shmflg)
5146{
5147 u32 perms;
5148 int rc;
5149
5150 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5151 if (rc)
5152 return rc;
5153
5154 if (shmflg & SHM_RDONLY)
5155 perms = SHM__READ;
5156 else
5157 perms = SHM__READ | SHM__WRITE;
5158
Stephen Smalley6af963f2005-05-01 08:58:39 -07005159 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160}
5161
5162/* Semaphore security operations */
5163static int selinux_sem_alloc_security(struct sem_array *sma)
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 int rc;
5169
5170 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5171 if (rc)
5172 return rc;
5173
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 isec = sma->sem_perm.security;
5175
5176 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005177 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178
David Howells275bb412008-11-14 10:39:19 +11005179 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 SEM__CREATE, &ad);
5181 if (rc) {
5182 ipc_free_security(&sma->sem_perm);
5183 return rc;
5184 }
5185 return 0;
5186}
5187
5188static void selinux_sem_free_security(struct sem_array *sma)
5189{
5190 ipc_free_security(&sma->sem_perm);
5191}
5192
5193static int selinux_sem_associate(struct sem_array *sma, int semflg)
5194{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 struct ipc_security_struct *isec;
5196 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005197 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 isec = sma->sem_perm.security;
5200
5201 AVC_AUDIT_DATA_INIT(&ad, IPC);
5202 ad.u.ipc_id = sma->sem_perm.key;
5203
David Howells275bb412008-11-14 10:39:19 +11005204 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 SEM__ASSOCIATE, &ad);
5206}
5207
5208/* Note, at this point, sma is locked down */
5209static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5210{
5211 int err;
5212 u32 perms;
5213
Eric Paris828dfe12008-04-17 13:17:49 -04005214 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 case IPC_INFO:
5216 case SEM_INFO:
5217 /* No specific object, just general system-wide information. */
5218 return task_has_system(current, SYSTEM__IPC_INFO);
5219 case GETPID:
5220 case GETNCNT:
5221 case GETZCNT:
5222 perms = SEM__GETATTR;
5223 break;
5224 case GETVAL:
5225 case GETALL:
5226 perms = SEM__READ;
5227 break;
5228 case SETVAL:
5229 case SETALL:
5230 perms = SEM__WRITE;
5231 break;
5232 case IPC_RMID:
5233 perms = SEM__DESTROY;
5234 break;
5235 case IPC_SET:
5236 perms = SEM__SETATTR;
5237 break;
5238 case IPC_STAT:
5239 case SEM_STAT:
5240 perms = SEM__GETATTR | SEM__ASSOCIATE;
5241 break;
5242 default:
5243 return 0;
5244 }
5245
Stephen Smalley6af963f2005-05-01 08:58:39 -07005246 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 return err;
5248}
5249
5250static int selinux_sem_semop(struct sem_array *sma,
5251 struct sembuf *sops, unsigned nsops, int alter)
5252{
5253 u32 perms;
5254
5255 if (alter)
5256 perms = SEM__READ | SEM__WRITE;
5257 else
5258 perms = SEM__READ;
5259
Stephen Smalley6af963f2005-05-01 08:58:39 -07005260 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261}
5262
5263static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5264{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 u32 av = 0;
5266
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 av = 0;
5268 if (flag & S_IRUGO)
5269 av |= IPC__UNIX_READ;
5270 if (flag & S_IWUGO)
5271 av |= IPC__UNIX_WRITE;
5272
5273 if (av == 0)
5274 return 0;
5275
Stephen Smalley6af963f2005-05-01 08:58:39 -07005276 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277}
5278
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02005279static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5280{
5281 struct ipc_security_struct *isec = ipcp->security;
5282 *secid = isec->sid;
5283}
5284
Eric Paris828dfe12008-04-17 13:17:49 -04005285static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286{
5287 if (inode)
5288 inode_doinit_with_dentry(inode, dentry);
5289}
5290
5291static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005292 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293{
David Howells275bb412008-11-14 10:39:19 +11005294 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005295 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005297 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298
5299 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005300 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 if (error)
5302 return error;
5303 }
5304
David Howells275bb412008-11-14 10:39:19 +11005305 rcu_read_lock();
5306 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307
5308 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005309 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005311 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005313 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005315 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005316 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005317 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005318 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005319 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 else
David Howells275bb412008-11-14 10:39:19 +11005321 goto invalid;
5322 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323
5324 if (!sid)
5325 return 0;
5326
Al Viro04ff9702007-03-12 16:17:58 +00005327 error = security_sid_to_context(sid, value, &len);
5328 if (error)
5329 return error;
5330 return len;
David Howells275bb412008-11-14 10:39:19 +11005331
5332invalid:
5333 rcu_read_unlock();
5334 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335}
5336
5337static int selinux_setprocattr(struct task_struct *p,
5338 char *name, void *value, size_t size)
5339{
5340 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005341 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005342 struct cred *new;
5343 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 int error;
5345 char *str = value;
5346
5347 if (current != p) {
5348 /* SELinux only allows a process to change its own
5349 security attributes. */
5350 return -EACCES;
5351 }
5352
5353 /*
5354 * Basic control over ability to set these attributes at all.
5355 * current == p, but we'll pass them separately in case the
5356 * above restriction is ever removed.
5357 */
5358 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005359 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005361 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005362 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005363 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005364 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005365 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005367 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 else
5369 error = -EINVAL;
5370 if (error)
5371 return error;
5372
5373 /* Obtain a SID for the context, if one was specified. */
5374 if (size && str[1] && str[1] != '\n') {
5375 if (str[size-1] == '\n') {
5376 str[size-1] = 0;
5377 size--;
5378 }
5379 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005380 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5381 if (!capable(CAP_MAC_ADMIN))
5382 return error;
5383 error = security_context_to_sid_force(value, size,
5384 &sid);
5385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 if (error)
5387 return error;
5388 }
5389
David Howellsd84f4f92008-11-14 10:39:23 +11005390 new = prepare_creds();
5391 if (!new)
5392 return -ENOMEM;
5393
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 /* Permission checking based on the specified context is
5395 performed during the actual operation (execve,
5396 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005397 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 checks and may_create for the file creation checks. The
5399 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005400 tsec = new->security;
5401 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005403 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005405 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005406 error = may_create_key(sid, p);
5407 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005408 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005409 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005410 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005411 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005412 } else if (!strcmp(name, "current")) {
5413 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005415 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005416
David Howellsd84f4f92008-11-14 10:39:23 +11005417 /* Only allow single threaded processes to change context */
5418 error = -EPERM;
5419 if (!is_single_threaded(p)) {
5420 error = security_bounded_transition(tsec->sid, sid);
5421 if (error)
5422 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
5425 /* Check permissions for the transition. */
5426 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005427 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005429 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430
5431 /* Check for ptracing, and update the task SID if ok.
5432 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005433 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005435 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005436 if (tracer)
5437 ptsid = task_sid(tracer);
5438 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439
David Howellsd84f4f92008-11-14 10:39:23 +11005440 if (tracer) {
5441 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5442 PROCESS__PTRACE, NULL);
5443 if (error)
5444 goto abort_change;
5445 }
5446
5447 tsec->sid = sid;
5448 } else {
5449 error = -EINVAL;
5450 goto abort_change;
5451 }
5452
5453 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005455
5456abort_change:
5457 abort_creds(new);
5458 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459}
5460
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005461static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5462{
5463 return security_sid_to_context(secid, secdata, seclen);
5464}
5465
David Howells7bf570d2008-04-29 20:52:51 +01005466static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005467{
5468 return security_context_to_sid(secdata, seclen, secid);
5469}
5470
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005471static void selinux_release_secctx(char *secdata, u32 seclen)
5472{
Paul Moore088999e2007-08-01 11:12:58 -04005473 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005474}
5475
Michael LeMayd7200242006-06-22 14:47:17 -07005476#ifdef CONFIG_KEYS
5477
David Howellsd84f4f92008-11-14 10:39:23 +11005478static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005479 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005480{
David Howellsd84f4f92008-11-14 10:39:23 +11005481 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005482 struct key_security_struct *ksec;
5483
5484 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5485 if (!ksec)
5486 return -ENOMEM;
5487
David Howellsd84f4f92008-11-14 10:39:23 +11005488 tsec = cred->security;
5489 if (tsec->keycreate_sid)
5490 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005491 else
David Howellsd84f4f92008-11-14 10:39:23 +11005492 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005493
David Howells275bb412008-11-14 10:39:19 +11005494 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005495 return 0;
5496}
5497
5498static void selinux_key_free(struct key *k)
5499{
5500 struct key_security_struct *ksec = k->security;
5501
5502 k->security = NULL;
5503 kfree(ksec);
5504}
5505
5506static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005507 const struct cred *cred,
5508 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005509{
5510 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005511 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005512 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005513
5514 /* if no specific permissions are requested, we skip the
5515 permission check. No serious, additional covert channels
5516 appear to be created. */
5517 if (perm == 0)
5518 return 0;
5519
David Howellsd84f4f92008-11-14 10:39:23 +11005520 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005521
5522 key = key_ref_to_ptr(key_ref);
5523 ksec = key->security;
5524
5525 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005526}
5527
David Howells70a5bb72008-04-29 01:01:26 -07005528static int selinux_key_getsecurity(struct key *key, char **_buffer)
5529{
5530 struct key_security_struct *ksec = key->security;
5531 char *context = NULL;
5532 unsigned len;
5533 int rc;
5534
5535 rc = security_sid_to_context(ksec->sid, &context, &len);
5536 if (!rc)
5537 rc = len;
5538 *_buffer = context;
5539 return rc;
5540}
5541
Michael LeMayd7200242006-06-22 14:47:17 -07005542#endif
5543
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005545 .name = "selinux",
5546
David Howells5cd9c582008-08-14 11:37:28 +01005547 .ptrace_may_access = selinux_ptrace_may_access,
5548 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005550 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 .sysctl = selinux_sysctl,
5552 .capable = selinux_capable,
5553 .quotactl = selinux_quotactl,
5554 .quota_on = selinux_quota_on,
5555 .syslog = selinux_syslog,
5556 .vm_enough_memory = selinux_vm_enough_memory,
5557
5558 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005559 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560
David Howellsa6f76f22008-11-14 10:39:24 +11005561 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005562 .bprm_committing_creds = selinux_bprm_committing_creds,
5563 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 .bprm_secureexec = selinux_bprm_secureexec,
5565
5566 .sb_alloc_security = selinux_sb_alloc_security,
5567 .sb_free_security = selinux_sb_free_security,
5568 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005569 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005570 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 .sb_statfs = selinux_sb_statfs,
5572 .sb_mount = selinux_mount,
5573 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005574 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005575 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005576 .sb_parse_opts_str = selinux_parse_opts_str,
5577
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
5579 .inode_alloc_security = selinux_inode_alloc_security,
5580 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005581 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 .inode_unlink = selinux_inode_unlink,
5585 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 .inode_rmdir = selinux_inode_rmdir,
5588 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 .inode_readlink = selinux_inode_readlink,
5591 .inode_follow_link = selinux_inode_follow_link,
5592 .inode_permission = selinux_inode_permission,
5593 .inode_setattr = selinux_inode_setattr,
5594 .inode_getattr = selinux_inode_getattr,
5595 .inode_setxattr = selinux_inode_setxattr,
5596 .inode_post_setxattr = selinux_inode_post_setxattr,
5597 .inode_getxattr = selinux_inode_getxattr,
5598 .inode_listxattr = selinux_inode_listxattr,
5599 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005600 .inode_getsecurity = selinux_inode_getsecurity,
5601 .inode_setsecurity = selinux_inode_setsecurity,
5602 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005603 .inode_need_killpriv = selinux_inode_need_killpriv,
5604 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005605 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606
5607 .file_permission = selinux_file_permission,
5608 .file_alloc_security = selinux_file_alloc_security,
5609 .file_free_security = selinux_file_free_security,
5610 .file_ioctl = selinux_file_ioctl,
5611 .file_mmap = selinux_file_mmap,
5612 .file_mprotect = selinux_file_mprotect,
5613 .file_lock = selinux_file_lock,
5614 .file_fcntl = selinux_file_fcntl,
5615 .file_set_fowner = selinux_file_set_fowner,
5616 .file_send_sigiotask = selinux_file_send_sigiotask,
5617 .file_receive = selinux_file_receive,
5618
Eric Paris828dfe12008-04-17 13:17:49 -04005619 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005620
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005622 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005623 .cred_prepare = selinux_cred_prepare,
5624 .cred_commit = selinux_cred_commit,
David Howells3a3b7ce2008-11-14 10:39:28 +11005625 .kernel_act_as = selinux_kernel_act_as,
5626 .kernel_create_files_as = selinux_kernel_create_files_as,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005628 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 .task_setgid = selinux_task_setgid,
5630 .task_setpgid = selinux_task_setpgid,
5631 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005632 .task_getsid = selinux_task_getsid,
David Quigleyf9008e4c2006-06-30 01:55:46 -07005633 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 .task_setgroups = selinux_task_setgroups,
5635 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005636 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005637 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 .task_setrlimit = selinux_task_setrlimit,
5639 .task_setscheduler = selinux_task_setscheduler,
5640 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005641 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 .task_kill = selinux_task_kill,
5643 .task_wait = selinux_task_wait,
5644 .task_prctl = selinux_task_prctl,
Eric Paris828dfe12008-04-17 13:17:49 -04005645 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646
5647 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005648 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649
5650 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5651 .msg_msg_free_security = selinux_msg_msg_free_security,
5652
5653 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5654 .msg_queue_free_security = selinux_msg_queue_free_security,
5655 .msg_queue_associate = selinux_msg_queue_associate,
5656 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5657 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5658 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5659
5660 .shm_alloc_security = selinux_shm_alloc_security,
5661 .shm_free_security = selinux_shm_free_security,
5662 .shm_associate = selinux_shm_associate,
5663 .shm_shmctl = selinux_shm_shmctl,
5664 .shm_shmat = selinux_shm_shmat,
5665
Eric Paris828dfe12008-04-17 13:17:49 -04005666 .sem_alloc_security = selinux_sem_alloc_security,
5667 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 .sem_associate = selinux_sem_associate,
5669 .sem_semctl = selinux_sem_semctl,
5670 .sem_semop = selinux_sem_semop,
5671
Eric Paris828dfe12008-04-17 13:17:49 -04005672 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673
Eric Paris828dfe12008-04-17 13:17:49 -04005674 .getprocattr = selinux_getprocattr,
5675 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005677 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005678 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005679 .release_secctx = selinux_release_secctx,
5680
Eric Paris828dfe12008-04-17 13:17:49 -04005681 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 .unix_may_send = selinux_socket_unix_may_send,
5683
5684 .socket_create = selinux_socket_create,
5685 .socket_post_create = selinux_socket_post_create,
5686 .socket_bind = selinux_socket_bind,
5687 .socket_connect = selinux_socket_connect,
5688 .socket_listen = selinux_socket_listen,
5689 .socket_accept = selinux_socket_accept,
5690 .socket_sendmsg = selinux_socket_sendmsg,
5691 .socket_recvmsg = selinux_socket_recvmsg,
5692 .socket_getsockname = selinux_socket_getsockname,
5693 .socket_getpeername = selinux_socket_getpeername,
5694 .socket_getsockopt = selinux_socket_getsockopt,
5695 .socket_setsockopt = selinux_socket_setsockopt,
5696 .socket_shutdown = selinux_socket_shutdown,
5697 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005698 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5699 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 .sk_alloc_security = selinux_sk_alloc_security,
5701 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005702 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005703 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005704 .sock_graft = selinux_sock_graft,
5705 .inet_conn_request = selinux_inet_conn_request,
5706 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005707 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005708 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005709
5710#ifdef CONFIG_SECURITY_NETWORK_XFRM
5711 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5712 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5713 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005714 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005715 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5716 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005717 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005718 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005719 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005720 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005722
5723#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005724 .key_alloc = selinux_key_alloc,
5725 .key_free = selinux_key_free,
5726 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005727 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005728#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005729
5730#ifdef CONFIG_AUDIT
5731 .audit_rule_init = selinux_audit_rule_init,
5732 .audit_rule_known = selinux_audit_rule_known,
5733 .audit_rule_match = selinux_audit_rule_match,
5734 .audit_rule_free = selinux_audit_rule_free,
5735#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736};
5737
5738static __init int selinux_init(void)
5739{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005740 if (!security_module_enable(&selinux_ops)) {
5741 selinux_enabled = 0;
5742 return 0;
5743 }
5744
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 if (!selinux_enabled) {
5746 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5747 return 0;
5748 }
5749
5750 printk(KERN_INFO "SELinux: Initializing.\n");
5751
5752 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005753 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754
James Morris7cae7e22006-03-22 00:09:22 -08005755 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5756 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005757 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 avc_init();
5759
James Morris6f0f0fd2008-07-10 17:02:07 +09005760 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005762 panic("SELinux: No initial security operations\n");
5763 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 panic("SELinux: Unable to register with kernel.\n");
5765
Eric Paris828dfe12008-04-17 13:17:49 -04005766 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005767 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005768 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005769 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005770
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 return 0;
5772}
5773
5774void selinux_complete_init(void)
5775{
Eric Parisfadcdb42007-02-22 18:11:31 -05005776 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777
5778 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005779 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005780 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 spin_lock(&sb_security_lock);
5782next_sb:
5783 if (!list_empty(&superblock_security_head)) {
5784 struct superblock_security_struct *sbsec =
5785 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005786 struct superblock_security_struct,
5787 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005791 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 down_read(&sb->s_umount);
5793 if (sb->s_root)
5794 superblock_doinit(sb, NULL);
5795 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005796 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 spin_lock(&sb_security_lock);
5798 list_del_init(&sbsec->list);
5799 goto next_sb;
5800 }
5801 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005802 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803}
5804
5805/* SELinux requires early initialization in order to label
5806 all processes and objects when they are created. */
5807security_initcall(selinux_init);
5808
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005809#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810
Paul Mooreeffad8d2008-01-29 08:49:27 -05005811static struct nf_hook_ops selinux_ipv4_ops[] = {
5812 {
5813 .hook = selinux_ipv4_postroute,
5814 .owner = THIS_MODULE,
5815 .pf = PF_INET,
5816 .hooknum = NF_INET_POST_ROUTING,
5817 .priority = NF_IP_PRI_SELINUX_LAST,
5818 },
5819 {
5820 .hook = selinux_ipv4_forward,
5821 .owner = THIS_MODULE,
5822 .pf = PF_INET,
5823 .hooknum = NF_INET_FORWARD,
5824 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005825 },
5826 {
5827 .hook = selinux_ipv4_output,
5828 .owner = THIS_MODULE,
5829 .pf = PF_INET,
5830 .hooknum = NF_INET_LOCAL_OUT,
5831 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833};
5834
5835#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5836
Paul Mooreeffad8d2008-01-29 08:49:27 -05005837static struct nf_hook_ops selinux_ipv6_ops[] = {
5838 {
5839 .hook = selinux_ipv6_postroute,
5840 .owner = THIS_MODULE,
5841 .pf = PF_INET6,
5842 .hooknum = NF_INET_POST_ROUTING,
5843 .priority = NF_IP6_PRI_SELINUX_LAST,
5844 },
5845 {
5846 .hook = selinux_ipv6_forward,
5847 .owner = THIS_MODULE,
5848 .pf = PF_INET6,
5849 .hooknum = NF_INET_FORWARD,
5850 .priority = NF_IP6_PRI_SELINUX_FIRST,
5851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852};
5853
5854#endif /* IPV6 */
5855
5856static int __init selinux_nf_ip_init(void)
5857{
5858 int err = 0;
5859
5860 if (!selinux_enabled)
5861 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005862
5863 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5864
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005865 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5866 if (err)
5867 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868
5869#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005870 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5871 if (err)
5872 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005874
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875out:
5876 return err;
5877}
5878
5879__initcall(selinux_nf_ip_init);
5880
5881#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5882static void selinux_nf_ip_exit(void)
5883{
Eric Parisfadcdb42007-02-22 18:11:31 -05005884 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005886 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005888 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889#endif /* IPV6 */
5890}
5891#endif
5892
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005893#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894
5895#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5896#define selinux_nf_ip_exit()
5897#endif
5898
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005899#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
5901#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005902static int selinux_disabled;
5903
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904int selinux_disable(void)
5905{
5906 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907
5908 if (ss_initialized) {
5909 /* Not permitted after initial policy load. */
5910 return -EINVAL;
5911 }
5912
5913 if (selinux_disabled) {
5914 /* Only do this once. */
5915 return -EINVAL;
5916 }
5917
5918 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5919
5920 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005921 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
5923 /* Reset security_ops to the secondary module, dummy or capability. */
5924 security_ops = secondary_ops;
5925
5926 /* Unregister netfilter hooks. */
5927 selinux_nf_ip_exit();
5928
5929 /* Unregister selinuxfs. */
5930 exit_sel_fs();
5931
5932 return 0;
5933}
5934#endif