blob: 2c98071fba8bba6f559a3e5a0477d85f3eb2594b [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 Sharma3bd858a2007-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. Darwish713a04a2008-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
3060 if (selinux_checkreqprot)
3061 prot = reqprot;
3062
3063#ifndef CONFIG_PPC32
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003064 if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003065 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003066 if (vma->vm_start >= vma->vm_mm->start_brk &&
3067 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003068 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003069 } else if (!vma->vm_file &&
3070 vma->vm_start <= vma->vm_mm->start_stack &&
3071 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003072 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003073 } else if (vma->vm_file && vma->anon_vma) {
3074 /*
3075 * We are making executable a file mapping that has
3076 * had some COW done. Since pages might have been
3077 * written, check ability to execute the possibly
3078 * modified content. This typically should only
3079 * occur for text relocations.
3080 */
David Howellsd84f4f92008-11-14 10:39:23 +11003081 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003082 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003083 if (rc)
3084 return rc;
3085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086#endif
3087
3088 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3089}
3090
3091static int selinux_file_lock(struct file *file, unsigned int cmd)
3092{
David Howells88e67f32008-11-14 10:39:21 +11003093 const struct cred *cred = current_cred();
3094
3095 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096}
3097
3098static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3099 unsigned long arg)
3100{
David Howells88e67f32008-11-14 10:39:21 +11003101 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 int err = 0;
3103
3104 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003105 case F_SETFL:
3106 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3107 err = -EINVAL;
3108 break;
3109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110
Eric Paris828dfe12008-04-17 13:17:49 -04003111 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003112 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003114 }
3115 /* fall through */
3116 case F_SETOWN:
3117 case F_SETSIG:
3118 case F_GETFL:
3119 case F_GETOWN:
3120 case F_GETSIG:
3121 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003122 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003123 break;
3124 case F_GETLK:
3125 case F_SETLK:
3126 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003128 case F_GETLK64:
3129 case F_SETLK64:
3130 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003132 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3133 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003135 }
David Howells88e67f32008-11-14 10:39:21 +11003136 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003137 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 }
3139
3140 return err;
3141}
3142
3143static int selinux_file_set_fowner(struct file *file)
3144{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 struct file_security_struct *fsec;
3146
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003148 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
3150 return 0;
3151}
3152
3153static int selinux_file_send_sigiotask(struct task_struct *tsk,
3154 struct fown_struct *fown, int signum)
3155{
Eric Paris828dfe12008-04-17 13:17:49 -04003156 struct file *file;
David Howells275bb412008-11-14 10:39:19 +11003157 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 struct file_security_struct *fsec;
3160
3161 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003162 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 fsec = file->f_security;
3165
3166 if (!signum)
3167 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3168 else
3169 perm = signal_to_av(signum);
3170
David Howells275bb412008-11-14 10:39:19 +11003171 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 SECCLASS_PROCESS, perm, NULL);
3173}
3174
3175static int selinux_file_receive(struct file *file)
3176{
David Howells88e67f32008-11-14 10:39:21 +11003177 const struct cred *cred = current_cred();
3178
3179 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180}
3181
David Howells745ca242008-11-14 10:39:22 +11003182static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003183{
3184 struct file_security_struct *fsec;
3185 struct inode *inode;
3186 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003187
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003188 inode = file->f_path.dentry->d_inode;
3189 fsec = file->f_security;
3190 isec = inode->i_security;
3191 /*
3192 * Save inode label and policy sequence number
3193 * at open-time so that selinux_file_permission
3194 * can determine whether revalidation is necessary.
3195 * Task label is already saved in the file security
3196 * struct as its SID.
3197 */
3198 fsec->isid = isec->sid;
3199 fsec->pseqno = avc_policy_seqno();
3200 /*
3201 * Since the inode label or policy seqno may have changed
3202 * between the selinux_inode_permission check and the saving
3203 * of state above, recheck that access is still permitted.
3204 * Otherwise, access might never be revalidated against the
3205 * new inode label or new policy.
3206 * This check is not redundant - do not remove.
3207 */
David Howells88e67f32008-11-14 10:39:21 +11003208 return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003209}
3210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211/* task security operations */
3212
3213static int selinux_task_create(unsigned long clone_flags)
3214{
3215 int rc;
3216
3217 rc = secondary_ops->task_create(clone_flags);
3218 if (rc)
3219 return rc;
3220
David Howells3b11a1d2008-11-14 10:39:26 +11003221 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222}
3223
David Howellsf1752ee2008-11-14 10:39:17 +11003224/*
3225 * detach and free the LSM part of a set of credentials
3226 */
3227static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228{
David Howellsf1752ee2008-11-14 10:39:17 +11003229 struct task_security_struct *tsec = cred->security;
3230 cred->security = NULL;
3231 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232}
3233
David Howellsd84f4f92008-11-14 10:39:23 +11003234/*
3235 * prepare a new set of credentials for modification
3236 */
3237static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3238 gfp_t gfp)
3239{
3240 const struct task_security_struct *old_tsec;
3241 struct task_security_struct *tsec;
3242
3243 old_tsec = old->security;
3244
3245 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3246 if (!tsec)
3247 return -ENOMEM;
3248
3249 new->security = tsec;
3250 return 0;
3251}
3252
3253/*
3254 * commit new credentials
3255 */
3256static void selinux_cred_commit(struct cred *new, const struct cred *old)
3257{
3258 secondary_ops->cred_commit(new, old);
3259}
3260
David Howells3a3b7ce2008-11-14 10:39:28 +11003261/*
3262 * set the security data for a kernel service
3263 * - all the creation contexts are set to unlabelled
3264 */
3265static int selinux_kernel_act_as(struct cred *new, u32 secid)
3266{
3267 struct task_security_struct *tsec = new->security;
3268 u32 sid = current_sid();
3269 int ret;
3270
3271 ret = avc_has_perm(sid, secid,
3272 SECCLASS_KERNEL_SERVICE,
3273 KERNEL_SERVICE__USE_AS_OVERRIDE,
3274 NULL);
3275 if (ret == 0) {
3276 tsec->sid = secid;
3277 tsec->create_sid = 0;
3278 tsec->keycreate_sid = 0;
3279 tsec->sockcreate_sid = 0;
3280 }
3281 return ret;
3282}
3283
3284/*
3285 * set the file creation context in a security record to the same as the
3286 * objective context of the specified inode
3287 */
3288static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3289{
3290 struct inode_security_struct *isec = inode->i_security;
3291 struct task_security_struct *tsec = new->security;
3292 u32 sid = current_sid();
3293 int ret;
3294
3295 ret = avc_has_perm(sid, isec->sid,
3296 SECCLASS_KERNEL_SERVICE,
3297 KERNEL_SERVICE__CREATE_FILES_AS,
3298 NULL);
3299
3300 if (ret == 0)
3301 tsec->create_sid = isec->sid;
3302 return 0;
3303}
3304
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3306{
3307 /* Since setuid only affects the current process, and
3308 since the SELinux controls are not based on the Linux
3309 identity attributes, SELinux does not need to control
3310 this operation. However, SELinux does control the use
3311 of the CAP_SETUID and CAP_SETGID capabilities using the
3312 capable hook. */
3313 return 0;
3314}
3315
David Howellsd84f4f92008-11-14 10:39:23 +11003316static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3317 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318{
David Howellsd84f4f92008-11-14 10:39:23 +11003319 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320}
3321
3322static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3323{
3324 /* See the comment for setuid above. */
3325 return 0;
3326}
3327
3328static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3329{
David Howells3b11a1d2008-11-14 10:39:26 +11003330 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331}
3332
3333static int selinux_task_getpgid(struct task_struct *p)
3334{
David Howells3b11a1d2008-11-14 10:39:26 +11003335 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336}
3337
3338static int selinux_task_getsid(struct task_struct *p)
3339{
David Howells3b11a1d2008-11-14 10:39:26 +11003340 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341}
3342
David Quigleyf9008e42006-06-30 01:55:46 -07003343static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3344{
David Howells275bb412008-11-14 10:39:19 +11003345 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003346}
3347
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348static int selinux_task_setgroups(struct group_info *group_info)
3349{
3350 /* See the comment for setuid above. */
3351 return 0;
3352}
3353
3354static int selinux_task_setnice(struct task_struct *p, int nice)
3355{
3356 int rc;
3357
3358 rc = secondary_ops->task_setnice(p, nice);
3359 if (rc)
3360 return rc;
3361
David Howells3b11a1d2008-11-14 10:39:26 +11003362 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363}
3364
James Morris03e68062006-06-23 02:03:58 -07003365static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3366{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003367 int rc;
3368
3369 rc = secondary_ops->task_setioprio(p, ioprio);
3370 if (rc)
3371 return rc;
3372
David Howells3b11a1d2008-11-14 10:39:26 +11003373 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003374}
3375
David Quigleya1836a42006-06-30 01:55:49 -07003376static int selinux_task_getioprio(struct task_struct *p)
3377{
David Howells3b11a1d2008-11-14 10:39:26 +11003378 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003379}
3380
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3382{
3383 struct rlimit *old_rlim = current->signal->rlim + resource;
3384 int rc;
3385
3386 rc = secondary_ops->task_setrlimit(resource, new_rlim);
3387 if (rc)
3388 return rc;
3389
3390 /* Control the ability to change the hard limit (whether
3391 lowering or raising it), so that the hard limit can
3392 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003393 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003395 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396
3397 return 0;
3398}
3399
3400static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3401{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003402 int rc;
3403
3404 rc = secondary_ops->task_setscheduler(p, policy, lp);
3405 if (rc)
3406 return rc;
3407
David Howells3b11a1d2008-11-14 10:39:26 +11003408 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409}
3410
3411static int selinux_task_getscheduler(struct task_struct *p)
3412{
David Howells3b11a1d2008-11-14 10:39:26 +11003413 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414}
3415
David Quigley35601542006-06-23 02:04:01 -07003416static int selinux_task_movememory(struct task_struct *p)
3417{
David Howells3b11a1d2008-11-14 10:39:26 +11003418 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003419}
3420
David Quigleyf9008e42006-06-30 01:55:46 -07003421static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3422 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423{
3424 u32 perm;
3425 int rc;
3426
David Quigleyf9008e42006-06-30 01:55:46 -07003427 rc = secondary_ops->task_kill(p, info, sig, secid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 if (rc)
3429 return rc;
3430
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 if (!sig)
3432 perm = PROCESS__SIGNULL; /* null signal; existence test */
3433 else
3434 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003435 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003436 rc = avc_has_perm(secid, task_sid(p),
3437 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003438 else
David Howells3b11a1d2008-11-14 10:39:26 +11003439 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003440 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441}
3442
3443static int selinux_task_prctl(int option,
3444 unsigned long arg2,
3445 unsigned long arg3,
3446 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003447 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448{
3449 /* The current prctl operations do not appear to require
3450 any SELinux controls since they merely observe or modify
3451 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003452 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453}
3454
3455static int selinux_task_wait(struct task_struct *p)
3456{
Eric Paris8a535142007-10-22 16:10:31 -04003457 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458}
3459
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460static void selinux_task_to_inode(struct task_struct *p,
3461 struct inode *inode)
3462{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003464 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465
David Howells275bb412008-11-14 10:39:19 +11003466 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468}
3469
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003471static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3472 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473{
3474 int offset, ihlen, ret = -EINVAL;
3475 struct iphdr _iph, *ih;
3476
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003477 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3479 if (ih == NULL)
3480 goto out;
3481
3482 ihlen = ih->ihl * 4;
3483 if (ihlen < sizeof(_iph))
3484 goto out;
3485
3486 ad->u.net.v4info.saddr = ih->saddr;
3487 ad->u.net.v4info.daddr = ih->daddr;
3488 ret = 0;
3489
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003490 if (proto)
3491 *proto = ih->protocol;
3492
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003494 case IPPROTO_TCP: {
3495 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
Eric Paris828dfe12008-04-17 13:17:49 -04003497 if (ntohs(ih->frag_off) & IP_OFFSET)
3498 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
3500 offset += ihlen;
3501 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3502 if (th == NULL)
3503 break;
3504
3505 ad->u.net.sport = th->source;
3506 ad->u.net.dport = th->dest;
3507 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509
Eric Paris828dfe12008-04-17 13:17:49 -04003510 case IPPROTO_UDP: {
3511 struct udphdr _udph, *uh;
3512
3513 if (ntohs(ih->frag_off) & IP_OFFSET)
3514 break;
3515
3516 offset += ihlen;
3517 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3518 if (uh == NULL)
3519 break;
3520
3521 ad->u.net.sport = uh->source;
3522 ad->u.net.dport = uh->dest;
3523 break;
3524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
James Morris2ee92d42006-11-13 16:09:01 -08003526 case IPPROTO_DCCP: {
3527 struct dccp_hdr _dccph, *dh;
3528
3529 if (ntohs(ih->frag_off) & IP_OFFSET)
3530 break;
3531
3532 offset += ihlen;
3533 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3534 if (dh == NULL)
3535 break;
3536
3537 ad->u.net.sport = dh->dccph_sport;
3538 ad->u.net.dport = dh->dccph_dport;
3539 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003540 }
James Morris2ee92d42006-11-13 16:09:01 -08003541
Eric Paris828dfe12008-04-17 13:17:49 -04003542 default:
3543 break;
3544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545out:
3546 return ret;
3547}
3548
3549#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3550
3551/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003552static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3553 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554{
3555 u8 nexthdr;
3556 int ret = -EINVAL, offset;
3557 struct ipv6hdr _ipv6h, *ip6;
3558
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003559 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3561 if (ip6 == NULL)
3562 goto out;
3563
3564 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3565 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3566 ret = 0;
3567
3568 nexthdr = ip6->nexthdr;
3569 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003570 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 if (offset < 0)
3572 goto out;
3573
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003574 if (proto)
3575 *proto = nexthdr;
3576
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 switch (nexthdr) {
3578 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003579 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
3581 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3582 if (th == NULL)
3583 break;
3584
3585 ad->u.net.sport = th->source;
3586 ad->u.net.dport = th->dest;
3587 break;
3588 }
3589
3590 case IPPROTO_UDP: {
3591 struct udphdr _udph, *uh;
3592
3593 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3594 if (uh == NULL)
3595 break;
3596
3597 ad->u.net.sport = uh->source;
3598 ad->u.net.dport = uh->dest;
3599 break;
3600 }
3601
James Morris2ee92d42006-11-13 16:09:01 -08003602 case IPPROTO_DCCP: {
3603 struct dccp_hdr _dccph, *dh;
3604
3605 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3606 if (dh == NULL)
3607 break;
3608
3609 ad->u.net.sport = dh->dccph_sport;
3610 ad->u.net.dport = dh->dccph_dport;
3611 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003612 }
James Morris2ee92d42006-11-13 16:09:01 -08003613
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 /* includes fragments */
3615 default:
3616 break;
3617 }
3618out:
3619 return ret;
3620}
3621
3622#endif /* IPV6 */
3623
3624static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003625 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626{
David Howellscf9481e2008-07-27 21:31:07 +10003627 char *addrp;
3628 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
3630 switch (ad->u.net.family) {
3631 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003632 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003633 if (ret)
3634 goto parse_error;
3635 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3636 &ad->u.net.v4info.daddr);
3637 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
3639#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3640 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003641 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003642 if (ret)
3643 goto parse_error;
3644 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3645 &ad->u.net.v6info.daddr);
3646 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647#endif /* IPV6 */
3648 default:
David Howellscf9481e2008-07-27 21:31:07 +10003649 addrp = NULL;
3650 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 }
3652
David Howellscf9481e2008-07-27 21:31:07 +10003653parse_error:
3654 printk(KERN_WARNING
3655 "SELinux: failure in selinux_parse_skb(),"
3656 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003658
3659okay:
3660 if (_addrp)
3661 *_addrp = addrp;
3662 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663}
3664
Paul Moore4f6a9932007-03-01 14:35:22 -05003665/**
Paul Moore220deb92008-01-29 08:38:23 -05003666 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003667 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003668 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003669 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003670 *
3671 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003672 * Check the various different forms of network peer labeling and determine
3673 * the peer label/SID for the packet; most of the magic actually occurs in
3674 * the security server function security_net_peersid_cmp(). The function
3675 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3676 * or -EACCES if @sid is invalid due to inconsistencies with the different
3677 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003678 *
3679 */
Paul Moore220deb92008-01-29 08:38:23 -05003680static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003681{
Paul Moore71f1cb02008-01-29 08:51:16 -05003682 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003683 u32 xfrm_sid;
3684 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003685 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003686
3687 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003688 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003689
Paul Moore71f1cb02008-01-29 08:51:16 -05003690 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3691 if (unlikely(err)) {
3692 printk(KERN_WARNING
3693 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3694 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003695 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003696 }
Paul Moore220deb92008-01-29 08:38:23 -05003697
3698 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003699}
3700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701/* socket security operations */
3702static int socket_has_perm(struct task_struct *task, struct socket *sock,
3703 u32 perms)
3704{
3705 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003707 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 int err = 0;
3709
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 isec = SOCK_INODE(sock)->i_security;
3711
3712 if (isec->sid == SECINITSID_KERNEL)
3713 goto out;
David Howells275bb412008-11-14 10:39:19 +11003714 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
Eric Paris828dfe12008-04-17 13:17:49 -04003716 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003718 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
3720out:
3721 return err;
3722}
3723
3724static int selinux_socket_create(int family, int type,
3725 int protocol, int kern)
3726{
David Howells275bb412008-11-14 10:39:19 +11003727 const struct cred *cred = current_cred();
3728 const struct task_security_struct *tsec = cred->security;
3729 u32 sid, newsid;
3730 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
3733 if (kern)
3734 goto out;
3735
David Howells275bb412008-11-14 10:39:19 +11003736 sid = tsec->sid;
3737 newsid = tsec->sockcreate_sid ?: sid;
3738
3739 secclass = socket_type_to_security_class(family, type, protocol);
3740 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
3742out:
3743 return err;
3744}
3745
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003746static int selinux_socket_post_create(struct socket *sock, int family,
3747 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748{
David Howells275bb412008-11-14 10:39:19 +11003749 const struct cred *cred = current_cred();
3750 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003752 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003753 u32 sid, newsid;
3754 int err = 0;
3755
3756 sid = tsec->sid;
3757 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
3759 isec = SOCK_INODE(sock)->i_security;
3760
David Howells275bb412008-11-14 10:39:19 +11003761 if (kern)
3762 isec->sid = SECINITSID_KERNEL;
3763 else if (newsid)
3764 isec->sid = newsid;
3765 else
3766 isec->sid = sid;
3767
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 isec->initialized = 1;
3770
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003771 if (sock->sk) {
3772 sksec = sock->sk->sk_security;
3773 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003774 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003775 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003776 }
3777
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003778 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779}
3780
3781/* Range of port numbers used to automatically bind.
3782 Need to determine whether we should perform a name_bind
3783 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
3785static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3786{
3787 u16 family;
3788 int err;
3789
3790 err = socket_has_perm(current, sock, SOCKET__BIND);
3791 if (err)
3792 goto out;
3793
3794 /*
3795 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003796 * Multiple address binding for SCTP is not supported yet: we just
3797 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 */
3799 family = sock->sk->sk_family;
3800 if (family == PF_INET || family == PF_INET6) {
3801 char *addrp;
3802 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 struct avc_audit_data ad;
3804 struct sockaddr_in *addr4 = NULL;
3805 struct sockaddr_in6 *addr6 = NULL;
3806 unsigned short snum;
3807 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003808 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 isec = SOCK_INODE(sock)->i_security;
3811
3812 if (family == PF_INET) {
3813 addr4 = (struct sockaddr_in *)address;
3814 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 addrp = (char *)&addr4->sin_addr.s_addr;
3816 } else {
3817 addr6 = (struct sockaddr_in6 *)address;
3818 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 addrp = (char *)&addr6->sin6_addr.s6_addr;
3820 }
3821
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003822 if (snum) {
3823 int low, high;
3824
3825 inet_get_local_port_range(&low, &high);
3826
3827 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003828 err = sel_netport_sid(sk->sk_protocol,
3829 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003830 if (err)
3831 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003832 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003833 ad.u.net.sport = htons(snum);
3834 ad.u.net.family = family;
3835 err = avc_has_perm(isec->sid, sid,
3836 isec->sclass,
3837 SOCKET__NAME_BIND, &ad);
3838 if (err)
3839 goto out;
3840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 }
Eric Paris828dfe12008-04-17 13:17:49 -04003842
3843 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003844 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 node_perm = TCP_SOCKET__NODE_BIND;
3846 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003847
James Morris13402582005-09-30 14:24:34 -04003848 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 node_perm = UDP_SOCKET__NODE_BIND;
3850 break;
James Morris2ee92d42006-11-13 16:09:01 -08003851
3852 case SECCLASS_DCCP_SOCKET:
3853 node_perm = DCCP_SOCKET__NODE_BIND;
3854 break;
3855
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 default:
3857 node_perm = RAWIP_SOCKET__NODE_BIND;
3858 break;
3859 }
Eric Paris828dfe12008-04-17 13:17:49 -04003860
Paul Moore224dfbd2008-01-29 08:38:13 -05003861 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 if (err)
3863 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003864
3865 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 ad.u.net.sport = htons(snum);
3867 ad.u.net.family = family;
3868
3869 if (family == PF_INET)
3870 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3871 else
3872 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3873
3874 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003875 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 if (err)
3877 goto out;
3878 }
3879out:
3880 return err;
3881}
3882
3883static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3884{
Paul Moore014ab192008-10-10 10:16:33 -04003885 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 struct inode_security_struct *isec;
3887 int err;
3888
3889 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3890 if (err)
3891 return err;
3892
3893 /*
James Morris2ee92d42006-11-13 16:09:01 -08003894 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 */
3896 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003897 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3898 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 struct avc_audit_data ad;
3900 struct sockaddr_in *addr4 = NULL;
3901 struct sockaddr_in6 *addr6 = NULL;
3902 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003903 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
3905 if (sk->sk_family == PF_INET) {
3906 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003907 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 return -EINVAL;
3909 snum = ntohs(addr4->sin_port);
3910 } else {
3911 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003912 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 return -EINVAL;
3914 snum = ntohs(addr6->sin6_port);
3915 }
3916
Paul Moore3e112172008-04-10 10:48:14 -04003917 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 if (err)
3919 goto out;
3920
James Morris2ee92d42006-11-13 16:09:01 -08003921 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3922 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3923
Eric Paris828dfe12008-04-17 13:17:49 -04003924 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 ad.u.net.dport = htons(snum);
3926 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003927 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 if (err)
3929 goto out;
3930 }
3931
Paul Moore014ab192008-10-10 10:16:33 -04003932 err = selinux_netlbl_socket_connect(sk, address);
3933
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934out:
3935 return err;
3936}
3937
3938static int selinux_socket_listen(struct socket *sock, int backlog)
3939{
3940 return socket_has_perm(current, sock, SOCKET__LISTEN);
3941}
3942
3943static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3944{
3945 int err;
3946 struct inode_security_struct *isec;
3947 struct inode_security_struct *newisec;
3948
3949 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3950 if (err)
3951 return err;
3952
3953 newisec = SOCK_INODE(newsock)->i_security;
3954
3955 isec = SOCK_INODE(sock)->i_security;
3956 newisec->sclass = isec->sclass;
3957 newisec->sid = isec->sid;
3958 newisec->initialized = 1;
3959
3960 return 0;
3961}
3962
3963static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003964 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003966 int rc;
3967
3968 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3969 if (rc)
3970 return rc;
3971
3972 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973}
3974
3975static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3976 int size, int flags)
3977{
3978 return socket_has_perm(current, sock, SOCKET__READ);
3979}
3980
3981static int selinux_socket_getsockname(struct socket *sock)
3982{
3983 return socket_has_perm(current, sock, SOCKET__GETATTR);
3984}
3985
3986static int selinux_socket_getpeername(struct socket *sock)
3987{
3988 return socket_has_perm(current, sock, SOCKET__GETATTR);
3989}
3990
Eric Paris828dfe12008-04-17 13:17:49 -04003991static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992{
Paul Mooref8687af2006-10-30 15:22:15 -08003993 int err;
3994
3995 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3996 if (err)
3997 return err;
3998
3999 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000}
4001
4002static int selinux_socket_getsockopt(struct socket *sock, int level,
4003 int optname)
4004{
4005 return socket_has_perm(current, sock, SOCKET__GETOPT);
4006}
4007
4008static int selinux_socket_shutdown(struct socket *sock, int how)
4009{
4010 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
4011}
4012
4013static int selinux_socket_unix_stream_connect(struct socket *sock,
4014 struct socket *other,
4015 struct sock *newsk)
4016{
4017 struct sk_security_struct *ssec;
4018 struct inode_security_struct *isec;
4019 struct inode_security_struct *other_isec;
4020 struct avc_audit_data ad;
4021 int err;
4022
4023 err = secondary_ops->unix_stream_connect(sock, other, newsk);
4024 if (err)
4025 return err;
4026
4027 isec = SOCK_INODE(sock)->i_security;
4028 other_isec = SOCK_INODE(other)->i_security;
4029
Eric Paris828dfe12008-04-17 13:17:49 -04004030 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 ad.u.net.sk = other->sk;
4032
4033 err = avc_has_perm(isec->sid, other_isec->sid,
4034 isec->sclass,
4035 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4036 if (err)
4037 return err;
4038
4039 /* connecting socket */
4040 ssec = sock->sk->sk_security;
4041 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004042
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 /* server child socket */
4044 ssec = newsk->sk_security;
4045 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004046 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4047
4048 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049}
4050
4051static int selinux_socket_unix_may_send(struct socket *sock,
4052 struct socket *other)
4053{
4054 struct inode_security_struct *isec;
4055 struct inode_security_struct *other_isec;
4056 struct avc_audit_data ad;
4057 int err;
4058
4059 isec = SOCK_INODE(sock)->i_security;
4060 other_isec = SOCK_INODE(other)->i_security;
4061
Eric Paris828dfe12008-04-17 13:17:49 -04004062 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 ad.u.net.sk = other->sk;
4064
4065 err = avc_has_perm(isec->sid, other_isec->sid,
4066 isec->sclass, SOCKET__SENDTO, &ad);
4067 if (err)
4068 return err;
4069
4070 return 0;
4071}
4072
Paul Mooreeffad8d2008-01-29 08:49:27 -05004073static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4074 u32 peer_sid,
4075 struct avc_audit_data *ad)
4076{
4077 int err;
4078 u32 if_sid;
4079 u32 node_sid;
4080
4081 err = sel_netif_sid(ifindex, &if_sid);
4082 if (err)
4083 return err;
4084 err = avc_has_perm(peer_sid, if_sid,
4085 SECCLASS_NETIF, NETIF__INGRESS, ad);
4086 if (err)
4087 return err;
4088
4089 err = sel_netnode_sid(addrp, family, &node_sid);
4090 if (err)
4091 return err;
4092 return avc_has_perm(peer_sid, node_sid,
4093 SECCLASS_NODE, NODE__RECVFROM, ad);
4094}
4095
Paul Moore220deb92008-01-29 08:38:23 -05004096static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4097 struct sk_buff *skb,
4098 struct avc_audit_data *ad,
4099 u16 family,
4100 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101{
Paul Moore220deb92008-01-29 08:38:23 -05004102 int err;
4103 struct sk_security_struct *sksec = sk->sk_security;
4104 u16 sk_class;
4105 u32 netif_perm, node_perm, recv_perm;
4106 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004107
Paul Moore220deb92008-01-29 08:38:23 -05004108 sk_sid = sksec->sid;
4109 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
Paul Moore220deb92008-01-29 08:38:23 -05004111 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 case SECCLASS_UDP_SOCKET:
4113 netif_perm = NETIF__UDP_RECV;
4114 node_perm = NODE__UDP_RECV;
4115 recv_perm = UDP_SOCKET__RECV_MSG;
4116 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 case SECCLASS_TCP_SOCKET:
4118 netif_perm = NETIF__TCP_RECV;
4119 node_perm = NODE__TCP_RECV;
4120 recv_perm = TCP_SOCKET__RECV_MSG;
4121 break;
James Morris2ee92d42006-11-13 16:09:01 -08004122 case SECCLASS_DCCP_SOCKET:
4123 netif_perm = NETIF__DCCP_RECV;
4124 node_perm = NODE__DCCP_RECV;
4125 recv_perm = DCCP_SOCKET__RECV_MSG;
4126 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 default:
4128 netif_perm = NETIF__RAWIP_RECV;
4129 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004130 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 break;
4132 }
4133
Paul Moore220deb92008-01-29 08:38:23 -05004134 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004136 return err;
4137 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4138 if (err)
4139 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004140
Paul Moore224dfbd2008-01-29 08:38:13 -05004141 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004143 return err;
4144 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004146 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147
Paul Moore220deb92008-01-29 08:38:23 -05004148 if (!recv_perm)
4149 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004150 err = sel_netport_sid(sk->sk_protocol,
4151 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004152 if (unlikely(err)) {
4153 printk(KERN_WARNING
4154 "SELinux: failure in"
4155 " selinux_sock_rcv_skb_iptables_compat(),"
4156 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004157 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004158 }
Paul Moore220deb92008-01-29 08:38:23 -05004159 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4160}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161
Paul Moore220deb92008-01-29 08:38:23 -05004162static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004163 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004164{
Paul Moore277d3422008-12-31 12:54:11 -05004165 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004166 struct sk_security_struct *sksec = sk->sk_security;
4167 u32 peer_sid;
4168 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004169 struct avc_audit_data ad;
4170 char *addrp;
4171
4172 AVC_AUDIT_DATA_INIT(&ad, NET);
4173 ad.u.net.netif = skb->iif;
4174 ad.u.net.family = family;
4175 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4176 if (err)
4177 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004178
4179 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004180 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004181 family, addrp);
Paul Moore277d3422008-12-31 12:54:11 -05004182 else if (selinux_secmark_enabled())
Paul Moore220deb92008-01-29 08:38:23 -05004183 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004184 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004185 if (err)
4186 return err;
4187
4188 if (selinux_policycap_netpeer) {
4189 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004191 return err;
4192 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004193 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004194 if (err)
4195 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004196 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004197 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004198 if (err)
4199 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004200 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004202
James Morris4e5ab4c2006-06-09 00:33:33 -07004203 return err;
4204}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004205
James Morris4e5ab4c2006-06-09 00:33:33 -07004206static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4207{
Paul Moore220deb92008-01-29 08:38:23 -05004208 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004209 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004210 u16 family = sk->sk_family;
4211 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004212 struct avc_audit_data ad;
4213 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004214 u8 secmark_active;
4215 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004216
James Morris4e5ab4c2006-06-09 00:33:33 -07004217 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004218 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004219
4220 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004221 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004222 family = PF_INET;
4223
Paul Moored8395c82008-10-10 10:16:30 -04004224 /* If any sort of compatibility mode is enabled then handoff processing
4225 * to the selinux_sock_rcv_skb_compat() function to deal with the
4226 * special handling. We do this in an attempt to keep this function
4227 * as fast and as clean as possible. */
4228 if (selinux_compat_net || !selinux_policycap_netpeer)
4229 return selinux_sock_rcv_skb_compat(sk, skb, family);
4230
4231 secmark_active = selinux_secmark_enabled();
4232 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4233 if (!secmark_active && !peerlbl_active)
4234 return 0;
4235
James Morris4e5ab4c2006-06-09 00:33:33 -07004236 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004237 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004238 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004239 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004240 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004241 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004242
Paul Moored8395c82008-10-10 10:16:30 -04004243 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004244 u32 peer_sid;
4245
4246 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4247 if (err)
4248 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004249 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4250 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004251 if (err) {
4252 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004253 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004254 }
Paul Moored621d352008-01-29 08:43:36 -05004255 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4256 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004257 if (err)
4258 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004259 }
4260
Paul Moored8395c82008-10-10 10:16:30 -04004261 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004262 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4263 PACKET__RECV, &ad);
4264 if (err)
4265 return err;
4266 }
4267
Paul Moored621d352008-01-29 08:43:36 -05004268 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269}
4270
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004271static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4272 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273{
4274 int err = 0;
4275 char *scontext;
4276 u32 scontext_len;
4277 struct sk_security_struct *ssec;
4278 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004279 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
4281 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004282
Paul Moore3de4bab2006-11-17 17:38:54 -05004283 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4284 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004285 ssec = sock->sk->sk_security;
4286 peer_sid = ssec->peer_sid;
4287 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004288 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 err = -ENOPROTOOPT;
4290 goto out;
4291 }
4292
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004293 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4294
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 if (err)
4296 goto out;
4297
4298 if (scontext_len > len) {
4299 err = -ERANGE;
4300 goto out_len;
4301 }
4302
4303 if (copy_to_user(optval, scontext, scontext_len))
4304 err = -EFAULT;
4305
4306out_len:
4307 if (put_user(scontext_len, optlen))
4308 err = -EFAULT;
4309
4310 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004311out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 return err;
4313}
4314
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004315static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004316{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004317 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004318 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004319
Paul Mooreaa862902008-10-10 10:16:29 -04004320 if (skb && skb->protocol == htons(ETH_P_IP))
4321 family = PF_INET;
4322 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4323 family = PF_INET6;
4324 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004325 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004326 else
4327 goto out;
4328
4329 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004330 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004331 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004332 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004333
Paul Moore75e22912008-01-29 08:38:04 -05004334out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004335 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004336 if (peer_secid == SECSID_NULL)
4337 return -EINVAL;
4338 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004339}
4340
Al Viro7d877f32005-10-21 03:20:43 -04004341static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342{
4343 return sk_alloc_security(sk, family, priority);
4344}
4345
4346static void selinux_sk_free_security(struct sock *sk)
4347{
4348 sk_free_security(sk);
4349}
4350
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004351static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4352{
4353 struct sk_security_struct *ssec = sk->sk_security;
4354 struct sk_security_struct *newssec = newsk->sk_security;
4355
4356 newssec->sid = ssec->sid;
4357 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004358 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004359
Paul Mooref74af6e2008-02-25 11:40:33 -05004360 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004361}
4362
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004363static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004364{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004365 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004366 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004367 else {
4368 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004369
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004370 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004371 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004372}
4373
Eric Paris828dfe12008-04-17 13:17:49 -04004374static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004375{
4376 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4377 struct sk_security_struct *sksec = sk->sk_security;
4378
David Woodhouse2148ccc2006-09-29 15:50:25 -07004379 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4380 sk->sk_family == PF_UNIX)
4381 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004382 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004383}
4384
Adrian Bunk9a673e52006-08-15 00:03:53 -07004385static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4386 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004387{
4388 struct sk_security_struct *sksec = sk->sk_security;
4389 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004390 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004391 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004392 u32 peersid;
4393
Paul Mooreaa862902008-10-10 10:16:29 -04004394 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4395 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4396 family = PF_INET;
4397
4398 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004399 if (err)
4400 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004401 if (peersid == SECSID_NULL) {
4402 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004403 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004404 return 0;
4405 }
4406
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004407 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4408 if (err)
4409 return err;
4410
4411 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004412 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004413 return 0;
4414}
4415
Adrian Bunk9a673e52006-08-15 00:03:53 -07004416static void selinux_inet_csk_clone(struct sock *newsk,
4417 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004418{
4419 struct sk_security_struct *newsksec = newsk->sk_security;
4420
4421 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004422 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004423 /* NOTE: Ideally, we should also get the isec->sid for the
4424 new socket in sync, but we don't have the isec available yet.
4425 So we will wait until sock_graft to do it, by which
4426 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004427
Paul Moore9f2ad662006-11-17 17:38:53 -05004428 /* We don't need to take any sort of lock here as we are the only
4429 * thread with access to newsksec */
4430 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004431}
4432
Paul Moore014ab192008-10-10 10:16:33 -04004433static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004434{
Paul Mooreaa862902008-10-10 10:16:29 -04004435 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004436 struct sk_security_struct *sksec = sk->sk_security;
4437
Paul Mooreaa862902008-10-10 10:16:29 -04004438 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4439 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4440 family = PF_INET;
4441
4442 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004443
4444 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004445}
4446
Adrian Bunk9a673e52006-08-15 00:03:53 -07004447static void selinux_req_classify_flow(const struct request_sock *req,
4448 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004449{
4450 fl->secid = req->secid;
4451}
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4454{
4455 int err = 0;
4456 u32 perm;
4457 struct nlmsghdr *nlh;
4458 struct socket *sock = sk->sk_socket;
4459 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 if (skb->len < NLMSG_SPACE(0)) {
4462 err = -EINVAL;
4463 goto out;
4464 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004465 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004466
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4468 if (err) {
4469 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004470 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 "SELinux: unrecognized netlink message"
4472 " type=%hu for sclass=%hu\n",
4473 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004474 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 err = 0;
4476 }
4477
4478 /* Ignore */
4479 if (err == -ENOENT)
4480 err = 0;
4481 goto out;
4482 }
4483
4484 err = socket_has_perm(current, sock, perm);
4485out:
4486 return err;
4487}
4488
4489#ifdef CONFIG_NETFILTER
4490
Paul Mooreeffad8d2008-01-29 08:49:27 -05004491static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4492 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493{
Paul Mooredfaebe92008-10-10 10:16:31 -04004494 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004495 char *addrp;
4496 u32 peer_sid;
4497 struct avc_audit_data ad;
4498 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004499 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004500 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004501
Paul Mooreeffad8d2008-01-29 08:49:27 -05004502 if (!selinux_policycap_netpeer)
4503 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004504
Paul Mooreeffad8d2008-01-29 08:49:27 -05004505 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004506 netlbl_active = netlbl_enabled();
4507 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004508 if (!secmark_active && !peerlbl_active)
4509 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004510
Paul Moored8395c82008-10-10 10:16:30 -04004511 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4512 return NF_DROP;
4513
Paul Mooreeffad8d2008-01-29 08:49:27 -05004514 AVC_AUDIT_DATA_INIT(&ad, NET);
4515 ad.u.net.netif = ifindex;
4516 ad.u.net.family = family;
4517 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4518 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
Paul Mooredfaebe92008-10-10 10:16:31 -04004520 if (peerlbl_active) {
4521 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4522 peer_sid, &ad);
4523 if (err) {
4524 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004525 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004526 }
4527 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004528
4529 if (secmark_active)
4530 if (avc_has_perm(peer_sid, skb->secmark,
4531 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4532 return NF_DROP;
4533
Paul Moore948bf852008-10-10 10:16:32 -04004534 if (netlbl_active)
4535 /* we do this in the FORWARD path and not the POST_ROUTING
4536 * path because we want to make sure we apply the necessary
4537 * labeling before IPsec is applied so we can leverage AH
4538 * protection */
4539 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4540 return NF_DROP;
4541
Paul Mooreeffad8d2008-01-29 08:49:27 -05004542 return NF_ACCEPT;
4543}
4544
4545static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4546 struct sk_buff *skb,
4547 const struct net_device *in,
4548 const struct net_device *out,
4549 int (*okfn)(struct sk_buff *))
4550{
4551 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4552}
4553
4554#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4555static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4556 struct sk_buff *skb,
4557 const struct net_device *in,
4558 const struct net_device *out,
4559 int (*okfn)(struct sk_buff *))
4560{
4561 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4562}
4563#endif /* IPV6 */
4564
Paul Moore948bf852008-10-10 10:16:32 -04004565static unsigned int selinux_ip_output(struct sk_buff *skb,
4566 u16 family)
4567{
4568 u32 sid;
4569
4570 if (!netlbl_enabled())
4571 return NF_ACCEPT;
4572
4573 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4574 * because we want to make sure we apply the necessary labeling
4575 * before IPsec is applied so we can leverage AH protection */
4576 if (skb->sk) {
4577 struct sk_security_struct *sksec = skb->sk->sk_security;
4578 sid = sksec->sid;
4579 } else
4580 sid = SECINITSID_KERNEL;
4581 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4582 return NF_DROP;
4583
4584 return NF_ACCEPT;
4585}
4586
4587static unsigned int selinux_ipv4_output(unsigned int hooknum,
4588 struct sk_buff *skb,
4589 const struct net_device *in,
4590 const struct net_device *out,
4591 int (*okfn)(struct sk_buff *))
4592{
4593 return selinux_ip_output(skb, PF_INET);
4594}
4595
Paul Mooreeffad8d2008-01-29 08:49:27 -05004596static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4597 int ifindex,
4598 struct avc_audit_data *ad,
4599 u16 family, char *addrp)
4600{
4601 int err;
4602 struct sk_security_struct *sksec = sk->sk_security;
4603 u16 sk_class;
4604 u32 netif_perm, node_perm, send_perm;
4605 u32 port_sid, node_sid, if_sid, sk_sid;
4606
4607 sk_sid = sksec->sid;
4608 sk_class = sksec->sclass;
4609
4610 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 case SECCLASS_UDP_SOCKET:
4612 netif_perm = NETIF__UDP_SEND;
4613 node_perm = NODE__UDP_SEND;
4614 send_perm = UDP_SOCKET__SEND_MSG;
4615 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 case SECCLASS_TCP_SOCKET:
4617 netif_perm = NETIF__TCP_SEND;
4618 node_perm = NODE__TCP_SEND;
4619 send_perm = TCP_SOCKET__SEND_MSG;
4620 break;
James Morris2ee92d42006-11-13 16:09:01 -08004621 case SECCLASS_DCCP_SOCKET:
4622 netif_perm = NETIF__DCCP_SEND;
4623 node_perm = NODE__DCCP_SEND;
4624 send_perm = DCCP_SOCKET__SEND_MSG;
4625 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 default:
4627 netif_perm = NETIF__RAWIP_SEND;
4628 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004629 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 break;
4631 }
4632
Paul Mooreeffad8d2008-01-29 08:49:27 -05004633 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004634 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004635 return err;
4636 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4637 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004638
Paul Moore224dfbd2008-01-29 08:38:13 -05004639 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004640 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004641 return err;
4642 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004643 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004644 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
Paul Mooreeffad8d2008-01-29 08:49:27 -05004646 if (send_perm != 0)
4647 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648
Paul Moore3e112172008-04-10 10:48:14 -04004649 err = sel_netport_sid(sk->sk_protocol,
4650 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004651 if (unlikely(err)) {
4652 printk(KERN_WARNING
4653 "SELinux: failure in"
4654 " selinux_ip_postroute_iptables_compat(),"
4655 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004656 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004657 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004658 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004659}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Paul Mooreeffad8d2008-01-29 08:49:27 -05004661static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4662 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004663 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004664{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004665 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004666 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004667 struct avc_audit_data ad;
4668 char *addrp;
4669 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004670
Paul Mooreeffad8d2008-01-29 08:49:27 -05004671 if (sk == NULL)
4672 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004673 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004674
Paul Moored8395c82008-10-10 10:16:30 -04004675 AVC_AUDIT_DATA_INIT(&ad, NET);
4676 ad.u.net.netif = ifindex;
4677 ad.u.net.family = family;
4678 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4679 return NF_DROP;
4680
Paul Mooreeffad8d2008-01-29 08:49:27 -05004681 if (selinux_compat_net) {
4682 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004683 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004684 return NF_DROP;
Paul Moore277d3422008-12-31 12:54:11 -05004685 } else if (selinux_secmark_enabled()) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004686 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004687 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004688 return NF_DROP;
4689 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004690
Paul Mooreeffad8d2008-01-29 08:49:27 -05004691 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004692 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004693 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004694
Paul Mooreeffad8d2008-01-29 08:49:27 -05004695 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696}
4697
Paul Mooreeffad8d2008-01-29 08:49:27 -05004698static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4699 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004701 u32 secmark_perm;
4702 u32 peer_sid;
4703 struct sock *sk;
4704 struct avc_audit_data ad;
4705 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706 u8 secmark_active;
4707 u8 peerlbl_active;
4708
Paul Mooreeffad8d2008-01-29 08:49:27 -05004709 /* If any sort of compatibility mode is enabled then handoff processing
4710 * to the selinux_ip_postroute_compat() function to deal with the
4711 * special handling. We do this in an attempt to keep this function
4712 * as fast and as clean as possible. */
4713 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004714 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004715#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4717 * packet transformation so allow the packet to pass without any checks
4718 * since we'll have another chance to perform access control checks
4719 * when the packet is on it's final way out.
4720 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4721 * is NULL, in this case go ahead and apply access control. */
4722 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4723 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004724#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004725 secmark_active = selinux_secmark_enabled();
4726 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4727 if (!secmark_active && !peerlbl_active)
4728 return NF_ACCEPT;
4729
Paul Moored8395c82008-10-10 10:16:30 -04004730 /* if the packet is being forwarded then get the peer label from the
4731 * packet itself; otherwise check to see if it is from a local
4732 * application or the kernel, if from an application get the peer label
4733 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004734 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004735 if (sk == NULL) {
4736 switch (family) {
4737 case PF_INET:
4738 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4739 secmark_perm = PACKET__FORWARD_OUT;
4740 else
4741 secmark_perm = PACKET__SEND;
4742 break;
4743 case PF_INET6:
4744 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4745 secmark_perm = PACKET__FORWARD_OUT;
4746 else
4747 secmark_perm = PACKET__SEND;
4748 break;
4749 default:
4750 return NF_DROP;
4751 }
4752 if (secmark_perm == PACKET__FORWARD_OUT) {
4753 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4754 return NF_DROP;
4755 } else
4756 peer_sid = SECINITSID_KERNEL;
4757 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004758 struct sk_security_struct *sksec = sk->sk_security;
4759 peer_sid = sksec->sid;
4760 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004761 }
4762
Paul Moored8395c82008-10-10 10:16:30 -04004763 AVC_AUDIT_DATA_INIT(&ad, NET);
4764 ad.u.net.netif = ifindex;
4765 ad.u.net.family = family;
4766 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4767 return NF_DROP;
4768
Paul Mooreeffad8d2008-01-29 08:49:27 -05004769 if (secmark_active)
4770 if (avc_has_perm(peer_sid, skb->secmark,
4771 SECCLASS_PACKET, secmark_perm, &ad))
4772 return NF_DROP;
4773
4774 if (peerlbl_active) {
4775 u32 if_sid;
4776 u32 node_sid;
4777
4778 if (sel_netif_sid(ifindex, &if_sid))
4779 return NF_DROP;
4780 if (avc_has_perm(peer_sid, if_sid,
4781 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4782 return NF_DROP;
4783
4784 if (sel_netnode_sid(addrp, family, &node_sid))
4785 return NF_DROP;
4786 if (avc_has_perm(peer_sid, node_sid,
4787 SECCLASS_NODE, NODE__SENDTO, &ad))
4788 return NF_DROP;
4789 }
4790
4791 return NF_ACCEPT;
4792}
4793
4794static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4795 struct sk_buff *skb,
4796 const struct net_device *in,
4797 const struct net_device *out,
4798 int (*okfn)(struct sk_buff *))
4799{
4800 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801}
4802
4803#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004804static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4805 struct sk_buff *skb,
4806 const struct net_device *in,
4807 const struct net_device *out,
4808 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004810 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812#endif /* IPV6 */
4813
4814#endif /* CONFIG_NETFILTER */
4815
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4817{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 int err;
4819
4820 err = secondary_ops->netlink_send(sk, skb);
4821 if (err)
4822 return err;
4823
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4825 err = selinux_nlmsg_perm(sk, skb);
4826
4827 return err;
4828}
4829
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004830static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004832 int err;
4833 struct avc_audit_data ad;
4834
4835 err = secondary_ops->netlink_recv(skb, capability);
4836 if (err)
4837 return err;
4838
4839 AVC_AUDIT_DATA_INIT(&ad, CAP);
4840 ad.u.cap = capability;
4841
4842 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004843 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844}
4845
4846static int ipc_alloc_security(struct task_struct *task,
4847 struct kern_ipc_perm *perm,
4848 u16 sclass)
4849{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004851 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
James Morris89d155e2005-10-30 14:59:21 -08004853 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 if (!isec)
4855 return -ENOMEM;
4856
David Howells275bb412008-11-14 10:39:19 +11004857 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004859 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 perm->security = isec;
4861
4862 return 0;
4863}
4864
4865static void ipc_free_security(struct kern_ipc_perm *perm)
4866{
4867 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 perm->security = NULL;
4869 kfree(isec);
4870}
4871
4872static int msg_msg_alloc_security(struct msg_msg *msg)
4873{
4874 struct msg_security_struct *msec;
4875
James Morris89d155e2005-10-30 14:59:21 -08004876 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 if (!msec)
4878 return -ENOMEM;
4879
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 msec->sid = SECINITSID_UNLABELED;
4881 msg->security = msec;
4882
4883 return 0;
4884}
4885
4886static void msg_msg_free_security(struct msg_msg *msg)
4887{
4888 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889
4890 msg->security = NULL;
4891 kfree(msec);
4892}
4893
4894static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004895 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 struct ipc_security_struct *isec;
4898 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004899 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 isec = ipc_perms->security;
4902
4903 AVC_AUDIT_DATA_INIT(&ad, IPC);
4904 ad.u.ipc_id = ipc_perms->key;
4905
David Howells275bb412008-11-14 10:39:19 +11004906 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907}
4908
4909static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4910{
4911 return msg_msg_alloc_security(msg);
4912}
4913
4914static void selinux_msg_msg_free_security(struct msg_msg *msg)
4915{
4916 msg_msg_free_security(msg);
4917}
4918
4919/* message queue security operations */
4920static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4921{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 struct ipc_security_struct *isec;
4923 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004924 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 int rc;
4926
4927 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4928 if (rc)
4929 return rc;
4930
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 isec = msq->q_perm.security;
4932
4933 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004934 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935
David Howells275bb412008-11-14 10:39:19 +11004936 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 MSGQ__CREATE, &ad);
4938 if (rc) {
4939 ipc_free_security(&msq->q_perm);
4940 return rc;
4941 }
4942 return 0;
4943}
4944
4945static void selinux_msg_queue_free_security(struct msg_queue *msq)
4946{
4947 ipc_free_security(&msq->q_perm);
4948}
4949
4950static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4951{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 struct ipc_security_struct *isec;
4953 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004954 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 isec = msq->q_perm.security;
4957
4958 AVC_AUDIT_DATA_INIT(&ad, IPC);
4959 ad.u.ipc_id = msq->q_perm.key;
4960
David Howells275bb412008-11-14 10:39:19 +11004961 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 MSGQ__ASSOCIATE, &ad);
4963}
4964
4965static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4966{
4967 int err;
4968 int perms;
4969
Eric Paris828dfe12008-04-17 13:17:49 -04004970 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 case IPC_INFO:
4972 case MSG_INFO:
4973 /* No specific object, just general system-wide information. */
4974 return task_has_system(current, SYSTEM__IPC_INFO);
4975 case IPC_STAT:
4976 case MSG_STAT:
4977 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4978 break;
4979 case IPC_SET:
4980 perms = MSGQ__SETATTR;
4981 break;
4982 case IPC_RMID:
4983 perms = MSGQ__DESTROY;
4984 break;
4985 default:
4986 return 0;
4987 }
4988
Stephen Smalley6af963f2005-05-01 08:58:39 -07004989 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 return err;
4991}
4992
4993static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4994{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 struct ipc_security_struct *isec;
4996 struct msg_security_struct *msec;
4997 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004998 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999 int rc;
5000
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 isec = msq->q_perm.security;
5002 msec = msg->security;
5003
5004 /*
5005 * First time through, need to assign label to the message
5006 */
5007 if (msec->sid == SECINITSID_UNLABELED) {
5008 /*
5009 * Compute new sid based on current process and
5010 * message queue this message will be stored in
5011 */
David Howells275bb412008-11-14 10:39:19 +11005012 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 &msec->sid);
5014 if (rc)
5015 return rc;
5016 }
5017
5018 AVC_AUDIT_DATA_INIT(&ad, IPC);
5019 ad.u.ipc_id = msq->q_perm.key;
5020
5021 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005022 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 MSGQ__WRITE, &ad);
5024 if (!rc)
5025 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005026 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5027 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 if (!rc)
5029 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005030 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5031 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032
5033 return rc;
5034}
5035
5036static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5037 struct task_struct *target,
5038 long type, int mode)
5039{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 struct ipc_security_struct *isec;
5041 struct msg_security_struct *msec;
5042 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005043 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 int rc;
5045
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 isec = msq->q_perm.security;
5047 msec = msg->security;
5048
5049 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005050 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
David Howells275bb412008-11-14 10:39:19 +11005052 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 SECCLASS_MSGQ, MSGQ__READ, &ad);
5054 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005055 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 SECCLASS_MSG, MSG__RECEIVE, &ad);
5057 return rc;
5058}
5059
5060/* Shared Memory security operations */
5061static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5062{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 struct ipc_security_struct *isec;
5064 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005065 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 int rc;
5067
5068 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5069 if (rc)
5070 return rc;
5071
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 isec = shp->shm_perm.security;
5073
5074 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005075 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076
David Howells275bb412008-11-14 10:39:19 +11005077 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 SHM__CREATE, &ad);
5079 if (rc) {
5080 ipc_free_security(&shp->shm_perm);
5081 return rc;
5082 }
5083 return 0;
5084}
5085
5086static void selinux_shm_free_security(struct shmid_kernel *shp)
5087{
5088 ipc_free_security(&shp->shm_perm);
5089}
5090
5091static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5092{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 struct ipc_security_struct *isec;
5094 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005095 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 isec = shp->shm_perm.security;
5098
5099 AVC_AUDIT_DATA_INIT(&ad, IPC);
5100 ad.u.ipc_id = shp->shm_perm.key;
5101
David Howells275bb412008-11-14 10:39:19 +11005102 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 SHM__ASSOCIATE, &ad);
5104}
5105
5106/* Note, at this point, shp is locked down */
5107static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5108{
5109 int perms;
5110 int err;
5111
Eric Paris828dfe12008-04-17 13:17:49 -04005112 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 case IPC_INFO:
5114 case SHM_INFO:
5115 /* No specific object, just general system-wide information. */
5116 return task_has_system(current, SYSTEM__IPC_INFO);
5117 case IPC_STAT:
5118 case SHM_STAT:
5119 perms = SHM__GETATTR | SHM__ASSOCIATE;
5120 break;
5121 case IPC_SET:
5122 perms = SHM__SETATTR;
5123 break;
5124 case SHM_LOCK:
5125 case SHM_UNLOCK:
5126 perms = SHM__LOCK;
5127 break;
5128 case IPC_RMID:
5129 perms = SHM__DESTROY;
5130 break;
5131 default:
5132 return 0;
5133 }
5134
Stephen Smalley6af963f2005-05-01 08:58:39 -07005135 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 return err;
5137}
5138
5139static int selinux_shm_shmat(struct shmid_kernel *shp,
5140 char __user *shmaddr, int shmflg)
5141{
5142 u32 perms;
5143 int rc;
5144
5145 rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
5146 if (rc)
5147 return rc;
5148
5149 if (shmflg & SHM_RDONLY)
5150 perms = SHM__READ;
5151 else
5152 perms = SHM__READ | SHM__WRITE;
5153
Stephen Smalley6af963f2005-05-01 08:58:39 -07005154 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155}
5156
5157/* Semaphore security operations */
5158static int selinux_sem_alloc_security(struct sem_array *sma)
5159{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 struct ipc_security_struct *isec;
5161 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005162 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 int rc;
5164
5165 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5166 if (rc)
5167 return rc;
5168
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 isec = sma->sem_perm.security;
5170
5171 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005172 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173
David Howells275bb412008-11-14 10:39:19 +11005174 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 SEM__CREATE, &ad);
5176 if (rc) {
5177 ipc_free_security(&sma->sem_perm);
5178 return rc;
5179 }
5180 return 0;
5181}
5182
5183static void selinux_sem_free_security(struct sem_array *sma)
5184{
5185 ipc_free_security(&sma->sem_perm);
5186}
5187
5188static int selinux_sem_associate(struct sem_array *sma, int semflg)
5189{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 struct ipc_security_struct *isec;
5191 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005192 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 isec = sma->sem_perm.security;
5195
5196 AVC_AUDIT_DATA_INIT(&ad, IPC);
5197 ad.u.ipc_id = sma->sem_perm.key;
5198
David Howells275bb412008-11-14 10:39:19 +11005199 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 SEM__ASSOCIATE, &ad);
5201}
5202
5203/* Note, at this point, sma is locked down */
5204static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5205{
5206 int err;
5207 u32 perms;
5208
Eric Paris828dfe12008-04-17 13:17:49 -04005209 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 case IPC_INFO:
5211 case SEM_INFO:
5212 /* No specific object, just general system-wide information. */
5213 return task_has_system(current, SYSTEM__IPC_INFO);
5214 case GETPID:
5215 case GETNCNT:
5216 case GETZCNT:
5217 perms = SEM__GETATTR;
5218 break;
5219 case GETVAL:
5220 case GETALL:
5221 perms = SEM__READ;
5222 break;
5223 case SETVAL:
5224 case SETALL:
5225 perms = SEM__WRITE;
5226 break;
5227 case IPC_RMID:
5228 perms = SEM__DESTROY;
5229 break;
5230 case IPC_SET:
5231 perms = SEM__SETATTR;
5232 break;
5233 case IPC_STAT:
5234 case SEM_STAT:
5235 perms = SEM__GETATTR | SEM__ASSOCIATE;
5236 break;
5237 default:
5238 return 0;
5239 }
5240
Stephen Smalley6af963f2005-05-01 08:58:39 -07005241 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 return err;
5243}
5244
5245static int selinux_sem_semop(struct sem_array *sma,
5246 struct sembuf *sops, unsigned nsops, int alter)
5247{
5248 u32 perms;
5249
5250 if (alter)
5251 perms = SEM__READ | SEM__WRITE;
5252 else
5253 perms = SEM__READ;
5254
Stephen Smalley6af963f2005-05-01 08:58:39 -07005255 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256}
5257
5258static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 u32 av = 0;
5261
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 av = 0;
5263 if (flag & S_IRUGO)
5264 av |= IPC__UNIX_READ;
5265 if (flag & S_IWUGO)
5266 av |= IPC__UNIX_WRITE;
5267
5268 if (av == 0)
5269 return 0;
5270
Stephen Smalley6af963f2005-05-01 08:58:39 -07005271 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272}
5273
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005274static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5275{
5276 struct ipc_security_struct *isec = ipcp->security;
5277 *secid = isec->sid;
5278}
5279
Eric Paris828dfe12008-04-17 13:17:49 -04005280static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281{
5282 if (inode)
5283 inode_doinit_with_dentry(inode, dentry);
5284}
5285
5286static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005287 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288{
David Howells275bb412008-11-14 10:39:19 +11005289 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005290 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005292 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293
5294 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005295 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 if (error)
5297 return error;
5298 }
5299
David Howells275bb412008-11-14 10:39:19 +11005300 rcu_read_lock();
5301 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
5303 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005304 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005306 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005308 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005310 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005311 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005312 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005313 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005314 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 else
David Howells275bb412008-11-14 10:39:19 +11005316 goto invalid;
5317 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318
5319 if (!sid)
5320 return 0;
5321
Al Viro04ff9702007-03-12 16:17:58 +00005322 error = security_sid_to_context(sid, value, &len);
5323 if (error)
5324 return error;
5325 return len;
David Howells275bb412008-11-14 10:39:19 +11005326
5327invalid:
5328 rcu_read_unlock();
5329 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330}
5331
5332static int selinux_setprocattr(struct task_struct *p,
5333 char *name, void *value, size_t size)
5334{
5335 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005336 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005337 struct cred *new;
5338 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 int error;
5340 char *str = value;
5341
5342 if (current != p) {
5343 /* SELinux only allows a process to change its own
5344 security attributes. */
5345 return -EACCES;
5346 }
5347
5348 /*
5349 * Basic control over ability to set these attributes at all.
5350 * current == p, but we'll pass them separately in case the
5351 * above restriction is ever removed.
5352 */
5353 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005354 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005356 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005357 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005358 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005359 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005360 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005362 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 else
5364 error = -EINVAL;
5365 if (error)
5366 return error;
5367
5368 /* Obtain a SID for the context, if one was specified. */
5369 if (size && str[1] && str[1] != '\n') {
5370 if (str[size-1] == '\n') {
5371 str[size-1] = 0;
5372 size--;
5373 }
5374 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005375 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5376 if (!capable(CAP_MAC_ADMIN))
5377 return error;
5378 error = security_context_to_sid_force(value, size,
5379 &sid);
5380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 if (error)
5382 return error;
5383 }
5384
David Howellsd84f4f92008-11-14 10:39:23 +11005385 new = prepare_creds();
5386 if (!new)
5387 return -ENOMEM;
5388
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 /* Permission checking based on the specified context is
5390 performed during the actual operation (execve,
5391 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005392 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 checks and may_create for the file creation checks. The
5394 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005395 tsec = new->security;
5396 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005398 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005400 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005401 error = may_create_key(sid, p);
5402 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005403 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005404 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005405 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005406 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005407 } else if (!strcmp(name, "current")) {
5408 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005410 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005411
David Howellsd84f4f92008-11-14 10:39:23 +11005412 /* Only allow single threaded processes to change context */
5413 error = -EPERM;
5414 if (!is_single_threaded(p)) {
5415 error = security_bounded_transition(tsec->sid, sid);
5416 if (error)
5417 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419
5420 /* Check permissions for the transition. */
5421 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005422 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005424 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425
5426 /* Check for ptracing, and update the task SID if ok.
5427 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005428 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005430 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005431 if (tracer)
5432 ptsid = task_sid(tracer);
5433 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
David Howellsd84f4f92008-11-14 10:39:23 +11005435 if (tracer) {
5436 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5437 PROCESS__PTRACE, NULL);
5438 if (error)
5439 goto abort_change;
5440 }
5441
5442 tsec->sid = sid;
5443 } else {
5444 error = -EINVAL;
5445 goto abort_change;
5446 }
5447
5448 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005450
5451abort_change:
5452 abort_creds(new);
5453 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454}
5455
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005456static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5457{
5458 return security_sid_to_context(secid, secdata, seclen);
5459}
5460
David Howells7bf570d2008-04-29 20:52:51 +01005461static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005462{
5463 return security_context_to_sid(secdata, seclen, secid);
5464}
5465
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005466static void selinux_release_secctx(char *secdata, u32 seclen)
5467{
Paul Moore088999e2007-08-01 11:12:58 -04005468 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005469}
5470
Michael LeMayd7200242006-06-22 14:47:17 -07005471#ifdef CONFIG_KEYS
5472
David Howellsd84f4f92008-11-14 10:39:23 +11005473static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005474 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005475{
David Howellsd84f4f92008-11-14 10:39:23 +11005476 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005477 struct key_security_struct *ksec;
5478
5479 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5480 if (!ksec)
5481 return -ENOMEM;
5482
David Howellsd84f4f92008-11-14 10:39:23 +11005483 tsec = cred->security;
5484 if (tsec->keycreate_sid)
5485 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005486 else
David Howellsd84f4f92008-11-14 10:39:23 +11005487 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005488
David Howells275bb412008-11-14 10:39:19 +11005489 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005490 return 0;
5491}
5492
5493static void selinux_key_free(struct key *k)
5494{
5495 struct key_security_struct *ksec = k->security;
5496
5497 k->security = NULL;
5498 kfree(ksec);
5499}
5500
5501static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005502 const struct cred *cred,
5503 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005504{
5505 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005506 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005507 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005508
5509 /* if no specific permissions are requested, we skip the
5510 permission check. No serious, additional covert channels
5511 appear to be created. */
5512 if (perm == 0)
5513 return 0;
5514
David Howellsd84f4f92008-11-14 10:39:23 +11005515 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005516
5517 key = key_ref_to_ptr(key_ref);
5518 ksec = key->security;
5519
5520 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005521}
5522
David Howells70a5bb72008-04-29 01:01:26 -07005523static int selinux_key_getsecurity(struct key *key, char **_buffer)
5524{
5525 struct key_security_struct *ksec = key->security;
5526 char *context = NULL;
5527 unsigned len;
5528 int rc;
5529
5530 rc = security_sid_to_context(ksec->sid, &context, &len);
5531 if (!rc)
5532 rc = len;
5533 *_buffer = context;
5534 return rc;
5535}
5536
Michael LeMayd7200242006-06-22 14:47:17 -07005537#endif
5538
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005540 .name = "selinux",
5541
David Howells5cd9c582008-08-14 11:37:28 +01005542 .ptrace_may_access = selinux_ptrace_may_access,
5543 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005545 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 .sysctl = selinux_sysctl,
5547 .capable = selinux_capable,
5548 .quotactl = selinux_quotactl,
5549 .quota_on = selinux_quota_on,
5550 .syslog = selinux_syslog,
5551 .vm_enough_memory = selinux_vm_enough_memory,
5552
5553 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005554 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555
David Howellsa6f76f22008-11-14 10:39:24 +11005556 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005557 .bprm_committing_creds = selinux_bprm_committing_creds,
5558 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 .bprm_secureexec = selinux_bprm_secureexec,
5560
5561 .sb_alloc_security = selinux_sb_alloc_security,
5562 .sb_free_security = selinux_sb_free_security,
5563 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005564 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005565 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 .sb_statfs = selinux_sb_statfs,
5567 .sb_mount = selinux_mount,
5568 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005569 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005570 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005571 .sb_parse_opts_str = selinux_parse_opts_str,
5572
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
5574 .inode_alloc_security = selinux_inode_alloc_security,
5575 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005576 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 .inode_unlink = selinux_inode_unlink,
5580 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 .inode_rmdir = selinux_inode_rmdir,
5583 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 .inode_readlink = selinux_inode_readlink,
5586 .inode_follow_link = selinux_inode_follow_link,
5587 .inode_permission = selinux_inode_permission,
5588 .inode_setattr = selinux_inode_setattr,
5589 .inode_getattr = selinux_inode_getattr,
5590 .inode_setxattr = selinux_inode_setxattr,
5591 .inode_post_setxattr = selinux_inode_post_setxattr,
5592 .inode_getxattr = selinux_inode_getxattr,
5593 .inode_listxattr = selinux_inode_listxattr,
5594 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005595 .inode_getsecurity = selinux_inode_getsecurity,
5596 .inode_setsecurity = selinux_inode_setsecurity,
5597 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005598 .inode_need_killpriv = selinux_inode_need_killpriv,
5599 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005600 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
5602 .file_permission = selinux_file_permission,
5603 .file_alloc_security = selinux_file_alloc_security,
5604 .file_free_security = selinux_file_free_security,
5605 .file_ioctl = selinux_file_ioctl,
5606 .file_mmap = selinux_file_mmap,
5607 .file_mprotect = selinux_file_mprotect,
5608 .file_lock = selinux_file_lock,
5609 .file_fcntl = selinux_file_fcntl,
5610 .file_set_fowner = selinux_file_set_fowner,
5611 .file_send_sigiotask = selinux_file_send_sigiotask,
5612 .file_receive = selinux_file_receive,
5613
Eric Paris828dfe12008-04-17 13:17:49 -04005614 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005615
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005617 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005618 .cred_prepare = selinux_cred_prepare,
5619 .cred_commit = selinux_cred_commit,
David Howells3a3b7ce2008-11-14 10:39:28 +11005620 .kernel_act_as = selinux_kernel_act_as,
5621 .kernel_create_files_as = selinux_kernel_create_files_as,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005623 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 .task_setgid = selinux_task_setgid,
5625 .task_setpgid = selinux_task_setpgid,
5626 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005627 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005628 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 .task_setgroups = selinux_task_setgroups,
5630 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005631 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005632 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 .task_setrlimit = selinux_task_setrlimit,
5634 .task_setscheduler = selinux_task_setscheduler,
5635 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005636 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .task_kill = selinux_task_kill,
5638 .task_wait = selinux_task_wait,
5639 .task_prctl = selinux_task_prctl,
Eric Paris828dfe12008-04-17 13:17:49 -04005640 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641
5642 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005643 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644
5645 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5646 .msg_msg_free_security = selinux_msg_msg_free_security,
5647
5648 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5649 .msg_queue_free_security = selinux_msg_queue_free_security,
5650 .msg_queue_associate = selinux_msg_queue_associate,
5651 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5652 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5653 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5654
5655 .shm_alloc_security = selinux_shm_alloc_security,
5656 .shm_free_security = selinux_shm_free_security,
5657 .shm_associate = selinux_shm_associate,
5658 .shm_shmctl = selinux_shm_shmctl,
5659 .shm_shmat = selinux_shm_shmat,
5660
Eric Paris828dfe12008-04-17 13:17:49 -04005661 .sem_alloc_security = selinux_sem_alloc_security,
5662 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 .sem_associate = selinux_sem_associate,
5664 .sem_semctl = selinux_sem_semctl,
5665 .sem_semop = selinux_sem_semop,
5666
Eric Paris828dfe12008-04-17 13:17:49 -04005667 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668
Eric Paris828dfe12008-04-17 13:17:49 -04005669 .getprocattr = selinux_getprocattr,
5670 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005672 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005673 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005674 .release_secctx = selinux_release_secctx,
5675
Eric Paris828dfe12008-04-17 13:17:49 -04005676 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 .unix_may_send = selinux_socket_unix_may_send,
5678
5679 .socket_create = selinux_socket_create,
5680 .socket_post_create = selinux_socket_post_create,
5681 .socket_bind = selinux_socket_bind,
5682 .socket_connect = selinux_socket_connect,
5683 .socket_listen = selinux_socket_listen,
5684 .socket_accept = selinux_socket_accept,
5685 .socket_sendmsg = selinux_socket_sendmsg,
5686 .socket_recvmsg = selinux_socket_recvmsg,
5687 .socket_getsockname = selinux_socket_getsockname,
5688 .socket_getpeername = selinux_socket_getpeername,
5689 .socket_getsockopt = selinux_socket_getsockopt,
5690 .socket_setsockopt = selinux_socket_setsockopt,
5691 .socket_shutdown = selinux_socket_shutdown,
5692 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005693 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5694 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 .sk_alloc_security = selinux_sk_alloc_security,
5696 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005697 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005698 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005699 .sock_graft = selinux_sock_graft,
5700 .inet_conn_request = selinux_inet_conn_request,
5701 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005702 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005703 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005704
5705#ifdef CONFIG_SECURITY_NETWORK_XFRM
5706 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5707 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5708 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005709 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005710 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5711 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005712 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005713 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005714 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005715 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005717
5718#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005719 .key_alloc = selinux_key_alloc,
5720 .key_free = selinux_key_free,
5721 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005722 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005723#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005724
5725#ifdef CONFIG_AUDIT
5726 .audit_rule_init = selinux_audit_rule_init,
5727 .audit_rule_known = selinux_audit_rule_known,
5728 .audit_rule_match = selinux_audit_rule_match,
5729 .audit_rule_free = selinux_audit_rule_free,
5730#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731};
5732
5733static __init int selinux_init(void)
5734{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005735 if (!security_module_enable(&selinux_ops)) {
5736 selinux_enabled = 0;
5737 return 0;
5738 }
5739
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 if (!selinux_enabled) {
5741 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5742 return 0;
5743 }
5744
5745 printk(KERN_INFO "SELinux: Initializing.\n");
5746
5747 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005748 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749
James Morris7cae7e22006-03-22 00:09:22 -08005750 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5751 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005752 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 avc_init();
5754
James Morris6f0f0fd2008-07-10 17:02:07 +09005755 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005757 panic("SELinux: No initial security operations\n");
5758 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 panic("SELinux: Unable to register with kernel.\n");
5760
Eric Paris828dfe12008-04-17 13:17:49 -04005761 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005762 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005763 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005764 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005765
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 return 0;
5767}
5768
5769void selinux_complete_init(void)
5770{
Eric Parisfadcdb42007-02-22 18:11:31 -05005771 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
5773 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005774 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005775 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 spin_lock(&sb_security_lock);
5777next_sb:
5778 if (!list_empty(&superblock_security_head)) {
5779 struct superblock_security_struct *sbsec =
5780 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005781 struct superblock_security_struct,
5782 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005786 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 down_read(&sb->s_umount);
5788 if (sb->s_root)
5789 superblock_doinit(sb, NULL);
5790 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005791 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 spin_lock(&sb_security_lock);
5793 list_del_init(&sbsec->list);
5794 goto next_sb;
5795 }
5796 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005797 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798}
5799
5800/* SELinux requires early initialization in order to label
5801 all processes and objects when they are created. */
5802security_initcall(selinux_init);
5803
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005804#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805
Paul Mooreeffad8d2008-01-29 08:49:27 -05005806static struct nf_hook_ops selinux_ipv4_ops[] = {
5807 {
5808 .hook = selinux_ipv4_postroute,
5809 .owner = THIS_MODULE,
5810 .pf = PF_INET,
5811 .hooknum = NF_INET_POST_ROUTING,
5812 .priority = NF_IP_PRI_SELINUX_LAST,
5813 },
5814 {
5815 .hook = selinux_ipv4_forward,
5816 .owner = THIS_MODULE,
5817 .pf = PF_INET,
5818 .hooknum = NF_INET_FORWARD,
5819 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005820 },
5821 {
5822 .hook = selinux_ipv4_output,
5823 .owner = THIS_MODULE,
5824 .pf = PF_INET,
5825 .hooknum = NF_INET_LOCAL_OUT,
5826 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828};
5829
5830#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5831
Paul Mooreeffad8d2008-01-29 08:49:27 -05005832static struct nf_hook_ops selinux_ipv6_ops[] = {
5833 {
5834 .hook = selinux_ipv6_postroute,
5835 .owner = THIS_MODULE,
5836 .pf = PF_INET6,
5837 .hooknum = NF_INET_POST_ROUTING,
5838 .priority = NF_IP6_PRI_SELINUX_LAST,
5839 },
5840 {
5841 .hook = selinux_ipv6_forward,
5842 .owner = THIS_MODULE,
5843 .pf = PF_INET6,
5844 .hooknum = NF_INET_FORWARD,
5845 .priority = NF_IP6_PRI_SELINUX_FIRST,
5846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847};
5848
5849#endif /* IPV6 */
5850
5851static int __init selinux_nf_ip_init(void)
5852{
5853 int err = 0;
5854
5855 if (!selinux_enabled)
5856 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005857
5858 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5859
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005860 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5861 if (err)
5862 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863
5864#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005865 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5866 if (err)
5867 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005869
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870out:
5871 return err;
5872}
5873
5874__initcall(selinux_nf_ip_init);
5875
5876#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5877static void selinux_nf_ip_exit(void)
5878{
Eric Parisfadcdb42007-02-22 18:11:31 -05005879 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005881 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005883 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884#endif /* IPV6 */
5885}
5886#endif
5887
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005888#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
5890#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5891#define selinux_nf_ip_exit()
5892#endif
5893
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005894#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895
5896#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005897static int selinux_disabled;
5898
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899int selinux_disable(void)
5900{
5901 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902
5903 if (ss_initialized) {
5904 /* Not permitted after initial policy load. */
5905 return -EINVAL;
5906 }
5907
5908 if (selinux_disabled) {
5909 /* Only do this once. */
5910 return -EINVAL;
5911 }
5912
5913 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5914
5915 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005916 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917
5918 /* Reset security_ops to the secondary module, dummy or capability. */
5919 security_ops = secondary_ops;
5920
5921 /* Unregister netfilter hooks. */
5922 selinux_nf_ip_exit();
5923
5924 /* Unregister selinuxfs. */
5925 exit_sel_fs();
5926
5927 return 0;
5928}
5929#endif