blob: d9604794a4d2327eaee052a499b80458f1d4c023 [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. Darwish713a04ae2008-03-01 21:52:30 +02002922static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2923{
2924 struct inode_security_struct *isec = inode->i_security;
2925 *secid = isec->sid;
2926}
2927
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928/* file security operations */
2929
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002930static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
David Howells88e67f32008-11-14 10:39:21 +11002932 const struct cred *cred = current_cred();
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002933 int rc;
Josef Sipek3d5ff522006-12-08 02:37:38 -08002934 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 if (!mask) {
2937 /* No permission to check. Existence test. */
2938 return 0;
2939 }
2940
2941 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2942 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2943 mask |= MAY_APPEND;
2944
David Howells88e67f32008-11-14 10:39:21 +11002945 rc = file_has_perm(cred, file,
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07002946 file_mask_to_av(inode->i_mode, mask));
2947 if (rc)
2948 return rc;
2949
2950 return selinux_netlbl_inode_permission(inode, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951}
2952
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002953static int selinux_file_permission(struct file *file, int mask)
2954{
2955 struct inode *inode = file->f_path.dentry->d_inode;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002956 struct file_security_struct *fsec = file->f_security;
2957 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11002958 u32 sid = current_sid();
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002959
2960 if (!mask) {
2961 /* No permission to check. Existence test. */
2962 return 0;
2963 }
2964
David Howells275bb412008-11-14 10:39:19 +11002965 if (sid == fsec->sid && fsec->isid == isec->sid
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002966 && fsec->pseqno == avc_policy_seqno())
2967 return selinux_netlbl_inode_permission(inode, mask);
2968
2969 return selinux_revalidate_file_permission(file, mask);
2970}
2971
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972static int selinux_file_alloc_security(struct file *file)
2973{
2974 return file_alloc_security(file);
2975}
2976
2977static void selinux_file_free_security(struct file *file)
2978{
2979 file_free_security(file);
2980}
2981
2982static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2983 unsigned long arg)
2984{
David Howells88e67f32008-11-14 10:39:21 +11002985 const struct cred *cred = current_cred();
Stephen Smalley242631c2008-06-05 09:21:28 -04002986 u32 av = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Stephen Smalley242631c2008-06-05 09:21:28 -04002988 if (_IOC_DIR(cmd) & _IOC_WRITE)
2989 av |= FILE__WRITE;
2990 if (_IOC_DIR(cmd) & _IOC_READ)
2991 av |= FILE__READ;
2992 if (!av)
2993 av = FILE__IOCTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
David Howells88e67f32008-11-14 10:39:21 +11002995 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996}
2997
2998static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
2999{
David Howells88e67f32008-11-14 10:39:21 +11003000 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003001 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003#ifndef CONFIG_PPC32
3004 if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
3005 /*
3006 * We are making executable an anonymous mapping or a
3007 * private file mapping that will also be writable.
3008 * This has an additional check.
3009 */
David Howellsd84f4f92008-11-14 10:39:23 +11003010 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003012 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 }
3014#endif
3015
3016 if (file) {
3017 /* read access is always possible with a mapping */
3018 u32 av = FILE__READ;
3019
3020 /* write access only matters if the mapping is shared */
3021 if (shared && (prot & PROT_WRITE))
3022 av |= FILE__WRITE;
3023
3024 if (prot & PROT_EXEC)
3025 av |= FILE__EXECUTE;
3026
David Howells88e67f32008-11-14 10:39:21 +11003027 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 }
David Howellsd84f4f92008-11-14 10:39:23 +11003029
3030error:
3031 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032}
3033
3034static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003035 unsigned long prot, unsigned long flags,
3036 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037{
Eric Parised032182007-06-28 15:55:21 -04003038 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003039 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
Eric Parised032182007-06-28 15:55:21 -04003041 if (addr < mmap_min_addr)
3042 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3043 MEMPROTECT__MMAP_ZERO, NULL);
3044 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 return rc;
3046
3047 if (selinux_checkreqprot)
3048 prot = reqprot;
3049
3050 return file_map_prot_check(file, prot,
3051 (flags & MAP_TYPE) == MAP_SHARED);
3052}
3053
3054static int selinux_file_mprotect(struct vm_area_struct *vma,
3055 unsigned long reqprot,
3056 unsigned long prot)
3057{
David Howells88e67f32008-11-14 10:39:21 +11003058 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
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{
David Howells3b11a1d2008-11-14 10:39:26 +11003215 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216}
3217
David Howellsf1752ee2008-11-14 10:39:17 +11003218/*
3219 * detach and free the LSM part of a set of credentials
3220 */
3221static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222{
David Howellsf1752ee2008-11-14 10:39:17 +11003223 struct task_security_struct *tsec = cred->security;
3224 cred->security = NULL;
3225 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226}
3227
David Howellsd84f4f92008-11-14 10:39:23 +11003228/*
3229 * prepare a new set of credentials for modification
3230 */
3231static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3232 gfp_t gfp)
3233{
3234 const struct task_security_struct *old_tsec;
3235 struct task_security_struct *tsec;
3236
3237 old_tsec = old->security;
3238
3239 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3240 if (!tsec)
3241 return -ENOMEM;
3242
3243 new->security = tsec;
3244 return 0;
3245}
3246
3247/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003248 * set the security data for a kernel service
3249 * - all the creation contexts are set to unlabelled
3250 */
3251static int selinux_kernel_act_as(struct cred *new, u32 secid)
3252{
3253 struct task_security_struct *tsec = new->security;
3254 u32 sid = current_sid();
3255 int ret;
3256
3257 ret = avc_has_perm(sid, secid,
3258 SECCLASS_KERNEL_SERVICE,
3259 KERNEL_SERVICE__USE_AS_OVERRIDE,
3260 NULL);
3261 if (ret == 0) {
3262 tsec->sid = secid;
3263 tsec->create_sid = 0;
3264 tsec->keycreate_sid = 0;
3265 tsec->sockcreate_sid = 0;
3266 }
3267 return ret;
3268}
3269
3270/*
3271 * set the file creation context in a security record to the same as the
3272 * objective context of the specified inode
3273 */
3274static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3275{
3276 struct inode_security_struct *isec = inode->i_security;
3277 struct task_security_struct *tsec = new->security;
3278 u32 sid = current_sid();
3279 int ret;
3280
3281 ret = avc_has_perm(sid, isec->sid,
3282 SECCLASS_KERNEL_SERVICE,
3283 KERNEL_SERVICE__CREATE_FILES_AS,
3284 NULL);
3285
3286 if (ret == 0)
3287 tsec->create_sid = isec->sid;
3288 return 0;
3289}
3290
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
3292{
3293 /* Since setuid only affects the current process, and
3294 since the SELinux controls are not based on the Linux
3295 identity attributes, SELinux does not need to control
3296 this operation. However, SELinux does control the use
3297 of the CAP_SETUID and CAP_SETGID capabilities using the
3298 capable hook. */
3299 return 0;
3300}
3301
David Howellsd84f4f92008-11-14 10:39:23 +11003302static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
3303 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
David Howellsd84f4f92008-11-14 10:39:23 +11003305 return secondary_ops->task_fix_setuid(new, old, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306}
3307
3308static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
3309{
3310 /* See the comment for setuid above. */
3311 return 0;
3312}
3313
3314static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3315{
David Howells3b11a1d2008-11-14 10:39:26 +11003316 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317}
3318
3319static int selinux_task_getpgid(struct task_struct *p)
3320{
David Howells3b11a1d2008-11-14 10:39:26 +11003321 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322}
3323
3324static int selinux_task_getsid(struct task_struct *p)
3325{
David Howells3b11a1d2008-11-14 10:39:26 +11003326 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327}
3328
David Quigleyf9008e42006-06-30 01:55:46 -07003329static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3330{
David Howells275bb412008-11-14 10:39:19 +11003331 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003332}
3333
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334static int selinux_task_setgroups(struct group_info *group_info)
3335{
3336 /* See the comment for setuid above. */
3337 return 0;
3338}
3339
3340static int selinux_task_setnice(struct task_struct *p, int nice)
3341{
3342 int rc;
3343
3344 rc = secondary_ops->task_setnice(p, nice);
3345 if (rc)
3346 return rc;
3347
David Howells3b11a1d2008-11-14 10:39:26 +11003348 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349}
3350
James Morris03e68062006-06-23 02:03:58 -07003351static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3352{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003353 int rc;
3354
3355 rc = secondary_ops->task_setioprio(p, ioprio);
3356 if (rc)
3357 return rc;
3358
David Howells3b11a1d2008-11-14 10:39:26 +11003359 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003360}
3361
David Quigleya1836a42006-06-30 01:55:49 -07003362static int selinux_task_getioprio(struct task_struct *p)
3363{
David Howells3b11a1d2008-11-14 10:39:26 +11003364 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003365}
3366
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
3368{
3369 struct rlimit *old_rlim = current->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
3371 /* Control the ability to change the hard limit (whether
3372 lowering or raising it), so that the hard limit can
3373 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003374 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 if (old_rlim->rlim_max != new_rlim->rlim_max)
David Howells3b11a1d2008-11-14 10:39:26 +11003376 return current_has_perm(current, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
3378 return 0;
3379}
3380
3381static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
3382{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003383 int rc;
3384
3385 rc = secondary_ops->task_setscheduler(p, policy, lp);
3386 if (rc)
3387 return rc;
3388
David Howells3b11a1d2008-11-14 10:39:26 +11003389 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390}
3391
3392static int selinux_task_getscheduler(struct task_struct *p)
3393{
David Howells3b11a1d2008-11-14 10:39:26 +11003394 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395}
3396
David Quigley35601542006-06-23 02:04:01 -07003397static int selinux_task_movememory(struct task_struct *p)
3398{
David Howells3b11a1d2008-11-14 10:39:26 +11003399 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003400}
3401
David Quigleyf9008e42006-06-30 01:55:46 -07003402static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3403 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404{
3405 u32 perm;
3406 int rc;
3407
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 if (!sig)
3409 perm = PROCESS__SIGNULL; /* null signal; existence test */
3410 else
3411 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003412 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003413 rc = avc_has_perm(secid, task_sid(p),
3414 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003415 else
David Howells3b11a1d2008-11-14 10:39:26 +11003416 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003417 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418}
3419
3420static int selinux_task_prctl(int option,
3421 unsigned long arg2,
3422 unsigned long arg3,
3423 unsigned long arg4,
David Howellsd84f4f92008-11-14 10:39:23 +11003424 unsigned long arg5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425{
3426 /* The current prctl operations do not appear to require
3427 any SELinux controls since they merely observe or modify
3428 the state of the current process. */
David Howellsd84f4f92008-11-14 10:39:23 +11003429 return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430}
3431
3432static int selinux_task_wait(struct task_struct *p)
3433{
Eric Paris8a535142007-10-22 16:10:31 -04003434 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435}
3436
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437static void selinux_task_to_inode(struct task_struct *p,
3438 struct inode *inode)
3439{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003441 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
David Howells275bb412008-11-14 10:39:19 +11003443 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445}
3446
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003448static int selinux_parse_skb_ipv4(struct sk_buff *skb,
3449 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450{
3451 int offset, ihlen, ret = -EINVAL;
3452 struct iphdr _iph, *ih;
3453
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003454 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3456 if (ih == NULL)
3457 goto out;
3458
3459 ihlen = ih->ihl * 4;
3460 if (ihlen < sizeof(_iph))
3461 goto out;
3462
3463 ad->u.net.v4info.saddr = ih->saddr;
3464 ad->u.net.v4info.daddr = ih->daddr;
3465 ret = 0;
3466
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003467 if (proto)
3468 *proto = ih->protocol;
3469
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003471 case IPPROTO_TCP: {
3472 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473
Eric Paris828dfe12008-04-17 13:17:49 -04003474 if (ntohs(ih->frag_off) & IP_OFFSET)
3475 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476
3477 offset += ihlen;
3478 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3479 if (th == NULL)
3480 break;
3481
3482 ad->u.net.sport = th->source;
3483 ad->u.net.dport = th->dest;
3484 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
Eric Paris828dfe12008-04-17 13:17:49 -04003487 case IPPROTO_UDP: {
3488 struct udphdr _udph, *uh;
3489
3490 if (ntohs(ih->frag_off) & IP_OFFSET)
3491 break;
3492
3493 offset += ihlen;
3494 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3495 if (uh == NULL)
3496 break;
3497
3498 ad->u.net.sport = uh->source;
3499 ad->u.net.dport = uh->dest;
3500 break;
3501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
James Morris2ee92d42006-11-13 16:09:01 -08003503 case IPPROTO_DCCP: {
3504 struct dccp_hdr _dccph, *dh;
3505
3506 if (ntohs(ih->frag_off) & IP_OFFSET)
3507 break;
3508
3509 offset += ihlen;
3510 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3511 if (dh == NULL)
3512 break;
3513
3514 ad->u.net.sport = dh->dccph_sport;
3515 ad->u.net.dport = dh->dccph_dport;
3516 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003517 }
James Morris2ee92d42006-11-13 16:09:01 -08003518
Eric Paris828dfe12008-04-17 13:17:49 -04003519 default:
3520 break;
3521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522out:
3523 return ret;
3524}
3525
3526#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3527
3528/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003529static int selinux_parse_skb_ipv6(struct sk_buff *skb,
3530 struct avc_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531{
3532 u8 nexthdr;
3533 int ret = -EINVAL, offset;
3534 struct ipv6hdr _ipv6h, *ip6;
3535
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003536 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3538 if (ip6 == NULL)
3539 goto out;
3540
3541 ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
3542 ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
3543 ret = 0;
3544
3545 nexthdr = ip6->nexthdr;
3546 offset += sizeof(_ipv6h);
Herbert Xu0d3d0772005-04-24 20:16:19 -07003547 offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 if (offset < 0)
3549 goto out;
3550
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003551 if (proto)
3552 *proto = nexthdr;
3553
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 switch (nexthdr) {
3555 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003556 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557
3558 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3559 if (th == NULL)
3560 break;
3561
3562 ad->u.net.sport = th->source;
3563 ad->u.net.dport = th->dest;
3564 break;
3565 }
3566
3567 case IPPROTO_UDP: {
3568 struct udphdr _udph, *uh;
3569
3570 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3571 if (uh == NULL)
3572 break;
3573
3574 ad->u.net.sport = uh->source;
3575 ad->u.net.dport = uh->dest;
3576 break;
3577 }
3578
James Morris2ee92d42006-11-13 16:09:01 -08003579 case IPPROTO_DCCP: {
3580 struct dccp_hdr _dccph, *dh;
3581
3582 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3583 if (dh == NULL)
3584 break;
3585
3586 ad->u.net.sport = dh->dccph_sport;
3587 ad->u.net.dport = dh->dccph_dport;
3588 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003589 }
James Morris2ee92d42006-11-13 16:09:01 -08003590
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 /* includes fragments */
3592 default:
3593 break;
3594 }
3595out:
3596 return ret;
3597}
3598
3599#endif /* IPV6 */
3600
3601static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003602 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603{
David Howellscf9481e2008-07-27 21:31:07 +10003604 char *addrp;
3605 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
3607 switch (ad->u.net.family) {
3608 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003609 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003610 if (ret)
3611 goto parse_error;
3612 addrp = (char *)(src ? &ad->u.net.v4info.saddr :
3613 &ad->u.net.v4info.daddr);
3614 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
3616#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3617 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003618 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003619 if (ret)
3620 goto parse_error;
3621 addrp = (char *)(src ? &ad->u.net.v6info.saddr :
3622 &ad->u.net.v6info.daddr);
3623 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624#endif /* IPV6 */
3625 default:
David Howellscf9481e2008-07-27 21:31:07 +10003626 addrp = NULL;
3627 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 }
3629
David Howellscf9481e2008-07-27 21:31:07 +10003630parse_error:
3631 printk(KERN_WARNING
3632 "SELinux: failure in selinux_parse_skb(),"
3633 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003635
3636okay:
3637 if (_addrp)
3638 *_addrp = addrp;
3639 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640}
3641
Paul Moore4f6a9932007-03-01 14:35:22 -05003642/**
Paul Moore220deb92008-01-29 08:38:23 -05003643 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003644 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003645 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003646 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003647 *
3648 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003649 * Check the various different forms of network peer labeling and determine
3650 * the peer label/SID for the packet; most of the magic actually occurs in
3651 * the security server function security_net_peersid_cmp(). The function
3652 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3653 * or -EACCES if @sid is invalid due to inconsistencies with the different
3654 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003655 *
3656 */
Paul Moore220deb92008-01-29 08:38:23 -05003657static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003658{
Paul Moore71f1cb02008-01-29 08:51:16 -05003659 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003660 u32 xfrm_sid;
3661 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003662 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003663
3664 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003665 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003666
Paul Moore71f1cb02008-01-29 08:51:16 -05003667 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3668 if (unlikely(err)) {
3669 printk(KERN_WARNING
3670 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3671 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003672 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003673 }
Paul Moore220deb92008-01-29 08:38:23 -05003674
3675 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003676}
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678/* socket security operations */
3679static int socket_has_perm(struct task_struct *task, struct socket *sock,
3680 u32 perms)
3681{
3682 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11003684 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 int err = 0;
3686
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 isec = SOCK_INODE(sock)->i_security;
3688
3689 if (isec->sid == SECINITSID_KERNEL)
3690 goto out;
David Howells275bb412008-11-14 10:39:19 +11003691 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
Eric Paris828dfe12008-04-17 13:17:49 -04003693 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 ad.u.net.sk = sock->sk;
David Howells275bb412008-11-14 10:39:19 +11003695 err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
3697out:
3698 return err;
3699}
3700
3701static int selinux_socket_create(int family, int type,
3702 int protocol, int kern)
3703{
David Howells275bb412008-11-14 10:39:19 +11003704 const struct cred *cred = current_cred();
3705 const struct task_security_struct *tsec = cred->security;
3706 u32 sid, newsid;
3707 u16 secclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710 if (kern)
3711 goto out;
3712
David Howells275bb412008-11-14 10:39:19 +11003713 sid = tsec->sid;
3714 newsid = tsec->sockcreate_sid ?: sid;
3715
3716 secclass = socket_type_to_security_class(family, type, protocol);
3717 err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
3719out:
3720 return err;
3721}
3722
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003723static int selinux_socket_post_create(struct socket *sock, int family,
3724 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725{
David Howells275bb412008-11-14 10:39:19 +11003726 const struct cred *cred = current_cred();
3727 const struct task_security_struct *tsec = cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 struct inode_security_struct *isec;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003729 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003730 u32 sid, newsid;
3731 int err = 0;
3732
3733 sid = tsec->sid;
3734 newsid = tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735
3736 isec = SOCK_INODE(sock)->i_security;
3737
David Howells275bb412008-11-14 10:39:19 +11003738 if (kern)
3739 isec->sid = SECINITSID_KERNEL;
3740 else if (newsid)
3741 isec->sid = newsid;
3742 else
3743 isec->sid = sid;
3744
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 isec->sclass = socket_type_to_security_class(family, type, protocol);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 isec->initialized = 1;
3747
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003748 if (sock->sk) {
3749 sksec = sock->sk->sk_security;
3750 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003751 sksec->sclass = isec->sclass;
Paul Moore9f2ad662006-11-17 17:38:53 -05003752 err = selinux_netlbl_socket_post_create(sock);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003753 }
3754
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003755 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756}
3757
3758/* Range of port numbers used to automatically bind.
3759 Need to determine whether we should perform a name_bind
3760 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
3762static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3763{
3764 u16 family;
3765 int err;
3766
3767 err = socket_has_perm(current, sock, SOCKET__BIND);
3768 if (err)
3769 goto out;
3770
3771 /*
3772 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003773 * Multiple address binding for SCTP is not supported yet: we just
3774 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 */
3776 family = sock->sk->sk_family;
3777 if (family == PF_INET || family == PF_INET6) {
3778 char *addrp;
3779 struct inode_security_struct *isec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 struct avc_audit_data ad;
3781 struct sockaddr_in *addr4 = NULL;
3782 struct sockaddr_in6 *addr6 = NULL;
3783 unsigned short snum;
3784 struct sock *sk = sock->sk;
James Morrise399f982008-06-12 01:39:58 +10003785 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 isec = SOCK_INODE(sock)->i_security;
3788
3789 if (family == PF_INET) {
3790 addr4 = (struct sockaddr_in *)address;
3791 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 addrp = (char *)&addr4->sin_addr.s_addr;
3793 } else {
3794 addr6 = (struct sockaddr_in6 *)address;
3795 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 addrp = (char *)&addr6->sin6_addr.s6_addr;
3797 }
3798
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003799 if (snum) {
3800 int low, high;
3801
3802 inet_get_local_port_range(&low, &high);
3803
3804 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003805 err = sel_netport_sid(sk->sk_protocol,
3806 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003807 if (err)
3808 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003809 AVC_AUDIT_DATA_INIT(&ad, NET);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003810 ad.u.net.sport = htons(snum);
3811 ad.u.net.family = family;
3812 err = avc_has_perm(isec->sid, sid,
3813 isec->sclass,
3814 SOCKET__NAME_BIND, &ad);
3815 if (err)
3816 goto out;
3817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 }
Eric Paris828dfe12008-04-17 13:17:49 -04003819
3820 switch (isec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003821 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 node_perm = TCP_SOCKET__NODE_BIND;
3823 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003824
James Morris13402582005-09-30 14:24:34 -04003825 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 node_perm = UDP_SOCKET__NODE_BIND;
3827 break;
James Morris2ee92d42006-11-13 16:09:01 -08003828
3829 case SECCLASS_DCCP_SOCKET:
3830 node_perm = DCCP_SOCKET__NODE_BIND;
3831 break;
3832
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 default:
3834 node_perm = RAWIP_SOCKET__NODE_BIND;
3835 break;
3836 }
Eric Paris828dfe12008-04-17 13:17:49 -04003837
Paul Moore224dfbd2008-01-29 08:38:13 -05003838 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 if (err)
3840 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003841
3842 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 ad.u.net.sport = htons(snum);
3844 ad.u.net.family = family;
3845
3846 if (family == PF_INET)
3847 ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
3848 else
3849 ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
3850
3851 err = avc_has_perm(isec->sid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04003852 isec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 if (err)
3854 goto out;
3855 }
3856out:
3857 return err;
3858}
3859
3860static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3861{
Paul Moore014ab192008-10-10 10:16:33 -04003862 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 struct inode_security_struct *isec;
3864 int err;
3865
3866 err = socket_has_perm(current, sock, SOCKET__CONNECT);
3867 if (err)
3868 return err;
3869
3870 /*
James Morris2ee92d42006-11-13 16:09:01 -08003871 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 */
3873 isec = SOCK_INODE(sock)->i_security;
James Morris2ee92d42006-11-13 16:09:01 -08003874 if (isec->sclass == SECCLASS_TCP_SOCKET ||
3875 isec->sclass == SECCLASS_DCCP_SOCKET) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 struct avc_audit_data ad;
3877 struct sockaddr_in *addr4 = NULL;
3878 struct sockaddr_in6 *addr6 = NULL;
3879 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003880 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881
3882 if (sk->sk_family == PF_INET) {
3883 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003884 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 return -EINVAL;
3886 snum = ntohs(addr4->sin_port);
3887 } else {
3888 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003889 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 return -EINVAL;
3891 snum = ntohs(addr6->sin6_port);
3892 }
3893
Paul Moore3e112172008-04-10 10:48:14 -04003894 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 if (err)
3896 goto out;
3897
James Morris2ee92d42006-11-13 16:09:01 -08003898 perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
3899 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3900
Eric Paris828dfe12008-04-17 13:17:49 -04003901 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 ad.u.net.dport = htons(snum);
3903 ad.u.net.family = sk->sk_family;
James Morris2ee92d42006-11-13 16:09:01 -08003904 err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 if (err)
3906 goto out;
3907 }
3908
Paul Moore014ab192008-10-10 10:16:33 -04003909 err = selinux_netlbl_socket_connect(sk, address);
3910
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911out:
3912 return err;
3913}
3914
3915static int selinux_socket_listen(struct socket *sock, int backlog)
3916{
3917 return socket_has_perm(current, sock, SOCKET__LISTEN);
3918}
3919
3920static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3921{
3922 int err;
3923 struct inode_security_struct *isec;
3924 struct inode_security_struct *newisec;
3925
3926 err = socket_has_perm(current, sock, SOCKET__ACCEPT);
3927 if (err)
3928 return err;
3929
3930 newisec = SOCK_INODE(newsock)->i_security;
3931
3932 isec = SOCK_INODE(sock)->i_security;
3933 newisec->sclass = isec->sclass;
3934 newisec->sid = isec->sid;
3935 newisec->initialized = 1;
3936
3937 return 0;
3938}
3939
3940static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003941 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942{
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003943 int rc;
3944
3945 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3946 if (rc)
3947 return rc;
3948
3949 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950}
3951
3952static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3953 int size, int flags)
3954{
3955 return socket_has_perm(current, sock, SOCKET__READ);
3956}
3957
3958static int selinux_socket_getsockname(struct socket *sock)
3959{
3960 return socket_has_perm(current, sock, SOCKET__GETATTR);
3961}
3962
3963static int selinux_socket_getpeername(struct socket *sock)
3964{
3965 return socket_has_perm(current, sock, SOCKET__GETATTR);
3966}
3967
Eric Paris828dfe12008-04-17 13:17:49 -04003968static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969{
Paul Mooref8687af2006-10-30 15:22:15 -08003970 int err;
3971
3972 err = socket_has_perm(current, sock, SOCKET__SETOPT);
3973 if (err)
3974 return err;
3975
3976 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977}
3978
3979static int selinux_socket_getsockopt(struct socket *sock, int level,
3980 int optname)
3981{
3982 return socket_has_perm(current, sock, SOCKET__GETOPT);
3983}
3984
3985static int selinux_socket_shutdown(struct socket *sock, int how)
3986{
3987 return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
3988}
3989
3990static int selinux_socket_unix_stream_connect(struct socket *sock,
3991 struct socket *other,
3992 struct sock *newsk)
3993{
3994 struct sk_security_struct *ssec;
3995 struct inode_security_struct *isec;
3996 struct inode_security_struct *other_isec;
3997 struct avc_audit_data ad;
3998 int err;
3999
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 isec = SOCK_INODE(sock)->i_security;
4001 other_isec = SOCK_INODE(other)->i_security;
4002
Eric Paris828dfe12008-04-17 13:17:49 -04004003 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 ad.u.net.sk = other->sk;
4005
4006 err = avc_has_perm(isec->sid, other_isec->sid,
4007 isec->sclass,
4008 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4009 if (err)
4010 return err;
4011
4012 /* connecting socket */
4013 ssec = sock->sk->sk_security;
4014 ssec->peer_sid = other_isec->sid;
Eric Paris828dfe12008-04-17 13:17:49 -04004015
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 /* server child socket */
4017 ssec = newsk->sk_security;
4018 ssec->peer_sid = isec->sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004019 err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
4020
4021 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022}
4023
4024static int selinux_socket_unix_may_send(struct socket *sock,
4025 struct socket *other)
4026{
4027 struct inode_security_struct *isec;
4028 struct inode_security_struct *other_isec;
4029 struct avc_audit_data ad;
4030 int err;
4031
4032 isec = SOCK_INODE(sock)->i_security;
4033 other_isec = SOCK_INODE(other)->i_security;
4034
Eric Paris828dfe12008-04-17 13:17:49 -04004035 AVC_AUDIT_DATA_INIT(&ad, NET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 ad.u.net.sk = other->sk;
4037
4038 err = avc_has_perm(isec->sid, other_isec->sid,
4039 isec->sclass, SOCKET__SENDTO, &ad);
4040 if (err)
4041 return err;
4042
4043 return 0;
4044}
4045
Paul Mooreeffad8d2008-01-29 08:49:27 -05004046static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4047 u32 peer_sid,
4048 struct avc_audit_data *ad)
4049{
4050 int err;
4051 u32 if_sid;
4052 u32 node_sid;
4053
4054 err = sel_netif_sid(ifindex, &if_sid);
4055 if (err)
4056 return err;
4057 err = avc_has_perm(peer_sid, if_sid,
4058 SECCLASS_NETIF, NETIF__INGRESS, ad);
4059 if (err)
4060 return err;
4061
4062 err = sel_netnode_sid(addrp, family, &node_sid);
4063 if (err)
4064 return err;
4065 return avc_has_perm(peer_sid, node_sid,
4066 SECCLASS_NODE, NODE__RECVFROM, ad);
4067}
4068
Paul Moore220deb92008-01-29 08:38:23 -05004069static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
4070 struct sk_buff *skb,
4071 struct avc_audit_data *ad,
4072 u16 family,
4073 char *addrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074{
Paul Moore220deb92008-01-29 08:38:23 -05004075 int err;
4076 struct sk_security_struct *sksec = sk->sk_security;
4077 u16 sk_class;
4078 u32 netif_perm, node_perm, recv_perm;
4079 u32 port_sid, node_sid, if_sid, sk_sid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004080
Paul Moore220deb92008-01-29 08:38:23 -05004081 sk_sid = sksec->sid;
4082 sk_class = sksec->sclass;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083
Paul Moore220deb92008-01-29 08:38:23 -05004084 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 case SECCLASS_UDP_SOCKET:
4086 netif_perm = NETIF__UDP_RECV;
4087 node_perm = NODE__UDP_RECV;
4088 recv_perm = UDP_SOCKET__RECV_MSG;
4089 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 case SECCLASS_TCP_SOCKET:
4091 netif_perm = NETIF__TCP_RECV;
4092 node_perm = NODE__TCP_RECV;
4093 recv_perm = TCP_SOCKET__RECV_MSG;
4094 break;
James Morris2ee92d42006-11-13 16:09:01 -08004095 case SECCLASS_DCCP_SOCKET:
4096 netif_perm = NETIF__DCCP_RECV;
4097 node_perm = NODE__DCCP_RECV;
4098 recv_perm = DCCP_SOCKET__RECV_MSG;
4099 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 default:
4101 netif_perm = NETIF__RAWIP_RECV;
4102 node_perm = NODE__RAWIP_RECV;
Paul Moore220deb92008-01-29 08:38:23 -05004103 recv_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 break;
4105 }
4106
Paul Moore220deb92008-01-29 08:38:23 -05004107 err = sel_netif_sid(skb->iif, &if_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004109 return err;
4110 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4111 if (err)
4112 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004113
Paul Moore224dfbd2008-01-29 08:38:13 -05004114 err = sel_netnode_sid(addrp, family, &node_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004116 return err;
4117 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004119 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
Paul Moore220deb92008-01-29 08:38:23 -05004121 if (!recv_perm)
4122 return 0;
Paul Moore3e112172008-04-10 10:48:14 -04004123 err = sel_netport_sid(sk->sk_protocol,
4124 ntohs(ad->u.net.sport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004125 if (unlikely(err)) {
4126 printk(KERN_WARNING
4127 "SELinux: failure in"
4128 " selinux_sock_rcv_skb_iptables_compat(),"
4129 " network port label not found\n");
Paul Moore220deb92008-01-29 08:38:23 -05004130 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004131 }
Paul Moore220deb92008-01-29 08:38:23 -05004132 return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
4133}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
Paul Moore220deb92008-01-29 08:38:23 -05004135static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004136 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004137{
Paul Moore277d3422008-12-31 12:54:11 -05004138 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004139 struct sk_security_struct *sksec = sk->sk_security;
4140 u32 peer_sid;
4141 u32 sk_sid = sksec->sid;
Paul Moored8395c82008-10-10 10:16:30 -04004142 struct avc_audit_data ad;
4143 char *addrp;
4144
4145 AVC_AUDIT_DATA_INIT(&ad, NET);
4146 ad.u.net.netif = skb->iif;
4147 ad.u.net.family = family;
4148 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4149 if (err)
4150 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004151
4152 if (selinux_compat_net)
Paul Moored8395c82008-10-10 10:16:30 -04004153 err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
Paul Moore220deb92008-01-29 08:38:23 -05004154 family, addrp);
Paul Moore277d3422008-12-31 12:54:11 -05004155 else if (selinux_secmark_enabled())
Paul Moore220deb92008-01-29 08:38:23 -05004156 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004157 PACKET__RECV, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004158 if (err)
4159 return err;
4160
4161 if (selinux_policycap_netpeer) {
4162 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004164 return err;
4165 err = avc_has_perm(sk_sid, peer_sid,
Paul Moored8395c82008-10-10 10:16:30 -04004166 SECCLASS_PEER, PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004167 if (err)
4168 selinux_netlbl_err(skb, err, 0);
Paul Moore220deb92008-01-29 08:38:23 -05004169 } else {
Paul Moored8395c82008-10-10 10:16:30 -04004170 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
Paul Moore220deb92008-01-29 08:38:23 -05004171 if (err)
4172 return err;
Paul Moored8395c82008-10-10 10:16:30 -04004173 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004175
James Morris4e5ab4c2006-06-09 00:33:33 -07004176 return err;
4177}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004178
James Morris4e5ab4c2006-06-09 00:33:33 -07004179static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4180{
Paul Moore220deb92008-01-29 08:38:23 -05004181 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004182 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004183 u16 family = sk->sk_family;
4184 u32 sk_sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004185 struct avc_audit_data ad;
4186 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004187 u8 secmark_active;
4188 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004189
James Morris4e5ab4c2006-06-09 00:33:33 -07004190 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004191 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004192
4193 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004194 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004195 family = PF_INET;
4196
Paul Moored8395c82008-10-10 10:16:30 -04004197 /* If any sort of compatibility mode is enabled then handoff processing
4198 * to the selinux_sock_rcv_skb_compat() function to deal with the
4199 * special handling. We do this in an attempt to keep this function
4200 * as fast and as clean as possible. */
4201 if (selinux_compat_net || !selinux_policycap_netpeer)
4202 return selinux_sock_rcv_skb_compat(sk, skb, family);
4203
4204 secmark_active = selinux_secmark_enabled();
4205 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4206 if (!secmark_active && !peerlbl_active)
4207 return 0;
4208
James Morris4e5ab4c2006-06-09 00:33:33 -07004209 AVC_AUDIT_DATA_INIT(&ad, NET);
Paul Mooreda5645a2008-01-29 08:38:10 -05004210 ad.u.net.netif = skb->iif;
James Morris4e5ab4c2006-06-09 00:33:33 -07004211 ad.u.net.family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004212 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004213 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004214 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004215
Paul Moored8395c82008-10-10 10:16:30 -04004216 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004217 u32 peer_sid;
4218
4219 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4220 if (err)
4221 return err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004222 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
4223 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004224 if (err) {
4225 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004226 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004227 }
Paul Moored621d352008-01-29 08:43:36 -05004228 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4229 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004230 if (err)
4231 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004232 }
4233
Paul Moored8395c82008-10-10 10:16:30 -04004234 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004235 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4236 PACKET__RECV, &ad);
4237 if (err)
4238 return err;
4239 }
4240
Paul Moored621d352008-01-29 08:43:36 -05004241 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242}
4243
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004244static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4245 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246{
4247 int err = 0;
4248 char *scontext;
4249 u32 scontext_len;
4250 struct sk_security_struct *ssec;
4251 struct inode_security_struct *isec;
Paul Moore3de4bab2006-11-17 17:38:54 -05004252 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253
4254 isec = SOCK_INODE(sock)->i_security;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004255
Paul Moore3de4bab2006-11-17 17:38:54 -05004256 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4257 isec->sclass == SECCLASS_TCP_SOCKET) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004258 ssec = sock->sk->sk_security;
4259 peer_sid = ssec->peer_sid;
4260 }
Paul Moore3de4bab2006-11-17 17:38:54 -05004261 if (peer_sid == SECSID_NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 err = -ENOPROTOOPT;
4263 goto out;
4264 }
4265
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004266 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
4267
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 if (err)
4269 goto out;
4270
4271 if (scontext_len > len) {
4272 err = -ERANGE;
4273 goto out_len;
4274 }
4275
4276 if (copy_to_user(optval, scontext, scontext_len))
4277 err = -EFAULT;
4278
4279out_len:
4280 if (put_user(scontext_len, optlen))
4281 err = -EFAULT;
4282
4283 kfree(scontext);
Eric Paris828dfe12008-04-17 13:17:49 -04004284out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 return err;
4286}
4287
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004288static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004289{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004290 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004291 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004292
Paul Mooreaa862902008-10-10 10:16:29 -04004293 if (skb && skb->protocol == htons(ETH_P_IP))
4294 family = PF_INET;
4295 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4296 family = PF_INET6;
4297 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004298 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004299 else
4300 goto out;
4301
4302 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02004303 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004304 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004305 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004306
Paul Moore75e22912008-01-29 08:38:04 -05004307out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004308 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004309 if (peer_secid == SECSID_NULL)
4310 return -EINVAL;
4311 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004312}
4313
Al Viro7d877f32005-10-21 03:20:43 -04004314static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315{
4316 return sk_alloc_security(sk, family, priority);
4317}
4318
4319static void selinux_sk_free_security(struct sock *sk)
4320{
4321 sk_free_security(sk);
4322}
4323
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004324static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4325{
4326 struct sk_security_struct *ssec = sk->sk_security;
4327 struct sk_security_struct *newssec = newsk->sk_security;
4328
4329 newssec->sid = ssec->sid;
4330 newssec->peer_sid = ssec->peer_sid;
Paul Moore220deb92008-01-29 08:38:23 -05004331 newssec->sclass = ssec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004332
Paul Mooref74af6e2008-02-25 11:40:33 -05004333 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004334}
4335
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004336static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004337{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004338 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004339 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004340 else {
4341 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004342
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004343 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004344 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004345}
4346
Eric Paris828dfe12008-04-17 13:17:49 -04004347static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004348{
4349 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4350 struct sk_security_struct *sksec = sk->sk_security;
4351
David Woodhouse2148ccc2006-09-29 15:50:25 -07004352 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4353 sk->sk_family == PF_UNIX)
4354 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004355 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004356}
4357
Adrian Bunk9a673e52006-08-15 00:03:53 -07004358static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4359 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004360{
4361 struct sk_security_struct *sksec = sk->sk_security;
4362 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004363 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004364 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004365 u32 peersid;
4366
Paul Mooreaa862902008-10-10 10:16:29 -04004367 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4368 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4369 family = PF_INET;
4370
4371 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004372 if (err)
4373 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004374 if (peersid == SECSID_NULL) {
4375 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004376 req->peer_secid = SECSID_NULL;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004377 return 0;
4378 }
4379
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004380 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4381 if (err)
4382 return err;
4383
4384 req->secid = newsid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004385 req->peer_secid = peersid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004386 return 0;
4387}
4388
Adrian Bunk9a673e52006-08-15 00:03:53 -07004389static void selinux_inet_csk_clone(struct sock *newsk,
4390 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004391{
4392 struct sk_security_struct *newsksec = newsk->sk_security;
4393
4394 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004395 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004396 /* NOTE: Ideally, we should also get the isec->sid for the
4397 new socket in sync, but we don't have the isec available yet.
4398 So we will wait until sock_graft to do it, by which
4399 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004400
Paul Moore9f2ad662006-11-17 17:38:53 -05004401 /* We don't need to take any sort of lock here as we are the only
4402 * thread with access to newsksec */
4403 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004404}
4405
Paul Moore014ab192008-10-10 10:16:33 -04004406static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004407{
Paul Mooreaa862902008-10-10 10:16:29 -04004408 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004409 struct sk_security_struct *sksec = sk->sk_security;
4410
Paul Mooreaa862902008-10-10 10:16:29 -04004411 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4412 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4413 family = PF_INET;
4414
4415 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Paul Moore014ab192008-10-10 10:16:33 -04004416
4417 selinux_netlbl_inet_conn_established(sk, family);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004418}
4419
Adrian Bunk9a673e52006-08-15 00:03:53 -07004420static void selinux_req_classify_flow(const struct request_sock *req,
4421 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004422{
4423 fl->secid = req->secid;
4424}
4425
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4427{
4428 int err = 0;
4429 u32 perm;
4430 struct nlmsghdr *nlh;
4431 struct socket *sock = sk->sk_socket;
4432 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 if (skb->len < NLMSG_SPACE(0)) {
4435 err = -EINVAL;
4436 goto out;
4437 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004438 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004439
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
4441 if (err) {
4442 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004443 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 "SELinux: unrecognized netlink message"
4445 " type=%hu for sclass=%hu\n",
4446 nlh->nlmsg_type, isec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004447 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 err = 0;
4449 }
4450
4451 /* Ignore */
4452 if (err == -ENOENT)
4453 err = 0;
4454 goto out;
4455 }
4456
4457 err = socket_has_perm(current, sock, perm);
4458out:
4459 return err;
4460}
4461
4462#ifdef CONFIG_NETFILTER
4463
Paul Mooreeffad8d2008-01-29 08:49:27 -05004464static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4465 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466{
Paul Mooredfaebe92008-10-10 10:16:31 -04004467 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004468 char *addrp;
4469 u32 peer_sid;
4470 struct avc_audit_data ad;
4471 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004472 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004473 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004474
Paul Mooreeffad8d2008-01-29 08:49:27 -05004475 if (!selinux_policycap_netpeer)
4476 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004477
Paul Mooreeffad8d2008-01-29 08:49:27 -05004478 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004479 netlbl_active = netlbl_enabled();
4480 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004481 if (!secmark_active && !peerlbl_active)
4482 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004483
Paul Moored8395c82008-10-10 10:16:30 -04004484 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4485 return NF_DROP;
4486
Paul Mooreeffad8d2008-01-29 08:49:27 -05004487 AVC_AUDIT_DATA_INIT(&ad, NET);
4488 ad.u.net.netif = ifindex;
4489 ad.u.net.family = family;
4490 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4491 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492
Paul Mooredfaebe92008-10-10 10:16:31 -04004493 if (peerlbl_active) {
4494 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4495 peer_sid, &ad);
4496 if (err) {
4497 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004498 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004499 }
4500 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004501
4502 if (secmark_active)
4503 if (avc_has_perm(peer_sid, skb->secmark,
4504 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4505 return NF_DROP;
4506
Paul Moore948bf852008-10-10 10:16:32 -04004507 if (netlbl_active)
4508 /* we do this in the FORWARD path and not the POST_ROUTING
4509 * path because we want to make sure we apply the necessary
4510 * labeling before IPsec is applied so we can leverage AH
4511 * protection */
4512 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4513 return NF_DROP;
4514
Paul Mooreeffad8d2008-01-29 08:49:27 -05004515 return NF_ACCEPT;
4516}
4517
4518static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4519 struct sk_buff *skb,
4520 const struct net_device *in,
4521 const struct net_device *out,
4522 int (*okfn)(struct sk_buff *))
4523{
4524 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4525}
4526
4527#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4528static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4529 struct sk_buff *skb,
4530 const struct net_device *in,
4531 const struct net_device *out,
4532 int (*okfn)(struct sk_buff *))
4533{
4534 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4535}
4536#endif /* IPV6 */
4537
Paul Moore948bf852008-10-10 10:16:32 -04004538static unsigned int selinux_ip_output(struct sk_buff *skb,
4539 u16 family)
4540{
4541 u32 sid;
4542
4543 if (!netlbl_enabled())
4544 return NF_ACCEPT;
4545
4546 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4547 * because we want to make sure we apply the necessary labeling
4548 * before IPsec is applied so we can leverage AH protection */
4549 if (skb->sk) {
4550 struct sk_security_struct *sksec = skb->sk->sk_security;
4551 sid = sksec->sid;
4552 } else
4553 sid = SECINITSID_KERNEL;
4554 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4555 return NF_DROP;
4556
4557 return NF_ACCEPT;
4558}
4559
4560static unsigned int selinux_ipv4_output(unsigned int hooknum,
4561 struct sk_buff *skb,
4562 const struct net_device *in,
4563 const struct net_device *out,
4564 int (*okfn)(struct sk_buff *))
4565{
4566 return selinux_ip_output(skb, PF_INET);
4567}
4568
Paul Mooreeffad8d2008-01-29 08:49:27 -05004569static int selinux_ip_postroute_iptables_compat(struct sock *sk,
4570 int ifindex,
4571 struct avc_audit_data *ad,
4572 u16 family, char *addrp)
4573{
4574 int err;
4575 struct sk_security_struct *sksec = sk->sk_security;
4576 u16 sk_class;
4577 u32 netif_perm, node_perm, send_perm;
4578 u32 port_sid, node_sid, if_sid, sk_sid;
4579
4580 sk_sid = sksec->sid;
4581 sk_class = sksec->sclass;
4582
4583 switch (sk_class) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 case SECCLASS_UDP_SOCKET:
4585 netif_perm = NETIF__UDP_SEND;
4586 node_perm = NODE__UDP_SEND;
4587 send_perm = UDP_SOCKET__SEND_MSG;
4588 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 case SECCLASS_TCP_SOCKET:
4590 netif_perm = NETIF__TCP_SEND;
4591 node_perm = NODE__TCP_SEND;
4592 send_perm = TCP_SOCKET__SEND_MSG;
4593 break;
James Morris2ee92d42006-11-13 16:09:01 -08004594 case SECCLASS_DCCP_SOCKET:
4595 netif_perm = NETIF__DCCP_SEND;
4596 node_perm = NODE__DCCP_SEND;
4597 send_perm = DCCP_SOCKET__SEND_MSG;
4598 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 default:
4600 netif_perm = NETIF__RAWIP_SEND;
4601 node_perm = NODE__RAWIP_SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004602 send_perm = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 break;
4604 }
4605
Paul Mooreeffad8d2008-01-29 08:49:27 -05004606 err = sel_netif_sid(ifindex, &if_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004607 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004608 return err;
4609 err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
4610 return err;
Eric Paris828dfe12008-04-17 13:17:49 -04004611
Paul Moore224dfbd2008-01-29 08:38:13 -05004612 err = sel_netnode_sid(addrp, family, &node_sid);
James Morris4e5ab4c2006-06-09 00:33:33 -07004613 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004614 return err;
4615 err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004616 if (err)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004617 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
Paul Mooreeffad8d2008-01-29 08:49:27 -05004619 if (send_perm != 0)
4620 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621
Paul Moore3e112172008-04-10 10:48:14 -04004622 err = sel_netport_sid(sk->sk_protocol,
4623 ntohs(ad->u.net.dport), &port_sid);
Paul Moore71f1cb02008-01-29 08:51:16 -05004624 if (unlikely(err)) {
4625 printk(KERN_WARNING
4626 "SELinux: failure in"
4627 " selinux_ip_postroute_iptables_compat(),"
4628 " network port label not found\n");
Paul Mooreeffad8d2008-01-29 08:49:27 -05004629 return err;
Paul Moore71f1cb02008-01-29 08:51:16 -05004630 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004631 return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
James Morris4e5ab4c2006-06-09 00:33:33 -07004632}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633
Paul Mooreeffad8d2008-01-29 08:49:27 -05004634static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4635 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004636 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004637{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004638 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004639 struct sk_security_struct *sksec;
Paul Moored8395c82008-10-10 10:16:30 -04004640 struct avc_audit_data ad;
4641 char *addrp;
4642 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004643
Paul Mooreeffad8d2008-01-29 08:49:27 -05004644 if (sk == NULL)
4645 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004646 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004647
Paul Moored8395c82008-10-10 10:16:30 -04004648 AVC_AUDIT_DATA_INIT(&ad, NET);
4649 ad.u.net.netif = ifindex;
4650 ad.u.net.family = family;
4651 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4652 return NF_DROP;
4653
Paul Mooreeffad8d2008-01-29 08:49:27 -05004654 if (selinux_compat_net) {
4655 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004656 &ad, family, addrp))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004657 return NF_DROP;
Paul Moore277d3422008-12-31 12:54:11 -05004658 } else if (selinux_secmark_enabled()) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004659 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004660 SECCLASS_PACKET, PACKET__SEND, &ad))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004661 return NF_DROP;
4662 }
James Morris4e5ab4c2006-06-09 00:33:33 -07004663
Paul Mooreeffad8d2008-01-29 08:49:27 -05004664 if (selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004665 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
Paul Mooreeffad8d2008-01-29 08:49:27 -05004666 return NF_DROP;
James Morris4e5ab4c2006-06-09 00:33:33 -07004667
Paul Mooreeffad8d2008-01-29 08:49:27 -05004668 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669}
4670
Paul Mooreeffad8d2008-01-29 08:49:27 -05004671static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4672 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004674 u32 secmark_perm;
4675 u32 peer_sid;
4676 struct sock *sk;
4677 struct avc_audit_data ad;
4678 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004679 u8 secmark_active;
4680 u8 peerlbl_active;
4681
Paul Mooreeffad8d2008-01-29 08:49:27 -05004682 /* If any sort of compatibility mode is enabled then handoff processing
4683 * to the selinux_ip_postroute_compat() function to deal with the
4684 * special handling. We do this in an attempt to keep this function
4685 * as fast and as clean as possible. */
4686 if (selinux_compat_net || !selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004687 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004688#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004689 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4690 * packet transformation so allow the packet to pass without any checks
4691 * since we'll have another chance to perform access control checks
4692 * when the packet is on it's final way out.
4693 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4694 * is NULL, in this case go ahead and apply access control. */
4695 if (skb->dst != NULL && skb->dst->xfrm != NULL)
4696 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004697#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004698 secmark_active = selinux_secmark_enabled();
4699 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4700 if (!secmark_active && !peerlbl_active)
4701 return NF_ACCEPT;
4702
Paul Moored8395c82008-10-10 10:16:30 -04004703 /* if the packet is being forwarded then get the peer label from the
4704 * packet itself; otherwise check to see if it is from a local
4705 * application or the kernel, if from an application get the peer label
4706 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004707 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004708 if (sk == NULL) {
4709 switch (family) {
4710 case PF_INET:
4711 if (IPCB(skb)->flags & IPSKB_FORWARDED)
4712 secmark_perm = PACKET__FORWARD_OUT;
4713 else
4714 secmark_perm = PACKET__SEND;
4715 break;
4716 case PF_INET6:
4717 if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
4718 secmark_perm = PACKET__FORWARD_OUT;
4719 else
4720 secmark_perm = PACKET__SEND;
4721 break;
4722 default:
4723 return NF_DROP;
4724 }
4725 if (secmark_perm == PACKET__FORWARD_OUT) {
4726 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
4727 return NF_DROP;
4728 } else
4729 peer_sid = SECINITSID_KERNEL;
4730 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004731 struct sk_security_struct *sksec = sk->sk_security;
4732 peer_sid = sksec->sid;
4733 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004734 }
4735
Paul Moored8395c82008-10-10 10:16:30 -04004736 AVC_AUDIT_DATA_INIT(&ad, NET);
4737 ad.u.net.netif = ifindex;
4738 ad.u.net.family = family;
4739 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
4740 return NF_DROP;
4741
Paul Mooreeffad8d2008-01-29 08:49:27 -05004742 if (secmark_active)
4743 if (avc_has_perm(peer_sid, skb->secmark,
4744 SECCLASS_PACKET, secmark_perm, &ad))
4745 return NF_DROP;
4746
4747 if (peerlbl_active) {
4748 u32 if_sid;
4749 u32 node_sid;
4750
4751 if (sel_netif_sid(ifindex, &if_sid))
4752 return NF_DROP;
4753 if (avc_has_perm(peer_sid, if_sid,
4754 SECCLASS_NETIF, NETIF__EGRESS, &ad))
4755 return NF_DROP;
4756
4757 if (sel_netnode_sid(addrp, family, &node_sid))
4758 return NF_DROP;
4759 if (avc_has_perm(peer_sid, node_sid,
4760 SECCLASS_NODE, NODE__SENDTO, &ad))
4761 return NF_DROP;
4762 }
4763
4764 return NF_ACCEPT;
4765}
4766
4767static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4768 struct sk_buff *skb,
4769 const struct net_device *in,
4770 const struct net_device *out,
4771 int (*okfn)(struct sk_buff *))
4772{
4773 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774}
4775
4776#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004777static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4778 struct sk_buff *skb,
4779 const struct net_device *in,
4780 const struct net_device *out,
4781 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004783 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785#endif /* IPV6 */
4786
4787#endif /* CONFIG_NETFILTER */
4788
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4790{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 int err;
4792
4793 err = secondary_ops->netlink_send(sk, skb);
4794 if (err)
4795 return err;
4796
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
4798 err = selinux_nlmsg_perm(sk, skb);
4799
4800 return err;
4801}
4802
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004803static int selinux_netlink_recv(struct sk_buff *skb, int capability)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804{
Darrel Goeddelc7bdb542006-06-27 13:26:11 -07004805 int err;
4806 struct avc_audit_data ad;
4807
4808 err = secondary_ops->netlink_recv(skb, capability);
4809 if (err)
4810 return err;
4811
4812 AVC_AUDIT_DATA_INIT(&ad, CAP);
4813 ad.u.cap = capability;
4814
4815 return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
Eric Paris828dfe12008-04-17 13:17:49 -04004816 SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817}
4818
4819static int ipc_alloc_security(struct task_struct *task,
4820 struct kern_ipc_perm *perm,
4821 u16 sclass)
4822{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004824 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825
James Morris89d155e2005-10-30 14:59:21 -08004826 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 if (!isec)
4828 return -ENOMEM;
4829
David Howells275bb412008-11-14 10:39:19 +11004830 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004832 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 perm->security = isec;
4834
4835 return 0;
4836}
4837
4838static void ipc_free_security(struct kern_ipc_perm *perm)
4839{
4840 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 perm->security = NULL;
4842 kfree(isec);
4843}
4844
4845static int msg_msg_alloc_security(struct msg_msg *msg)
4846{
4847 struct msg_security_struct *msec;
4848
James Morris89d155e2005-10-30 14:59:21 -08004849 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 if (!msec)
4851 return -ENOMEM;
4852
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 msec->sid = SECINITSID_UNLABELED;
4854 msg->security = msec;
4855
4856 return 0;
4857}
4858
4859static void msg_msg_free_security(struct msg_msg *msg)
4860{
4861 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862
4863 msg->security = NULL;
4864 kfree(msec);
4865}
4866
4867static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004868 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 struct ipc_security_struct *isec;
4871 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004872 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 isec = ipc_perms->security;
4875
4876 AVC_AUDIT_DATA_INIT(&ad, IPC);
4877 ad.u.ipc_id = ipc_perms->key;
4878
David Howells275bb412008-11-14 10:39:19 +11004879 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880}
4881
4882static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4883{
4884 return msg_msg_alloc_security(msg);
4885}
4886
4887static void selinux_msg_msg_free_security(struct msg_msg *msg)
4888{
4889 msg_msg_free_security(msg);
4890}
4891
4892/* message queue security operations */
4893static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4894{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 struct ipc_security_struct *isec;
4896 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004897 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 int rc;
4899
4900 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4901 if (rc)
4902 return rc;
4903
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 isec = msq->q_perm.security;
4905
4906 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04004907 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908
David Howells275bb412008-11-14 10:39:19 +11004909 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 MSGQ__CREATE, &ad);
4911 if (rc) {
4912 ipc_free_security(&msq->q_perm);
4913 return rc;
4914 }
4915 return 0;
4916}
4917
4918static void selinux_msg_queue_free_security(struct msg_queue *msq)
4919{
4920 ipc_free_security(&msq->q_perm);
4921}
4922
4923static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4924{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 struct ipc_security_struct *isec;
4926 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004927 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 isec = msq->q_perm.security;
4930
4931 AVC_AUDIT_DATA_INIT(&ad, IPC);
4932 ad.u.ipc_id = msq->q_perm.key;
4933
David Howells275bb412008-11-14 10:39:19 +11004934 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 MSGQ__ASSOCIATE, &ad);
4936}
4937
4938static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4939{
4940 int err;
4941 int perms;
4942
Eric Paris828dfe12008-04-17 13:17:49 -04004943 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944 case IPC_INFO:
4945 case MSG_INFO:
4946 /* No specific object, just general system-wide information. */
4947 return task_has_system(current, SYSTEM__IPC_INFO);
4948 case IPC_STAT:
4949 case MSG_STAT:
4950 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4951 break;
4952 case IPC_SET:
4953 perms = MSGQ__SETATTR;
4954 break;
4955 case IPC_RMID:
4956 perms = MSGQ__DESTROY;
4957 break;
4958 default:
4959 return 0;
4960 }
4961
Stephen Smalley6af963f2005-05-01 08:58:39 -07004962 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 return err;
4964}
4965
4966static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4967{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 struct ipc_security_struct *isec;
4969 struct msg_security_struct *msec;
4970 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004971 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 int rc;
4973
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 isec = msq->q_perm.security;
4975 msec = msg->security;
4976
4977 /*
4978 * First time through, need to assign label to the message
4979 */
4980 if (msec->sid == SECINITSID_UNLABELED) {
4981 /*
4982 * Compute new sid based on current process and
4983 * message queue this message will be stored in
4984 */
David Howells275bb412008-11-14 10:39:19 +11004985 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 &msec->sid);
4987 if (rc)
4988 return rc;
4989 }
4990
4991 AVC_AUDIT_DATA_INIT(&ad, IPC);
4992 ad.u.ipc_id = msq->q_perm.key;
4993
4994 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004995 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 MSGQ__WRITE, &ad);
4997 if (!rc)
4998 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11004999 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5000 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 if (!rc)
5002 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005003 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5004 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005
5006 return rc;
5007}
5008
5009static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5010 struct task_struct *target,
5011 long type, int mode)
5012{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 struct ipc_security_struct *isec;
5014 struct msg_security_struct *msec;
5015 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005016 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 int rc;
5018
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 isec = msq->q_perm.security;
5020 msec = msg->security;
5021
5022 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005023 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024
David Howells275bb412008-11-14 10:39:19 +11005025 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 SECCLASS_MSGQ, MSGQ__READ, &ad);
5027 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005028 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 SECCLASS_MSG, MSG__RECEIVE, &ad);
5030 return rc;
5031}
5032
5033/* Shared Memory security operations */
5034static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5035{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 struct ipc_security_struct *isec;
5037 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005038 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 int rc;
5040
5041 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5042 if (rc)
5043 return rc;
5044
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 isec = shp->shm_perm.security;
5046
5047 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005048 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049
David Howells275bb412008-11-14 10:39:19 +11005050 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 SHM__CREATE, &ad);
5052 if (rc) {
5053 ipc_free_security(&shp->shm_perm);
5054 return rc;
5055 }
5056 return 0;
5057}
5058
5059static void selinux_shm_free_security(struct shmid_kernel *shp)
5060{
5061 ipc_free_security(&shp->shm_perm);
5062}
5063
5064static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5065{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 struct ipc_security_struct *isec;
5067 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005068 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 isec = shp->shm_perm.security;
5071
5072 AVC_AUDIT_DATA_INIT(&ad, IPC);
5073 ad.u.ipc_id = shp->shm_perm.key;
5074
David Howells275bb412008-11-14 10:39:19 +11005075 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 SHM__ASSOCIATE, &ad);
5077}
5078
5079/* Note, at this point, shp is locked down */
5080static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5081{
5082 int perms;
5083 int err;
5084
Eric Paris828dfe12008-04-17 13:17:49 -04005085 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 case IPC_INFO:
5087 case SHM_INFO:
5088 /* No specific object, just general system-wide information. */
5089 return task_has_system(current, SYSTEM__IPC_INFO);
5090 case IPC_STAT:
5091 case SHM_STAT:
5092 perms = SHM__GETATTR | SHM__ASSOCIATE;
5093 break;
5094 case IPC_SET:
5095 perms = SHM__SETATTR;
5096 break;
5097 case SHM_LOCK:
5098 case SHM_UNLOCK:
5099 perms = SHM__LOCK;
5100 break;
5101 case IPC_RMID:
5102 perms = SHM__DESTROY;
5103 break;
5104 default:
5105 return 0;
5106 }
5107
Stephen Smalley6af963f2005-05-01 08:58:39 -07005108 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 return err;
5110}
5111
5112static int selinux_shm_shmat(struct shmid_kernel *shp,
5113 char __user *shmaddr, int shmflg)
5114{
5115 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
5117 if (shmflg & SHM_RDONLY)
5118 perms = SHM__READ;
5119 else
5120 perms = SHM__READ | SHM__WRITE;
5121
Stephen Smalley6af963f2005-05-01 08:58:39 -07005122 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123}
5124
5125/* Semaphore security operations */
5126static int selinux_sem_alloc_security(struct sem_array *sma)
5127{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 struct ipc_security_struct *isec;
5129 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005130 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 int rc;
5132
5133 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5134 if (rc)
5135 return rc;
5136
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 isec = sma->sem_perm.security;
5138
5139 AVC_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris828dfe12008-04-17 13:17:49 -04005140 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141
David Howells275bb412008-11-14 10:39:19 +11005142 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 SEM__CREATE, &ad);
5144 if (rc) {
5145 ipc_free_security(&sma->sem_perm);
5146 return rc;
5147 }
5148 return 0;
5149}
5150
5151static void selinux_sem_free_security(struct sem_array *sma)
5152{
5153 ipc_free_security(&sma->sem_perm);
5154}
5155
5156static int selinux_sem_associate(struct sem_array *sma, int semflg)
5157{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 struct ipc_security_struct *isec;
5159 struct avc_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005160 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 isec = sma->sem_perm.security;
5163
5164 AVC_AUDIT_DATA_INIT(&ad, IPC);
5165 ad.u.ipc_id = sma->sem_perm.key;
5166
David Howells275bb412008-11-14 10:39:19 +11005167 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 SEM__ASSOCIATE, &ad);
5169}
5170
5171/* Note, at this point, sma is locked down */
5172static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5173{
5174 int err;
5175 u32 perms;
5176
Eric Paris828dfe12008-04-17 13:17:49 -04005177 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 case IPC_INFO:
5179 case SEM_INFO:
5180 /* No specific object, just general system-wide information. */
5181 return task_has_system(current, SYSTEM__IPC_INFO);
5182 case GETPID:
5183 case GETNCNT:
5184 case GETZCNT:
5185 perms = SEM__GETATTR;
5186 break;
5187 case GETVAL:
5188 case GETALL:
5189 perms = SEM__READ;
5190 break;
5191 case SETVAL:
5192 case SETALL:
5193 perms = SEM__WRITE;
5194 break;
5195 case IPC_RMID:
5196 perms = SEM__DESTROY;
5197 break;
5198 case IPC_SET:
5199 perms = SEM__SETATTR;
5200 break;
5201 case IPC_STAT:
5202 case SEM_STAT:
5203 perms = SEM__GETATTR | SEM__ASSOCIATE;
5204 break;
5205 default:
5206 return 0;
5207 }
5208
Stephen Smalley6af963f2005-05-01 08:58:39 -07005209 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 return err;
5211}
5212
5213static int selinux_sem_semop(struct sem_array *sma,
5214 struct sembuf *sops, unsigned nsops, int alter)
5215{
5216 u32 perms;
5217
5218 if (alter)
5219 perms = SEM__READ | SEM__WRITE;
5220 else
5221 perms = SEM__READ;
5222
Stephen Smalley6af963f2005-05-01 08:58:39 -07005223 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224}
5225
5226static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5227{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 u32 av = 0;
5229
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 av = 0;
5231 if (flag & S_IRUGO)
5232 av |= IPC__UNIX_READ;
5233 if (flag & S_IWUGO)
5234 av |= IPC__UNIX_WRITE;
5235
5236 if (av == 0)
5237 return 0;
5238
Stephen Smalley6af963f2005-05-01 08:58:39 -07005239 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240}
5241
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02005242static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5243{
5244 struct ipc_security_struct *isec = ipcp->security;
5245 *secid = isec->sid;
5246}
5247
Eric Paris828dfe12008-04-17 13:17:49 -04005248static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249{
5250 if (inode)
5251 inode_doinit_with_dentry(inode, dentry);
5252}
5253
5254static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005255 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256{
David Howells275bb412008-11-14 10:39:19 +11005257 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005258 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005260 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261
5262 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005263 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 if (error)
5265 return error;
5266 }
5267
David Howells275bb412008-11-14 10:39:19 +11005268 rcu_read_lock();
5269 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270
5271 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005272 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005274 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005276 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005278 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005279 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005280 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005281 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005282 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 else
David Howells275bb412008-11-14 10:39:19 +11005284 goto invalid;
5285 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
5287 if (!sid)
5288 return 0;
5289
Al Viro04ff9702007-03-12 16:17:58 +00005290 error = security_sid_to_context(sid, value, &len);
5291 if (error)
5292 return error;
5293 return len;
David Howells275bb412008-11-14 10:39:19 +11005294
5295invalid:
5296 rcu_read_unlock();
5297 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298}
5299
5300static int selinux_setprocattr(struct task_struct *p,
5301 char *name, void *value, size_t size)
5302{
5303 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005304 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005305 struct cred *new;
5306 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 int error;
5308 char *str = value;
5309
5310 if (current != p) {
5311 /* SELinux only allows a process to change its own
5312 security attributes. */
5313 return -EACCES;
5314 }
5315
5316 /*
5317 * Basic control over ability to set these attributes at all.
5318 * current == p, but we'll pass them separately in case the
5319 * above restriction is ever removed.
5320 */
5321 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005322 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005324 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005325 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005326 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005327 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005328 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005330 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 else
5332 error = -EINVAL;
5333 if (error)
5334 return error;
5335
5336 /* Obtain a SID for the context, if one was specified. */
5337 if (size && str[1] && str[1] != '\n') {
5338 if (str[size-1] == '\n') {
5339 str[size-1] = 0;
5340 size--;
5341 }
5342 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005343 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5344 if (!capable(CAP_MAC_ADMIN))
5345 return error;
5346 error = security_context_to_sid_force(value, size,
5347 &sid);
5348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 if (error)
5350 return error;
5351 }
5352
David Howellsd84f4f92008-11-14 10:39:23 +11005353 new = prepare_creds();
5354 if (!new)
5355 return -ENOMEM;
5356
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 /* Permission checking based on the specified context is
5358 performed during the actual operation (execve,
5359 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005360 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 checks and may_create for the file creation checks. The
5362 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005363 tsec = new->security;
5364 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005366 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005368 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005369 error = may_create_key(sid, p);
5370 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005371 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005372 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005373 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005374 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005375 } else if (!strcmp(name, "current")) {
5376 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005378 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005379
David Howellsd84f4f92008-11-14 10:39:23 +11005380 /* Only allow single threaded processes to change context */
5381 error = -EPERM;
5382 if (!is_single_threaded(p)) {
5383 error = security_bounded_transition(tsec->sid, sid);
5384 if (error)
5385 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387
5388 /* Check permissions for the transition. */
5389 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005390 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005392 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393
5394 /* Check for ptracing, and update the task SID if ok.
5395 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005396 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 task_lock(p);
Roland McGrath0d094ef2008-07-25 19:45:49 -07005398 tracer = tracehook_tracer_task(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005399 if (tracer)
5400 ptsid = task_sid(tracer);
5401 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
David Howellsd84f4f92008-11-14 10:39:23 +11005403 if (tracer) {
5404 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5405 PROCESS__PTRACE, NULL);
5406 if (error)
5407 goto abort_change;
5408 }
5409
5410 tsec->sid = sid;
5411 } else {
5412 error = -EINVAL;
5413 goto abort_change;
5414 }
5415
5416 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005418
5419abort_change:
5420 abort_creds(new);
5421 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422}
5423
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005424static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5425{
5426 return security_sid_to_context(secid, secdata, seclen);
5427}
5428
David Howells7bf570d2008-04-29 20:52:51 +01005429static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005430{
5431 return security_context_to_sid(secdata, seclen, secid);
5432}
5433
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005434static void selinux_release_secctx(char *secdata, u32 seclen)
5435{
Paul Moore088999e2007-08-01 11:12:58 -04005436 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005437}
5438
Michael LeMayd7200242006-06-22 14:47:17 -07005439#ifdef CONFIG_KEYS
5440
David Howellsd84f4f92008-11-14 10:39:23 +11005441static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005442 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005443{
David Howellsd84f4f92008-11-14 10:39:23 +11005444 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005445 struct key_security_struct *ksec;
5446
5447 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5448 if (!ksec)
5449 return -ENOMEM;
5450
David Howellsd84f4f92008-11-14 10:39:23 +11005451 tsec = cred->security;
5452 if (tsec->keycreate_sid)
5453 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005454 else
David Howellsd84f4f92008-11-14 10:39:23 +11005455 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005456
David Howells275bb412008-11-14 10:39:19 +11005457 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005458 return 0;
5459}
5460
5461static void selinux_key_free(struct key *k)
5462{
5463 struct key_security_struct *ksec = k->security;
5464
5465 k->security = NULL;
5466 kfree(ksec);
5467}
5468
5469static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005470 const struct cred *cred,
5471 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005472{
5473 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005474 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005475 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005476
5477 /* if no specific permissions are requested, we skip the
5478 permission check. No serious, additional covert channels
5479 appear to be created. */
5480 if (perm == 0)
5481 return 0;
5482
David Howellsd84f4f92008-11-14 10:39:23 +11005483 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005484
5485 key = key_ref_to_ptr(key_ref);
5486 ksec = key->security;
5487
5488 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005489}
5490
David Howells70a5bb72008-04-29 01:01:26 -07005491static int selinux_key_getsecurity(struct key *key, char **_buffer)
5492{
5493 struct key_security_struct *ksec = key->security;
5494 char *context = NULL;
5495 unsigned len;
5496 int rc;
5497
5498 rc = security_sid_to_context(ksec->sid, &context, &len);
5499 if (!rc)
5500 rc = len;
5501 *_buffer = context;
5502 return rc;
5503}
5504
Michael LeMayd7200242006-06-22 14:47:17 -07005505#endif
5506
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005508 .name = "selinux",
5509
David Howells5cd9c582008-08-14 11:37:28 +01005510 .ptrace_may_access = selinux_ptrace_may_access,
5511 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005513 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 .sysctl = selinux_sysctl,
5515 .capable = selinux_capable,
5516 .quotactl = selinux_quotactl,
5517 .quota_on = selinux_quota_on,
5518 .syslog = selinux_syslog,
5519 .vm_enough_memory = selinux_vm_enough_memory,
5520
5521 .netlink_send = selinux_netlink_send,
Eric Paris828dfe12008-04-17 13:17:49 -04005522 .netlink_recv = selinux_netlink_recv,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523
David Howellsa6f76f22008-11-14 10:39:24 +11005524 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005525 .bprm_committing_creds = selinux_bprm_committing_creds,
5526 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 .bprm_secureexec = selinux_bprm_secureexec,
5528
5529 .sb_alloc_security = selinux_sb_alloc_security,
5530 .sb_free_security = selinux_sb_free_security,
5531 .sb_copy_data = selinux_sb_copy_data,
Eric Paris828dfe12008-04-17 13:17:49 -04005532 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005533 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 .sb_statfs = selinux_sb_statfs,
5535 .sb_mount = selinux_mount,
5536 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005537 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005538 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005539 .sb_parse_opts_str = selinux_parse_opts_str,
5540
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541
5542 .inode_alloc_security = selinux_inode_alloc_security,
5543 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005544 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 .inode_unlink = selinux_inode_unlink,
5548 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 .inode_rmdir = selinux_inode_rmdir,
5551 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 .inode_readlink = selinux_inode_readlink,
5554 .inode_follow_link = selinux_inode_follow_link,
5555 .inode_permission = selinux_inode_permission,
5556 .inode_setattr = selinux_inode_setattr,
5557 .inode_getattr = selinux_inode_getattr,
5558 .inode_setxattr = selinux_inode_setxattr,
5559 .inode_post_setxattr = selinux_inode_post_setxattr,
5560 .inode_getxattr = selinux_inode_getxattr,
5561 .inode_listxattr = selinux_inode_listxattr,
5562 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005563 .inode_getsecurity = selinux_inode_getsecurity,
5564 .inode_setsecurity = selinux_inode_setsecurity,
5565 .inode_listsecurity = selinux_inode_listsecurity,
Serge E. Hallynb5376772007-10-16 23:31:36 -07005566 .inode_need_killpriv = selinux_inode_need_killpriv,
5567 .inode_killpriv = selinux_inode_killpriv,
Eric Parisf5269712008-05-14 11:27:45 -04005568 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569
5570 .file_permission = selinux_file_permission,
5571 .file_alloc_security = selinux_file_alloc_security,
5572 .file_free_security = selinux_file_free_security,
5573 .file_ioctl = selinux_file_ioctl,
5574 .file_mmap = selinux_file_mmap,
5575 .file_mprotect = selinux_file_mprotect,
5576 .file_lock = selinux_file_lock,
5577 .file_fcntl = selinux_file_fcntl,
5578 .file_set_fowner = selinux_file_set_fowner,
5579 .file_send_sigiotask = selinux_file_send_sigiotask,
5580 .file_receive = selinux_file_receive,
5581
Eric Paris828dfe12008-04-17 13:17:49 -04005582 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005583
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 .task_create = selinux_task_create,
David Howellsf1752ee2008-11-14 10:39:17 +11005585 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005586 .cred_prepare = selinux_cred_prepare,
David Howells3a3b7ce2008-11-14 10:39:28 +11005587 .kernel_act_as = selinux_kernel_act_as,
5588 .kernel_create_files_as = selinux_kernel_create_files_as,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 .task_setuid = selinux_task_setuid,
David Howellsd84f4f92008-11-14 10:39:23 +11005590 .task_fix_setuid = selinux_task_fix_setuid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 .task_setgid = selinux_task_setgid,
5592 .task_setpgid = selinux_task_setpgid,
5593 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005594 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005595 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 .task_setgroups = selinux_task_setgroups,
5597 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005598 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005599 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 .task_setrlimit = selinux_task_setrlimit,
5601 .task_setscheduler = selinux_task_setscheduler,
5602 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005603 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 .task_kill = selinux_task_kill,
5605 .task_wait = selinux_task_wait,
5606 .task_prctl = selinux_task_prctl,
Eric Paris828dfe12008-04-17 13:17:49 -04005607 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608
5609 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005610 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611
5612 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5613 .msg_msg_free_security = selinux_msg_msg_free_security,
5614
5615 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5616 .msg_queue_free_security = selinux_msg_queue_free_security,
5617 .msg_queue_associate = selinux_msg_queue_associate,
5618 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5619 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5620 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5621
5622 .shm_alloc_security = selinux_shm_alloc_security,
5623 .shm_free_security = selinux_shm_free_security,
5624 .shm_associate = selinux_shm_associate,
5625 .shm_shmctl = selinux_shm_shmctl,
5626 .shm_shmat = selinux_shm_shmat,
5627
Eric Paris828dfe12008-04-17 13:17:49 -04005628 .sem_alloc_security = selinux_sem_alloc_security,
5629 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 .sem_associate = selinux_sem_associate,
5631 .sem_semctl = selinux_sem_semctl,
5632 .sem_semop = selinux_sem_semop,
5633
Eric Paris828dfe12008-04-17 13:17:49 -04005634 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Eric Paris828dfe12008-04-17 13:17:49 -04005636 .getprocattr = selinux_getprocattr,
5637 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005639 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005640 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005641 .release_secctx = selinux_release_secctx,
5642
Eric Paris828dfe12008-04-17 13:17:49 -04005643 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 .unix_may_send = selinux_socket_unix_may_send,
5645
5646 .socket_create = selinux_socket_create,
5647 .socket_post_create = selinux_socket_post_create,
5648 .socket_bind = selinux_socket_bind,
5649 .socket_connect = selinux_socket_connect,
5650 .socket_listen = selinux_socket_listen,
5651 .socket_accept = selinux_socket_accept,
5652 .socket_sendmsg = selinux_socket_sendmsg,
5653 .socket_recvmsg = selinux_socket_recvmsg,
5654 .socket_getsockname = selinux_socket_getsockname,
5655 .socket_getpeername = selinux_socket_getpeername,
5656 .socket_getsockopt = selinux_socket_getsockopt,
5657 .socket_setsockopt = selinux_socket_setsockopt,
5658 .socket_shutdown = selinux_socket_shutdown,
5659 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005660 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5661 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 .sk_alloc_security = selinux_sk_alloc_security,
5663 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005664 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005665 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005666 .sock_graft = selinux_sock_graft,
5667 .inet_conn_request = selinux_inet_conn_request,
5668 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005669 .inet_conn_established = selinux_inet_conn_established,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005670 .req_classify_flow = selinux_req_classify_flow,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005671
5672#ifdef CONFIG_SECURITY_NETWORK_XFRM
5673 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5674 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5675 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005676 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005677 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5678 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005679 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005680 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005681 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005682 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005684
5685#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005686 .key_alloc = selinux_key_alloc,
5687 .key_free = selinux_key_free,
5688 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005689 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005690#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005691
5692#ifdef CONFIG_AUDIT
5693 .audit_rule_init = selinux_audit_rule_init,
5694 .audit_rule_known = selinux_audit_rule_known,
5695 .audit_rule_match = selinux_audit_rule_match,
5696 .audit_rule_free = selinux_audit_rule_free,
5697#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698};
5699
5700static __init int selinux_init(void)
5701{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005702 if (!security_module_enable(&selinux_ops)) {
5703 selinux_enabled = 0;
5704 return 0;
5705 }
5706
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 if (!selinux_enabled) {
5708 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5709 return 0;
5710 }
5711
5712 printk(KERN_INFO "SELinux: Initializing.\n");
5713
5714 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005715 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
James Morris7cae7e22006-03-22 00:09:22 -08005717 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5718 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005719 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 avc_init();
5721
James Morris6f0f0fd2008-07-10 17:02:07 +09005722 secondary_ops = security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 if (!secondary_ops)
Eric Paris828dfe12008-04-17 13:17:49 -04005724 panic("SELinux: No initial security operations\n");
5725 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 panic("SELinux: Unable to register with kernel.\n");
5727
Eric Paris828dfe12008-04-17 13:17:49 -04005728 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005729 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005730 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005731 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005732
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 return 0;
5734}
5735
5736void selinux_complete_init(void)
5737{
Eric Parisfadcdb42007-02-22 18:11:31 -05005738 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739
5740 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005741 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005742 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 spin_lock(&sb_security_lock);
5744next_sb:
5745 if (!list_empty(&superblock_security_head)) {
5746 struct superblock_security_struct *sbsec =
5747 list_entry(superblock_security_head.next,
Eric Paris828dfe12008-04-17 13:17:49 -04005748 struct superblock_security_struct,
5749 list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 struct super_block *sb = sbsec->sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 sb->s_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005753 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 down_read(&sb->s_umount);
5755 if (sb->s_root)
5756 superblock_doinit(sb, NULL);
5757 drop_super(sb);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005758 spin_lock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 spin_lock(&sb_security_lock);
5760 list_del_init(&sbsec->list);
5761 goto next_sb;
5762 }
5763 spin_unlock(&sb_security_lock);
Stephen Smalleyba0c19e2006-06-04 02:51:30 -07005764 spin_unlock(&sb_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765}
5766
5767/* SELinux requires early initialization in order to label
5768 all processes and objects when they are created. */
5769security_initcall(selinux_init);
5770
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005771#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
Paul Mooreeffad8d2008-01-29 08:49:27 -05005773static struct nf_hook_ops selinux_ipv4_ops[] = {
5774 {
5775 .hook = selinux_ipv4_postroute,
5776 .owner = THIS_MODULE,
5777 .pf = PF_INET,
5778 .hooknum = NF_INET_POST_ROUTING,
5779 .priority = NF_IP_PRI_SELINUX_LAST,
5780 },
5781 {
5782 .hook = selinux_ipv4_forward,
5783 .owner = THIS_MODULE,
5784 .pf = PF_INET,
5785 .hooknum = NF_INET_FORWARD,
5786 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005787 },
5788 {
5789 .hook = selinux_ipv4_output,
5790 .owner = THIS_MODULE,
5791 .pf = PF_INET,
5792 .hooknum = NF_INET_LOCAL_OUT,
5793 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795};
5796
5797#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5798
Paul Mooreeffad8d2008-01-29 08:49:27 -05005799static struct nf_hook_ops selinux_ipv6_ops[] = {
5800 {
5801 .hook = selinux_ipv6_postroute,
5802 .owner = THIS_MODULE,
5803 .pf = PF_INET6,
5804 .hooknum = NF_INET_POST_ROUTING,
5805 .priority = NF_IP6_PRI_SELINUX_LAST,
5806 },
5807 {
5808 .hook = selinux_ipv6_forward,
5809 .owner = THIS_MODULE,
5810 .pf = PF_INET6,
5811 .hooknum = NF_INET_FORWARD,
5812 .priority = NF_IP6_PRI_SELINUX_FIRST,
5813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814};
5815
5816#endif /* IPV6 */
5817
5818static int __init selinux_nf_ip_init(void)
5819{
5820 int err = 0;
5821
5822 if (!selinux_enabled)
5823 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005824
5825 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5826
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005827 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5828 if (err)
5829 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830
5831#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005832 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5833 if (err)
5834 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005836
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837out:
5838 return err;
5839}
5840
5841__initcall(selinux_nf_ip_init);
5842
5843#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5844static void selinux_nf_ip_exit(void)
5845{
Eric Parisfadcdb42007-02-22 18:11:31 -05005846 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005848 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005850 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851#endif /* IPV6 */
5852}
5853#endif
5854
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005855#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856
5857#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5858#define selinux_nf_ip_exit()
5859#endif
5860
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005861#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
5863#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005864static int selinux_disabled;
5865
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866int selinux_disable(void)
5867{
5868 extern void exit_sel_fs(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
5870 if (ss_initialized) {
5871 /* Not permitted after initial policy load. */
5872 return -EINVAL;
5873 }
5874
5875 if (selinux_disabled) {
5876 /* Only do this once. */
5877 return -EINVAL;
5878 }
5879
5880 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5881
5882 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005883 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884
5885 /* Reset security_ops to the secondary module, dummy or capability. */
5886 security_ops = secondary_ops;
5887
5888 /* Unregister netfilter hooks. */
5889 selinux_nf_ip_exit();
5890
5891 /* Unregister selinuxfs. */
5892 exit_sel_fs();
5893
5894 return 0;
5895}
5896#endif