blob: 77de1b7742d89f1e3e3ed0f268bb21f02cafbba0 [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 Mooreed6d76e2009-08-28 18:12:49 -040016 * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
Paul Moore82c21bf2011-08-01 11:10:33 +000017 * Paul Moore <paul@paul-moore.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>
Eric Paris0b24dcb2011-02-25 15:39:20 -050027#include <linux/kd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/kernel.h>
Roland McGrath0d094ef2008-07-25 19:45:49 -070029#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/errno.h>
31#include <linux/sched.h>
32#include <linux/security.h>
33#include <linux/xattr.h>
34#include <linux/capability.h>
35#include <linux/unistd.h>
36#include <linux/mm.h>
37#include <linux/mman.h>
38#include <linux/slab.h>
39#include <linux/pagemap.h>
Eric Paris0b24dcb2011-02-25 15:39:20 -050040#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/swap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/spinlock.h>
43#include <linux/syscalls.h>
Eric Paris2a7dba32011-02-01 11:05:39 -050044#include <linux/dcache.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/file.h>
Al Viro9f3acc32008-04-24 07:44:08 -040046#include <linux/fdtable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/namei.h>
48#include <linux/mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/netfilter_ipv4.h>
50#include <linux/netfilter_ipv6.h>
51#include <linux/tty.h>
52#include <net/icmp.h>
Stephen Hemminger227b60f2007-10-10 17:30:46 -070053#include <net/ip.h> /* for local_port_range[] */
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
Paul Moore220deb92008-01-29 08:38:23 -050055#include <net/net_namespace.h>
Paul Moored621d352008-01-29 08:43:36 -050056#include <net/netlabel.h>
Eric Parisf5269712008-05-14 11:27:45 -040057#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <asm/ioctls.h>
Arun Sharma60063492011-07-26 16:09:06 -070059#include <linux/atomic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <linux/bitops.h>
61#include <linux/interrupt.h>
62#include <linux/netdevice.h> /* for network interface checks */
63#include <linux/netlink.h>
64#include <linux/tcp.h>
65#include <linux/udp.h>
James Morris2ee92d42006-11-13 16:09:01 -080066#include <linux/dccp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include <linux/quota.h>
68#include <linux/un.h> /* for Unix socket types */
69#include <net/af_unix.h> /* for Unix socket types */
70#include <linux/parser.h>
71#include <linux/nfs_mount.h>
72#include <net/ipv6.h>
73#include <linux/hugetlb.h>
74#include <linux/personality.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#include <linux/audit.h>
Eric Paris6931dfc2005-06-30 02:58:51 -070076#include <linux/string.h>
Catherine Zhang877ce7c2006-06-29 12:27:47 -070077#include <linux/selinux.h>
Eric Paris23970742006-09-25 23:32:01 -070078#include <linux/mutex.h>
Frank Mayharf06febc2008-09-12 09:54:39 -070079#include <linux/posix-timers.h>
Kees Cook00234592010-02-03 15:36:43 -080080#include <linux/syslog.h>
Serge E. Hallyn34867402011-03-23 16:43:17 -070081#include <linux/user_namespace.h>
Paul Gortmaker44fc7ea2011-05-26 20:52:10 -040082#include <linux/export.h>
Al Viro40401532012-02-13 03:58:52 +000083#include <linux/msg.h>
84#include <linux/shm.h>
Amir Samuelov6a22e462014-05-26 11:44:06 +030085#include <linux/pft.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87#include "avc.h"
88#include "objsec.h"
89#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050090#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040091#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080092#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050093#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020094#include "audit.h"
James Morris7b98a582011-08-30 12:52:32 +100095#include "avc_ss.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
David P. Quigley11689d42009-01-16 09:22:03 -050097#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050098
James Morris20510f22007-10-16 23:31:32 -070099extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Paul Moored621d352008-01-29 08:43:36 -0500101/* SECMARK reference count */
James Morris56a4ca92011-08-17 11:08:43 +1000102static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
Paul Moored621d352008-01-29 08:43:36 -0500103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400105int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107static int __init enforcing_setup(char *str)
108{
Eric Parisf5269712008-05-14 11:27:45 -0400109 unsigned long enforcing;
110 if (!strict_strtoul(str, 0, &enforcing))
111 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 return 1;
113}
114__setup("enforcing=", enforcing_setup);
115#endif
116
117#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
118int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
119
120static int __init selinux_enabled_setup(char *str)
121{
Eric Parisf5269712008-05-14 11:27:45 -0400122 unsigned long enabled;
123 if (!strict_strtoul(str, 0, &enabled))
124 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 return 1;
126}
127__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400128#else
129int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130#endif
131
Christoph Lametere18b8902006-12-06 20:33:20 -0800132static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800133
Paul Moored621d352008-01-29 08:43:36 -0500134/**
135 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
136 *
137 * Description:
138 * This function checks the SECMARK reference counter to see if any SECMARK
139 * targets are currently configured, if the reference counter is greater than
140 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
141 * enabled, false (0) if SECMARK is disabled.
142 *
143 */
144static int selinux_secmark_enabled(void)
145{
146 return (atomic_read(&selinux_secmark_refcount) > 0);
147}
148
David Howellsd84f4f92008-11-14 10:39:23 +1100149/*
150 * initialise the security for the init task
151 */
152static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
David Howells3b11a1d2008-11-14 10:39:26 +1100154 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 struct task_security_struct *tsec;
156
James Morris89d155e2005-10-30 14:59:21 -0800157 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100159 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
David Howellsd84f4f92008-11-14 10:39:23 +1100161 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100162 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
David Howells275bb412008-11-14 10:39:19 +1100165/*
David Howells88e67f32008-11-14 10:39:21 +1100166 * get the security ID of a set of credentials
167 */
168static inline u32 cred_sid(const struct cred *cred)
169{
170 const struct task_security_struct *tsec;
171
172 tsec = cred->security;
173 return tsec->sid;
174}
175
176/*
David Howells3b11a1d2008-11-14 10:39:26 +1100177 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100178 */
179static inline u32 task_sid(const struct task_struct *task)
180{
David Howells275bb412008-11-14 10:39:19 +1100181 u32 sid;
182
183 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100184 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100185 rcu_read_unlock();
186 return sid;
187}
188
189/*
David Howells3b11a1d2008-11-14 10:39:26 +1100190 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100191 */
192static inline u32 current_sid(void)
193{
Paul Moore5fb49872010-04-22 14:46:19 -0400194 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +1100195
196 return tsec->sid;
197}
198
David Howells88e67f32008-11-14 10:39:21 +1100199/* Allocate and free functions for each kind of security blob. */
200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static int inode_alloc_security(struct inode *inode)
202{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100204 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Josef Bacika02fe132008-04-04 09:35:05 +1100206 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (!isec)
208 return -ENOMEM;
209
Eric Paris23970742006-09-25 23:32:01 -0700210 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 isec->inode = inode;
213 isec->sid = SECINITSID_UNLABELED;
214 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100215 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 inode->i_security = isec;
217
218 return 0;
219}
220
221static void inode_free_security(struct inode *inode)
222{
223 struct inode_security_struct *isec = inode->i_security;
224 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 spin_lock(&sbsec->isec_lock);
227 if (!list_empty(&isec->list))
228 list_del_init(&isec->list);
229 spin_unlock(&sbsec->isec_lock);
230
231 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800232 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233}
234
235static int file_alloc_security(struct file *file)
236{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100238 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800240 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 if (!fsec)
242 return -ENOMEM;
243
David Howells275bb412008-11-14 10:39:19 +1100244 fsec->sid = sid;
245 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 file->f_security = fsec;
247
248 return 0;
249}
250
251static void file_free_security(struct file *file)
252{
253 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 file->f_security = NULL;
255 kfree(fsec);
256}
257
258static int superblock_alloc_security(struct super_block *sb)
259{
260 struct superblock_security_struct *sbsec;
261
James Morris89d155e2005-10-30 14:59:21 -0800262 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 if (!sbsec)
264 return -ENOMEM;
265
Eric Parisbc7e9822006-09-25 23:32:02 -0700266 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 INIT_LIST_HEAD(&sbsec->isec_head);
268 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sbsec->sb = sb;
270 sbsec->sid = SECINITSID_UNLABELED;
271 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700272 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 sb->s_security = sbsec;
274
275 return 0;
276}
277
278static void superblock_free_security(struct super_block *sb)
279{
280 struct superblock_security_struct *sbsec = sb->s_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 sb->s_security = NULL;
282 kfree(sbsec);
283}
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285/* The file system's label must be initialized prior to use. */
286
Stephen Hemminger634a5392010-03-04 21:59:03 -0800287static const char *labeling_behaviors[6] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 "uses xattr",
289 "uses transition SIDs",
290 "uses task SIDs",
291 "uses genfs_contexts",
292 "not configured for labeling",
293 "uses mountpoint labeling",
294};
295
296static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
297
298static inline int inode_doinit(struct inode *inode)
299{
300 return inode_doinit_with_dentry(inode, NULL);
301}
302
303enum {
Eric Paris31e87932007-09-19 17:19:12 -0400304 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 Opt_context = 1,
306 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500307 Opt_defcontext = 3,
308 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500309 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310};
311
Steven Whitehousea447c092008-10-13 10:46:57 +0100312static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400313 {Opt_context, CONTEXT_STR "%s"},
314 {Opt_fscontext, FSCONTEXT_STR "%s"},
315 {Opt_defcontext, DEFCONTEXT_STR "%s"},
316 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500317 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400318 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319};
320
321#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
322
Eric Parisc312feb2006-07-10 04:43:53 -0700323static int may_context_mount_sb_relabel(u32 sid,
324 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100325 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700326{
David Howells275bb412008-11-14 10:39:19 +1100327 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700328 int rc;
329
330 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
331 FILESYSTEM__RELABELFROM, NULL);
332 if (rc)
333 return rc;
334
335 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
336 FILESYSTEM__RELABELTO, NULL);
337 return rc;
338}
339
Eric Paris08089252006-07-10 04:43:55 -0700340static int may_context_mount_inode_relabel(u32 sid,
341 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100342 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700343{
David Howells275bb412008-11-14 10:39:19 +1100344 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700345 int rc;
346 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
347 FILESYSTEM__RELABELFROM, NULL);
348 if (rc)
349 return rc;
350
351 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
352 FILESYSTEM__ASSOCIATE, NULL);
353 return rc;
354}
355
Eric Parisc9180a52007-11-30 13:00:35 -0500356static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
358 struct superblock_security_struct *sbsec = sb->s_security;
359 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500360 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 int rc = 0;
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
364 /* Make sure that the xattr handler exists and that no
365 error other than -ENODATA is returned by getxattr on
366 the root directory. -ENODATA is ok, as this may be
367 the first boot of the SELinux kernel before we have
368 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500369 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
371 "xattr support\n", sb->s_id, sb->s_type->name);
372 rc = -EOPNOTSUPP;
373 goto out;
374 }
Eric Parisc9180a52007-11-30 13:00:35 -0500375 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (rc < 0 && rc != -ENODATA) {
377 if (rc == -EOPNOTSUPP)
378 printk(KERN_WARNING "SELinux: (dev %s, type "
379 "%s) has no security xattr handler\n",
380 sb->s_id, sb->s_type->name);
381 else
382 printk(KERN_WARNING "SELinux: (dev %s, type "
383 "%s) getxattr errno %d\n", sb->s_id,
384 sb->s_type->name, -rc);
385 goto out;
386 }
387 }
388
David P. Quigley11689d42009-01-16 09:22:03 -0500389 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Eric Parisc9180a52007-11-30 13:00:35 -0500391 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500392 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500394 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500395 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 sb->s_id, sb->s_type->name,
397 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
David P. Quigley11689d42009-01-16 09:22:03 -0500399 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
400 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
401 sbsec->behavior == SECURITY_FS_USE_NONE ||
402 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
403 sbsec->flags &= ~SE_SBLABELSUPP;
404
Mark Salyzyn2c088052015-01-07 09:27:15 -0800405 /* Special handling. Is genfs but also has in-core setxattr handler*/
406 if (!strcmp(sb->s_type->name, "sysfs") ||
407 !strcmp(sb->s_type->name, "pstore") ||
408 !strcmp(sb->s_type->name, "debugfs") ||
409 !strcmp(sb->s_type->name, "rootfs"))
David P. Quigleyddd29ec2009-09-09 14:25:37 -0400410 sbsec->flags |= SE_SBLABELSUPP;
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500413 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 /* Initialize any other inodes associated with the superblock, e.g.
416 inodes created prior to initial policy load or inodes created
417 during get_sb by a pseudo filesystem that directly
418 populates itself. */
419 spin_lock(&sbsec->isec_lock);
420next_inode:
421 if (!list_empty(&sbsec->isec_head)) {
422 struct inode_security_struct *isec =
423 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500424 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 struct inode *inode = isec->inode;
426 spin_unlock(&sbsec->isec_lock);
427 inode = igrab(inode);
428 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500429 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 inode_doinit(inode);
431 iput(inode);
432 }
433 spin_lock(&sbsec->isec_lock);
434 list_del_init(&isec->list);
435 goto next_inode;
436 }
437 spin_unlock(&sbsec->isec_lock);
438out:
Eric Parisc9180a52007-11-30 13:00:35 -0500439 return rc;
440}
441
442/*
443 * This function should allow an FS to ask what it's mount security
444 * options were so it can use those later for submounts, displaying
445 * mount options, or whatever.
446 */
447static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500448 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500449{
450 int rc = 0, i;
451 struct superblock_security_struct *sbsec = sb->s_security;
452 char *context = NULL;
453 u32 len;
454 char tmp;
455
Eric Parise0007522008-03-05 10:31:54 -0500456 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500457
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500458 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500459 return -EINVAL;
460
461 if (!ss_initialized)
462 return -EINVAL;
463
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500464 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500465 /* count the number of mount options for this sb */
466 for (i = 0; i < 8; i++) {
467 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500468 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500469 tmp >>= 1;
470 }
David P. Quigley11689d42009-01-16 09:22:03 -0500471 /* Check if the Label support flag is set */
472 if (sbsec->flags & SE_SBLABELSUPP)
473 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500474
Eric Parise0007522008-03-05 10:31:54 -0500475 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
476 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500477 rc = -ENOMEM;
478 goto out_free;
479 }
480
Eric Parise0007522008-03-05 10:31:54 -0500481 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
482 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500483 rc = -ENOMEM;
484 goto out_free;
485 }
486
487 i = 0;
488 if (sbsec->flags & FSCONTEXT_MNT) {
489 rc = security_sid_to_context(sbsec->sid, &context, &len);
490 if (rc)
491 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500492 opts->mnt_opts[i] = context;
493 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500494 }
495 if (sbsec->flags & CONTEXT_MNT) {
496 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
497 if (rc)
498 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500499 opts->mnt_opts[i] = context;
500 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500501 }
502 if (sbsec->flags & DEFCONTEXT_MNT) {
503 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
504 if (rc)
505 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500506 opts->mnt_opts[i] = context;
507 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500508 }
509 if (sbsec->flags & ROOTCONTEXT_MNT) {
510 struct inode *root = sbsec->sb->s_root->d_inode;
511 struct inode_security_struct *isec = root->i_security;
512
513 rc = security_sid_to_context(isec->sid, &context, &len);
514 if (rc)
515 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500516 opts->mnt_opts[i] = context;
517 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500518 }
David P. Quigley11689d42009-01-16 09:22:03 -0500519 if (sbsec->flags & SE_SBLABELSUPP) {
520 opts->mnt_opts[i] = NULL;
521 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
522 }
Eric Parisc9180a52007-11-30 13:00:35 -0500523
Eric Parise0007522008-03-05 10:31:54 -0500524 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500525
526 return 0;
527
528out_free:
Eric Parise0007522008-03-05 10:31:54 -0500529 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500530 return rc;
531}
532
533static int bad_option(struct superblock_security_struct *sbsec, char flag,
534 u32 old_sid, u32 new_sid)
535{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500536 char mnt_flags = sbsec->flags & SE_MNTMASK;
537
Eric Parisc9180a52007-11-30 13:00:35 -0500538 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500539 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500540 if (!(sbsec->flags & flag) ||
541 (old_sid != new_sid))
542 return 1;
543
544 /* check if we were passed the same options twice,
545 * aka someone passed context=a,context=b
546 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500547 if (!(sbsec->flags & SE_SBINITIALIZED))
548 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500549 return 1;
550 return 0;
551}
Eric Parise0007522008-03-05 10:31:54 -0500552
Eric Parisc9180a52007-11-30 13:00:35 -0500553/*
554 * Allow filesystems with binary mount data to explicitly set mount point
555 * labeling information.
556 */
Eric Parise0007522008-03-05 10:31:54 -0500557static int selinux_set_mnt_opts(struct super_block *sb,
558 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500559{
David Howells275bb412008-11-14 10:39:19 +1100560 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500561 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500562 struct superblock_security_struct *sbsec = sb->s_security;
563 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000564 struct inode *inode = sbsec->sb->s_root->d_inode;
565 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500566 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
567 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500568 char **mount_options = opts->mnt_opts;
569 int *flags = opts->mnt_opts_flags;
570 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500571
572 mutex_lock(&sbsec->lock);
573
574 if (!ss_initialized) {
575 if (!num_opts) {
576 /* Defer initialization until selinux_complete_init,
577 after the initial policy is loaded and the security
578 server is ready to handle calls. */
Eric Parisc9180a52007-11-30 13:00:35 -0500579 goto out;
580 }
581 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400582 printk(KERN_WARNING "SELinux: Unable to set superblock options "
583 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500584 goto out;
585 }
586
587 /*
Eric Parise0007522008-03-05 10:31:54 -0500588 * Binary mount data FS will come through this function twice. Once
589 * from an explicit call and once from the generic calls from the vfs.
590 * Since the generic VFS calls will not contain any security mount data
591 * we need to skip the double mount verification.
592 *
593 * This does open a hole in which we will not notice if the first
594 * mount using this sb set explict options and a second mount using
595 * this sb does not set any security options. (The first options
596 * will be used for both mounts)
597 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500598 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500599 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400600 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500601
602 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500603 * parse the mount options, check if they are valid sids.
604 * also check if someone is trying to mount the same sb more
605 * than once with different security options.
606 */
607 for (i = 0; i < num_opts; i++) {
608 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500609
610 if (flags[i] == SE_SBLABELSUPP)
611 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500612 rc = security_context_to_sid(mount_options[i],
613 strlen(mount_options[i]), &sid);
614 if (rc) {
615 printk(KERN_WARNING "SELinux: security_context_to_sid"
616 "(%s) failed for (dev %s, type %s) errno=%d\n",
617 mount_options[i], sb->s_id, name, rc);
618 goto out;
619 }
620 switch (flags[i]) {
621 case FSCONTEXT_MNT:
622 fscontext_sid = sid;
623
624 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
625 fscontext_sid))
626 goto out_double_mount;
627
628 sbsec->flags |= FSCONTEXT_MNT;
629 break;
630 case CONTEXT_MNT:
631 context_sid = sid;
632
633 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
634 context_sid))
635 goto out_double_mount;
636
637 sbsec->flags |= CONTEXT_MNT;
638 break;
639 case ROOTCONTEXT_MNT:
640 rootcontext_sid = sid;
641
642 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
643 rootcontext_sid))
644 goto out_double_mount;
645
646 sbsec->flags |= ROOTCONTEXT_MNT;
647
648 break;
649 case DEFCONTEXT_MNT:
650 defcontext_sid = sid;
651
652 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
653 defcontext_sid))
654 goto out_double_mount;
655
656 sbsec->flags |= DEFCONTEXT_MNT;
657
658 break;
659 default:
660 rc = -EINVAL;
661 goto out;
662 }
663 }
664
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500665 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500666 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500667 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500668 goto out_double_mount;
669 rc = 0;
670 goto out;
671 }
672
James Morris089be432008-07-15 18:32:49 +1000673 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500674 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500675
676 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500677 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500678 if (rc) {
679 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000680 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500681 goto out;
682 }
683
684 /* sets the context of the superblock for the fs being mounted. */
685 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100686 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500687 if (rc)
688 goto out;
689
690 sbsec->sid = fscontext_sid;
691 }
692
693 /*
694 * Switch to using mount point labeling behavior.
695 * sets the label used on all file below the mountpoint, and will set
696 * the superblock context if not already set.
697 */
698 if (context_sid) {
699 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100700 rc = may_context_mount_sb_relabel(context_sid, sbsec,
701 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500702 if (rc)
703 goto out;
704 sbsec->sid = context_sid;
705 } else {
David Howells275bb412008-11-14 10:39:19 +1100706 rc = may_context_mount_inode_relabel(context_sid, sbsec,
707 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500708 if (rc)
709 goto out;
710 }
711 if (!rootcontext_sid)
712 rootcontext_sid = context_sid;
713
714 sbsec->mntpoint_sid = context_sid;
715 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
716 }
717
718 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100719 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
720 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500721 if (rc)
722 goto out;
723
724 root_isec->sid = rootcontext_sid;
725 root_isec->initialized = 1;
726 }
727
728 if (defcontext_sid) {
729 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
730 rc = -EINVAL;
731 printk(KERN_WARNING "SELinux: defcontext option is "
732 "invalid for this filesystem type\n");
733 goto out;
734 }
735
736 if (defcontext_sid != sbsec->def_sid) {
737 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100738 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500739 if (rc)
740 goto out;
741 }
742
743 sbsec->def_sid = defcontext_sid;
744 }
745
746 rc = sb_finish_set_opts(sb);
747out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700748 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500750out_double_mount:
751 rc = -EINVAL;
752 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
753 "security settings for (dev %s, type %s)\n", sb->s_id, name);
754 goto out;
755}
756
757static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
758 struct super_block *newsb)
759{
760 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
761 struct superblock_security_struct *newsbsec = newsb->s_security;
762
763 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
764 int set_context = (oldsbsec->flags & CONTEXT_MNT);
765 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
766
Eric Paris0f5e6422008-04-21 16:24:11 -0400767 /*
768 * if the parent was able to be mounted it clearly had no special lsm
Al Viroe8c26252010-03-23 06:36:54 -0400769 * mount options. thus we can safely deal with this superblock later
Eric Paris0f5e6422008-04-21 16:24:11 -0400770 */
Al Viroe8c26252010-03-23 06:36:54 -0400771 if (!ss_initialized)
Eric Paris0f5e6422008-04-21 16:24:11 -0400772 return;
Eric Parisc9180a52007-11-30 13:00:35 -0500773
Eric Parisc9180a52007-11-30 13:00:35 -0500774 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500775 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500776
Eric Paris5a552612008-04-09 14:08:35 -0400777 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500778 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400779 return;
780
Eric Parisc9180a52007-11-30 13:00:35 -0500781 mutex_lock(&newsbsec->lock);
782
783 newsbsec->flags = oldsbsec->flags;
784
785 newsbsec->sid = oldsbsec->sid;
786 newsbsec->def_sid = oldsbsec->def_sid;
787 newsbsec->behavior = oldsbsec->behavior;
788
789 if (set_context) {
790 u32 sid = oldsbsec->mntpoint_sid;
791
792 if (!set_fscontext)
793 newsbsec->sid = sid;
794 if (!set_rootcontext) {
795 struct inode *newinode = newsb->s_root->d_inode;
796 struct inode_security_struct *newisec = newinode->i_security;
797 newisec->sid = sid;
798 }
799 newsbsec->mntpoint_sid = sid;
800 }
801 if (set_rootcontext) {
802 const struct inode *oldinode = oldsb->s_root->d_inode;
803 const struct inode_security_struct *oldisec = oldinode->i_security;
804 struct inode *newinode = newsb->s_root->d_inode;
805 struct inode_security_struct *newisec = newinode->i_security;
806
807 newisec->sid = oldisec->sid;
808 }
809
810 sb_finish_set_opts(newsb);
811 mutex_unlock(&newsbsec->lock);
812}
813
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200814static int selinux_parse_opts_str(char *options,
815 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500816{
Eric Parise0007522008-03-05 10:31:54 -0500817 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500818 char *context = NULL, *defcontext = NULL;
819 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500820 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500821
Eric Parise0007522008-03-05 10:31:54 -0500822 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500823
824 /* Standard string-based options. */
825 while ((p = strsep(&options, "|")) != NULL) {
826 int token;
827 substring_t args[MAX_OPT_ARGS];
828
829 if (!*p)
830 continue;
831
832 token = match_token(p, tokens, args);
833
834 switch (token) {
835 case Opt_context:
836 if (context || defcontext) {
837 rc = -EINVAL;
838 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
839 goto out_err;
840 }
841 context = match_strdup(&args[0]);
842 if (!context) {
843 rc = -ENOMEM;
844 goto out_err;
845 }
846 break;
847
848 case Opt_fscontext:
849 if (fscontext) {
850 rc = -EINVAL;
851 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
852 goto out_err;
853 }
854 fscontext = match_strdup(&args[0]);
855 if (!fscontext) {
856 rc = -ENOMEM;
857 goto out_err;
858 }
859 break;
860
861 case Opt_rootcontext:
862 if (rootcontext) {
863 rc = -EINVAL;
864 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
865 goto out_err;
866 }
867 rootcontext = match_strdup(&args[0]);
868 if (!rootcontext) {
869 rc = -ENOMEM;
870 goto out_err;
871 }
872 break;
873
874 case Opt_defcontext:
875 if (context || defcontext) {
876 rc = -EINVAL;
877 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
878 goto out_err;
879 }
880 defcontext = match_strdup(&args[0]);
881 if (!defcontext) {
882 rc = -ENOMEM;
883 goto out_err;
884 }
885 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500886 case Opt_labelsupport:
887 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500888 default:
889 rc = -EINVAL;
890 printk(KERN_WARNING "SELinux: unknown mount option\n");
891 goto out_err;
892
893 }
894 }
895
Eric Parise0007522008-03-05 10:31:54 -0500896 rc = -ENOMEM;
897 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
898 if (!opts->mnt_opts)
899 goto out_err;
900
901 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
902 if (!opts->mnt_opts_flags) {
903 kfree(opts->mnt_opts);
904 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500905 }
906
Eric Parise0007522008-03-05 10:31:54 -0500907 if (fscontext) {
908 opts->mnt_opts[num_mnt_opts] = fscontext;
909 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
910 }
911 if (context) {
912 opts->mnt_opts[num_mnt_opts] = context;
913 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
914 }
915 if (rootcontext) {
916 opts->mnt_opts[num_mnt_opts] = rootcontext;
917 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
918 }
919 if (defcontext) {
920 opts->mnt_opts[num_mnt_opts] = defcontext;
921 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
922 }
923
924 opts->num_mnt_opts = num_mnt_opts;
925 return 0;
926
Eric Parisc9180a52007-11-30 13:00:35 -0500927out_err:
928 kfree(context);
929 kfree(defcontext);
930 kfree(fscontext);
931 kfree(rootcontext);
932 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933}
Eric Parise0007522008-03-05 10:31:54 -0500934/*
935 * string mount options parsing and call set the sbsec
936 */
937static int superblock_doinit(struct super_block *sb, void *data)
938{
939 int rc = 0;
940 char *options = data;
941 struct security_mnt_opts opts;
942
943 security_init_mnt_opts(&opts);
944
945 if (!data)
946 goto out;
947
948 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
949
950 rc = selinux_parse_opts_str(options, &opts);
951 if (rc)
952 goto out_err;
953
954out:
955 rc = selinux_set_mnt_opts(sb, &opts);
956
957out_err:
958 security_free_mnt_opts(&opts);
959 return rc;
960}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Adrian Bunk3583a712008-07-22 20:21:23 +0300962static void selinux_write_opts(struct seq_file *m,
963 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000964{
965 int i;
966 char *prefix;
967
968 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -0500969 char *has_comma;
970
971 if (opts->mnt_opts[i])
972 has_comma = strchr(opts->mnt_opts[i], ',');
973 else
974 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +1000975
976 switch (opts->mnt_opts_flags[i]) {
977 case CONTEXT_MNT:
978 prefix = CONTEXT_STR;
979 break;
980 case FSCONTEXT_MNT:
981 prefix = FSCONTEXT_STR;
982 break;
983 case ROOTCONTEXT_MNT:
984 prefix = ROOTCONTEXT_STR;
985 break;
986 case DEFCONTEXT_MNT:
987 prefix = DEFCONTEXT_STR;
988 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500989 case SE_SBLABELSUPP:
990 seq_putc(m, ',');
991 seq_puts(m, LABELSUPP_STR);
992 continue;
Eric Paris2069f452008-07-04 09:47:13 +1000993 default:
994 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -0400995 return;
Eric Paris2069f452008-07-04 09:47:13 +1000996 };
997 /* we need a comma before each option */
998 seq_putc(m, ',');
999 seq_puts(m, prefix);
1000 if (has_comma)
1001 seq_putc(m, '\"');
1002 seq_puts(m, opts->mnt_opts[i]);
1003 if (has_comma)
1004 seq_putc(m, '\"');
1005 }
1006}
1007
1008static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1009{
1010 struct security_mnt_opts opts;
1011 int rc;
1012
1013 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001014 if (rc) {
1015 /* before policy load we may get EINVAL, don't show anything */
1016 if (rc == -EINVAL)
1017 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001018 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001019 }
Eric Paris2069f452008-07-04 09:47:13 +10001020
1021 selinux_write_opts(m, &opts);
1022
1023 security_free_mnt_opts(&opts);
1024
1025 return rc;
1026}
1027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028static inline u16 inode_mode_to_security_class(umode_t mode)
1029{
1030 switch (mode & S_IFMT) {
1031 case S_IFSOCK:
1032 return SECCLASS_SOCK_FILE;
1033 case S_IFLNK:
1034 return SECCLASS_LNK_FILE;
1035 case S_IFREG:
1036 return SECCLASS_FILE;
1037 case S_IFBLK:
1038 return SECCLASS_BLK_FILE;
1039 case S_IFDIR:
1040 return SECCLASS_DIR;
1041 case S_IFCHR:
1042 return SECCLASS_CHR_FILE;
1043 case S_IFIFO:
1044 return SECCLASS_FIFO_FILE;
1045
1046 }
1047
1048 return SECCLASS_FILE;
1049}
1050
James Morris13402582005-09-30 14:24:34 -04001051static inline int default_protocol_stream(int protocol)
1052{
1053 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1054}
1055
1056static inline int default_protocol_dgram(int protocol)
1057{
1058 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1059}
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1062{
1063 switch (family) {
1064 case PF_UNIX:
1065 switch (type) {
1066 case SOCK_STREAM:
1067 case SOCK_SEQPACKET:
1068 return SECCLASS_UNIX_STREAM_SOCKET;
1069 case SOCK_DGRAM:
1070 return SECCLASS_UNIX_DGRAM_SOCKET;
1071 }
1072 break;
1073 case PF_INET:
1074 case PF_INET6:
1075 switch (type) {
1076 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001077 if (default_protocol_stream(protocol))
1078 return SECCLASS_TCP_SOCKET;
1079 else
1080 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001082 if (default_protocol_dgram(protocol))
1083 return SECCLASS_UDP_SOCKET;
1084 else
1085 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001086 case SOCK_DCCP:
1087 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001088 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return SECCLASS_RAWIP_SOCKET;
1090 }
1091 break;
1092 case PF_NETLINK:
1093 switch (protocol) {
1094 case NETLINK_ROUTE:
1095 return SECCLASS_NETLINK_ROUTE_SOCKET;
1096 case NETLINK_FIREWALL:
1097 return SECCLASS_NETLINK_FIREWALL_SOCKET;
Pavel Emelyanov7f1fb602011-12-06 07:56:43 +00001098 case NETLINK_SOCK_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1100 case NETLINK_NFLOG:
1101 return SECCLASS_NETLINK_NFLOG_SOCKET;
1102 case NETLINK_XFRM:
1103 return SECCLASS_NETLINK_XFRM_SOCKET;
1104 case NETLINK_SELINUX:
1105 return SECCLASS_NETLINK_SELINUX_SOCKET;
1106 case NETLINK_AUDIT:
1107 return SECCLASS_NETLINK_AUDIT_SOCKET;
1108 case NETLINK_IP6_FW:
1109 return SECCLASS_NETLINK_IP6FW_SOCKET;
1110 case NETLINK_DNRTMSG:
1111 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001112 case NETLINK_KOBJECT_UEVENT:
1113 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 default:
1115 return SECCLASS_NETLINK_SOCKET;
1116 }
1117 case PF_PACKET:
1118 return SECCLASS_PACKET_SOCKET;
1119 case PF_KEY:
1120 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001121 case PF_APPLETALK:
1122 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 }
1124
1125 return SECCLASS_SOCKET;
1126}
1127
1128#ifdef CONFIG_PROC_FS
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001129static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 u16 tclass,
1131 u32 *sid)
1132{
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001133 int rc;
1134 char *buffer, *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Eric Paris828dfe12008-04-17 13:17:49 -04001136 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if (!buffer)
1138 return -ENOMEM;
1139
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001140 path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
1141 if (IS_ERR(path))
1142 rc = PTR_ERR(path);
1143 else {
1144 /* each process gets a /proc/PID/ entry. Strip off the
1145 * PID part to get a valid selinux labeling.
1146 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
1147 while (path[1] >= '0' && path[1] <= '9') {
1148 path[1] = '/';
1149 path++;
1150 }
1151 rc = security_genfs_sid("proc", path, tclass, sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 free_page((unsigned long)buffer);
1154 return rc;
1155}
1156#else
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001157static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 u16 tclass,
1159 u32 *sid)
1160{
1161 return -EINVAL;
1162}
1163#endif
1164
1165/* The inode's security attributes must be initialized before first use. */
1166static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1167{
1168 struct superblock_security_struct *sbsec = NULL;
1169 struct inode_security_struct *isec = inode->i_security;
1170 u32 sid;
1171 struct dentry *dentry;
1172#define INITCONTEXTLEN 255
1173 char *context = NULL;
1174 unsigned len = 0;
1175 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 if (isec->initialized)
1178 goto out;
1179
Eric Paris23970742006-09-25 23:32:01 -07001180 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001182 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001185 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 /* Defer initialization until selinux_complete_init,
1187 after the initial policy is loaded and the security
1188 server is ready to handle calls. */
1189 spin_lock(&sbsec->isec_lock);
1190 if (list_empty(&isec->list))
1191 list_add(&isec->list, &sbsec->isec_head);
1192 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001193 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 }
1195
1196 switch (sbsec->behavior) {
1197 case SECURITY_FS_USE_XATTR:
1198 if (!inode->i_op->getxattr) {
1199 isec->sid = sbsec->def_sid;
1200 break;
1201 }
1202
1203 /* Need a dentry, since the xattr API requires one.
1204 Life would be simpler if we could just pass the inode. */
1205 if (opt_dentry) {
1206 /* Called from d_instantiate or d_splice_alias. */
1207 dentry = dget(opt_dentry);
1208 } else {
1209 /* Called from selinux_complete_init, try to find a dentry. */
1210 dentry = d_find_alias(inode);
1211 }
1212 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001213 /*
1214 * this is can be hit on boot when a file is accessed
1215 * before the policy is loaded. When we load policy we
1216 * may find inodes that have no dentry on the
1217 * sbsec->isec_head list. No reason to complain as these
1218 * will get fixed up the next time we go through
1219 * inode_doinit with a dentry, before these inodes could
1220 * be used again by userspace.
1221 */
Eric Paris23970742006-09-25 23:32:01 -07001222 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 }
1224
1225 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001226 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 if (!context) {
1228 rc = -ENOMEM;
1229 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001230 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001232 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1234 context, len);
1235 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001236 kfree(context);
1237
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 /* Need a larger buffer. Query for the right size. */
1239 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1240 NULL, 0);
1241 if (rc < 0) {
1242 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001243 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001246 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 if (!context) {
1248 rc = -ENOMEM;
1249 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001250 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001252 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 rc = inode->i_op->getxattr(dentry,
1254 XATTR_NAME_SELINUX,
1255 context, len);
1256 }
1257 dput(dentry);
1258 if (rc < 0) {
1259 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001260 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001261 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 -rc, inode->i_sb->s_id, inode->i_ino);
1263 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001264 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
1266 /* Map ENODATA to the default file SID */
1267 sid = sbsec->def_sid;
1268 rc = 0;
1269 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001270 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001271 sbsec->def_sid,
1272 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001274 char *dev = inode->i_sb->s_id;
1275 unsigned long ino = inode->i_ino;
1276
1277 if (rc == -EINVAL) {
1278 if (printk_ratelimit())
1279 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1280 "context=%s. This indicates you may need to relabel the inode or the "
1281 "filesystem in question.\n", ino, dev, context);
1282 } else {
1283 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1284 "returned %d for dev=%s ino=%ld\n",
1285 __func__, context, -rc, dev, ino);
1286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 kfree(context);
1288 /* Leave with the unlabeled SID */
1289 rc = 0;
1290 break;
1291 }
1292 }
1293 kfree(context);
1294 isec->sid = sid;
1295 break;
1296 case SECURITY_FS_USE_TASK:
1297 isec->sid = isec->task_sid;
1298 break;
1299 case SECURITY_FS_USE_TRANS:
1300 /* Default to the fs SID. */
1301 isec->sid = sbsec->sid;
1302
1303 /* Try to obtain a transition SID. */
1304 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Eric Paris652bb9b2011-02-01 11:05:40 -05001305 rc = security_transition_sid(isec->task_sid, sbsec->sid,
1306 isec->sclass, NULL, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001308 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 isec->sid = sid;
1310 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001311 case SECURITY_FS_USE_MNTPOINT:
1312 isec->sid = sbsec->mntpoint_sid;
1313 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001315 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 isec->sid = sbsec->sid;
1317
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001318 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001319 if (opt_dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001321 rc = selinux_proc_get_sid(opt_dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 isec->sclass,
1323 &sid);
1324 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001325 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 isec->sid = sid;
1327 }
1328 }
1329 break;
1330 }
1331
1332 isec->initialized = 1;
1333
Eric Paris23970742006-09-25 23:32:01 -07001334out_unlock:
1335 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336out:
1337 if (isec->sclass == SECCLASS_FILE)
1338 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 return rc;
1340}
1341
1342/* Convert a Linux signal to an access vector. */
1343static inline u32 signal_to_av(int sig)
1344{
1345 u32 perm = 0;
1346
1347 switch (sig) {
1348 case SIGCHLD:
1349 /* Commonly granted from child to parent. */
1350 perm = PROCESS__SIGCHLD;
1351 break;
1352 case SIGKILL:
1353 /* Cannot be caught or ignored */
1354 perm = PROCESS__SIGKILL;
1355 break;
1356 case SIGSTOP:
1357 /* Cannot be caught or ignored */
1358 perm = PROCESS__SIGSTOP;
1359 break;
1360 default:
1361 /* All other signals. */
1362 perm = PROCESS__SIGNAL;
1363 break;
1364 }
1365
1366 return perm;
1367}
1368
David Howells275bb412008-11-14 10:39:19 +11001369/*
David Howellsd84f4f92008-11-14 10:39:23 +11001370 * Check permission between a pair of credentials
1371 * fork check, ptrace check, etc.
1372 */
1373static int cred_has_perm(const struct cred *actor,
1374 const struct cred *target,
1375 u32 perms)
1376{
1377 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1378
1379 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1380}
1381
1382/*
David Howells88e67f32008-11-14 10:39:21 +11001383 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001384 * fork check, ptrace check, etc.
1385 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001386 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001387 */
1388static int task_has_perm(const struct task_struct *tsk1,
1389 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 u32 perms)
1391{
David Howells275bb412008-11-14 10:39:19 +11001392 const struct task_security_struct *__tsec1, *__tsec2;
1393 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
David Howells275bb412008-11-14 10:39:19 +11001395 rcu_read_lock();
1396 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1397 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1398 rcu_read_unlock();
1399 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400}
1401
David Howells3b11a1d2008-11-14 10:39:26 +11001402/*
1403 * Check permission between current and another task, e.g. signal checks,
1404 * fork check, ptrace check, etc.
1405 * current is the actor and tsk2 is the target
1406 * - this uses current's subjective creds
1407 */
1408static int current_has_perm(const struct task_struct *tsk,
1409 u32 perms)
1410{
1411 u32 sid, tsid;
1412
1413 sid = current_sid();
1414 tsid = task_sid(tsk);
1415 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1416}
1417
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001418#if CAP_LAST_CAP > 63
1419#error Fix SELinux to handle capabilities > 63.
1420#endif
1421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422/* Check whether a task is allowed to use a capability. */
Eric Paris6a9de492012-01-03 12:25:14 -05001423static int cred_has_capability(const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001424 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425{
Thomas Liu2bf49692009-07-14 12:14:09 -04001426 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001427 struct selinux_audit_data sad = {0,};
Eric Paris06112162008-11-11 22:02:50 +11001428 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001429 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001430 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001431 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001432 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
Thomas Liu2bf49692009-07-14 12:14:09 -04001434 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001435 ad.selinux_audit_data = &sad;
Eric Paris6a9de492012-01-03 12:25:14 -05001436 ad.tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 ad.u.cap = cap;
1438
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001439 switch (CAP_TO_INDEX(cap)) {
1440 case 0:
1441 sclass = SECCLASS_CAPABILITY;
1442 break;
1443 case 1:
1444 sclass = SECCLASS_CAPABILITY2;
1445 break;
1446 default:
1447 printk(KERN_ERR
1448 "SELinux: out of range capability %d\n", cap);
1449 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001450 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001451 }
Eric Paris06112162008-11-11 22:02:50 +11001452
David Howells275bb412008-11-14 10:39:19 +11001453 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001454 if (audit == SECURITY_CAP_AUDIT) {
1455 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1456 if (rc2)
1457 return rc2;
1458 }
Eric Paris06112162008-11-11 22:02:50 +11001459 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460}
1461
1462/* Check whether a task is allowed to use a system operation. */
1463static int task_has_system(struct task_struct *tsk,
1464 u32 perms)
1465{
David Howells275bb412008-11-14 10:39:19 +11001466 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
David Howells275bb412008-11-14 10:39:19 +11001468 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 SECCLASS_SYSTEM, perms, NULL);
1470}
1471
1472/* Check whether a task has a particular permission to an inode.
1473 The 'adp' parameter is optional and allows other audit
1474 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001475static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 struct inode *inode,
1477 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001478 struct common_audit_data *adp,
1479 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001482 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
David Howellse0e81732009-09-02 09:13:40 +01001484 validate_creds(cred);
1485
Eric Paris828dfe12008-04-17 13:17:49 -04001486 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001487 return 0;
1488
David Howells88e67f32008-11-14 10:39:21 +11001489 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 isec = inode->i_security;
1491
Eric Paris9ade0cf2011-04-25 16:26:29 -04001492 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493}
1494
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001495static int inode_has_perm_noadp(const struct cred *cred,
1496 struct inode *inode,
1497 u32 perms,
1498 unsigned flags)
1499{
1500 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001501 struct selinux_audit_data sad = {0,};
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001502
1503 COMMON_AUDIT_DATA_INIT(&ad, INODE);
1504 ad.u.inode = inode;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001505 ad.selinux_audit_data = &sad;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001506 return inode_has_perm(cred, inode, perms, &ad, flags);
1507}
1508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509/* Same as inode_has_perm, but pass explicit audit data containing
1510 the dentry to help the auditing code to more easily generate the
1511 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001512static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 struct dentry *dentry,
1514 u32 av)
1515{
1516 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001517 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001518 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001519
Eric Paris2875fa02011-04-28 16:04:24 -04001520 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1521 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001522 ad.selinux_audit_data = &sad;
Eric Paris2875fa02011-04-28 16:04:24 -04001523 return inode_has_perm(cred, inode, av, &ad, 0);
1524}
1525
1526/* Same as inode_has_perm, but pass explicit audit data containing
1527 the path to help the auditing code to more easily generate the
1528 pathname if needed. */
1529static inline int path_has_perm(const struct cred *cred,
1530 struct path *path,
1531 u32 av)
1532{
1533 struct inode *inode = path->dentry->d_inode;
1534 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001535 struct selinux_audit_data sad = {0,};
Eric Paris2875fa02011-04-28 16:04:24 -04001536
Eric Parisf48b7392011-04-25 12:54:27 -04001537 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001538 ad.u.path = *path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001539 ad.selinux_audit_data = &sad;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001540 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541}
1542
1543/* Check whether a task can use an open file descriptor to
1544 access an inode in a given way. Check access to the
1545 descriptor itself, and then use dentry_has_perm to
1546 check a particular permission to the file.
1547 Access to the descriptor is implicitly granted if it
1548 has the same SID as the process. If av is zero, then
1549 access to the file is not checked, e.g. for cases
1550 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001551static int file_has_perm(const struct cred *cred,
1552 struct file *file,
1553 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001556 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001557 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001558 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001559 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 int rc;
1561
Eric Parisf48b7392011-04-25 12:54:27 -04001562 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1563 ad.u.path = file->f_path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001564 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
David Howells275bb412008-11-14 10:39:19 +11001566 if (sid != fsec->sid) {
1567 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 SECCLASS_FD,
1569 FD__USE,
1570 &ad);
1571 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001572 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
1574
1575 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001576 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001578 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
David Howells88e67f32008-11-14 10:39:21 +11001580out:
1581 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582}
1583
1584/* Check whether a task can create a file. */
1585static int may_create(struct inode *dir,
1586 struct dentry *dentry,
1587 u16 tclass)
1588{
Paul Moore5fb49872010-04-22 14:46:19 -04001589 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 struct inode_security_struct *dsec;
1591 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001592 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001593 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001594 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 int rc;
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 dsec = dir->i_security;
1598 sbsec = dir->i_sb->s_security;
1599
David Howells275bb412008-11-14 10:39:19 +11001600 sid = tsec->sid;
1601 newsid = tsec->create_sid;
1602
Eric Parisa2694342011-04-25 13:10:27 -04001603 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1604 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001605 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
David Howells275bb412008-11-14 10:39:19 +11001607 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 DIR__ADD_NAME | DIR__SEARCH,
1609 &ad);
1610 if (rc)
1611 return rc;
1612
David P. Quigleycd895962009-01-16 09:22:04 -05001613 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001614 rc = security_transition_sid(sid, dsec->sid, tclass,
1615 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 if (rc)
1617 return rc;
1618 }
1619
David Howells275bb412008-11-14 10:39:19 +11001620 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (rc)
1622 return rc;
1623
Amir Samuelov6a22e462014-05-26 11:44:06 +03001624 rc = avc_has_perm(newsid, sbsec->sid,
1625 SECCLASS_FILESYSTEM,
1626 FILESYSTEM__ASSOCIATE, &ad);
1627 if (rc)
1628 return rc;
1629
1630 rc = pft_inode_mknod(dir, dentry, 0, 0);
1631
1632 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633}
1634
Michael LeMay4eb582c2006-06-26 00:24:57 -07001635/* Check whether a task can create a key. */
1636static int may_create_key(u32 ksid,
1637 struct task_struct *ctx)
1638{
David Howells275bb412008-11-14 10:39:19 +11001639 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001640
David Howells275bb412008-11-14 10:39:19 +11001641 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001642}
1643
Eric Paris828dfe12008-04-17 13:17:49 -04001644#define MAY_LINK 0
1645#define MAY_UNLINK 1
1646#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
1648/* Check whether a task can link, unlink, or rmdir a file/directory. */
1649static int may_link(struct inode *dir,
1650 struct dentry *dentry,
1651 int kind)
1652
1653{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001655 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001656 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001657 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 u32 av;
1659 int rc;
1660
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 dsec = dir->i_security;
1662 isec = dentry->d_inode->i_security;
1663
Eric Parisa2694342011-04-25 13:10:27 -04001664 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1665 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001666 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 av = DIR__SEARCH;
1669 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001670 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (rc)
1672 return rc;
1673
1674 switch (kind) {
1675 case MAY_LINK:
1676 av = FILE__LINK;
1677 break;
1678 case MAY_UNLINK:
1679 av = FILE__UNLINK;
1680 break;
1681 case MAY_RMDIR:
1682 av = DIR__RMDIR;
1683 break;
1684 default:
Eric Paris744ba352008-04-17 11:52:44 -04001685 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1686 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return 0;
1688 }
1689
David Howells275bb412008-11-14 10:39:19 +11001690 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Amir Samuelov6a22e462014-05-26 11:44:06 +03001691 if (rc)
1692 return rc;
1693
1694 if (kind == MAY_UNLINK)
1695 rc = pft_inode_unlink(dir, dentry);
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 return rc;
1698}
1699
1700static inline int may_rename(struct inode *old_dir,
1701 struct dentry *old_dentry,
1702 struct inode *new_dir,
1703 struct dentry *new_dentry)
1704{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001706 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001707 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001708 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 u32 av;
1710 int old_is_dir, new_is_dir;
1711 int rc;
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 old_dsec = old_dir->i_security;
1714 old_isec = old_dentry->d_inode->i_security;
1715 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1716 new_dsec = new_dir->i_security;
1717
Eric Parisa2694342011-04-25 13:10:27 -04001718 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001719 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Eric Parisa2694342011-04-25 13:10:27 -04001721 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001722 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1724 if (rc)
1725 return rc;
David Howells275bb412008-11-14 10:39:19 +11001726 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 old_isec->sclass, FILE__RENAME, &ad);
1728 if (rc)
1729 return rc;
1730 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001731 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 old_isec->sclass, DIR__REPARENT, &ad);
1733 if (rc)
1734 return rc;
1735 }
1736
Eric Parisa2694342011-04-25 13:10:27 -04001737 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 av = DIR__ADD_NAME | DIR__SEARCH;
1739 if (new_dentry->d_inode)
1740 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001741 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 if (rc)
1743 return rc;
1744 if (new_dentry->d_inode) {
1745 new_isec = new_dentry->d_inode->i_security;
1746 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001747 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 new_isec->sclass,
1749 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1750 if (rc)
1751 return rc;
1752 }
1753
1754 return 0;
1755}
1756
1757/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001758static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 struct super_block *sb,
1760 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001761 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001764 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001767 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768}
1769
1770/* Convert a Linux mode and permission mask to an access vector. */
1771static inline u32 file_mask_to_av(int mode, int mask)
1772{
1773 u32 av = 0;
1774
Al Virodba19c62011-07-25 20:49:29 -04001775 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 if (mask & MAY_EXEC)
1777 av |= FILE__EXECUTE;
1778 if (mask & MAY_READ)
1779 av |= FILE__READ;
1780
1781 if (mask & MAY_APPEND)
1782 av |= FILE__APPEND;
1783 else if (mask & MAY_WRITE)
1784 av |= FILE__WRITE;
1785
1786 } else {
1787 if (mask & MAY_EXEC)
1788 av |= DIR__SEARCH;
1789 if (mask & MAY_WRITE)
1790 av |= DIR__WRITE;
1791 if (mask & MAY_READ)
1792 av |= DIR__READ;
1793 }
1794
1795 return av;
1796}
1797
1798/* Convert a Linux file to an access vector. */
1799static inline u32 file_to_av(struct file *file)
1800{
1801 u32 av = 0;
1802
1803 if (file->f_mode & FMODE_READ)
1804 av |= FILE__READ;
1805 if (file->f_mode & FMODE_WRITE) {
1806 if (file->f_flags & O_APPEND)
1807 av |= FILE__APPEND;
1808 else
1809 av |= FILE__WRITE;
1810 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001811 if (!av) {
1812 /*
1813 * Special file opened with flags 3 for ioctl-only use.
1814 */
1815 av = FILE__IOCTL;
1816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818 return av;
1819}
1820
Eric Paris8b6a5a32008-10-29 17:06:46 -04001821/*
1822 * Convert a file to an access vector and include the correct open
1823 * open permission.
1824 */
1825static inline u32 open_file_to_av(struct file *file)
1826{
1827 u32 av = file_to_av(file);
1828
Eric Paris49b7b8d2010-07-23 11:44:09 -04001829 if (selinux_policycap_openperm)
1830 av |= FILE__OPEN;
1831
Eric Paris8b6a5a32008-10-29 17:06:46 -04001832 return av;
1833}
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835/* Hook functions begin here. */
1836
Stephen Smalley48a23702012-11-05 08:15:34 -05001837static int selinux_binder_set_context_mgr(struct task_struct *mgr)
1838{
1839 u32 mysid = current_sid();
1840 u32 mgrsid = task_sid(mgr);
1841
1842 return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
1843}
1844
1845static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
1846{
1847 u32 mysid = current_sid();
1848 u32 fromsid = task_sid(from);
1849 u32 tosid = task_sid(to);
1850 int rc;
1851
1852 if (mysid != fromsid) {
1853 rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
1854 if (rc)
1855 return rc;
1856 }
1857
1858 return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
1859}
1860
1861static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
1862{
1863 u32 fromsid = task_sid(from);
1864 u32 tosid = task_sid(to);
1865 return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
1866}
1867
1868static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
1869{
1870 u32 sid = task_sid(to);
1871 struct file_security_struct *fsec = file->f_security;
1872 struct inode *inode = file->f_path.dentry->d_inode;
1873 struct inode_security_struct *isec = inode->i_security;
1874 struct common_audit_data ad;
1875 struct selinux_audit_data sad = {0,};
1876 int rc;
1877
1878 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1879 ad.u.path = file->f_path;
1880 ad.selinux_audit_data = &sad;
1881
1882 if (sid != fsec->sid) {
1883 rc = avc_has_perm(sid, fsec->sid,
1884 SECCLASS_FD,
1885 FD__USE,
1886 &ad);
1887 if (rc)
1888 return rc;
1889 }
1890
1891 if (unlikely(IS_PRIVATE(inode)))
1892 return 0;
1893
1894 return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
1895 &ad);
1896}
1897
Ingo Molnar9e488582009-05-07 19:26:19 +10001898static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001899 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 int rc;
1902
Ingo Molnar9e488582009-05-07 19:26:19 +10001903 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 if (rc)
1905 return rc;
1906
Eric Paris69f594a2012-01-03 12:25:15 -05001907 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001908 u32 sid = current_sid();
1909 u32 csid = task_sid(child);
1910 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001911 }
1912
David Howells3b11a1d2008-11-14 10:39:26 +11001913 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001914}
1915
1916static int selinux_ptrace_traceme(struct task_struct *parent)
1917{
1918 int rc;
1919
Eric Paris200ac532009-02-12 15:01:04 -05001920 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001921 if (rc)
1922 return rc;
1923
1924 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925}
1926
1927static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001928 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
1930 int error;
1931
David Howells3b11a1d2008-11-14 10:39:26 +11001932 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 if (error)
1934 return error;
1935
Eric Paris200ac532009-02-12 15:01:04 -05001936 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937}
1938
David Howellsd84f4f92008-11-14 10:39:23 +11001939static int selinux_capset(struct cred *new, const struct cred *old,
1940 const kernel_cap_t *effective,
1941 const kernel_cap_t *inheritable,
1942 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944 int error;
1945
Eric Paris200ac532009-02-12 15:01:04 -05001946 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001947 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 if (error)
1949 return error;
1950
David Howellsd84f4f92008-11-14 10:39:23 +11001951 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952}
1953
James Morris5626d3e2009-01-30 10:05:06 +11001954/*
1955 * (This comment used to live with the selinux_task_setuid hook,
1956 * which was removed).
1957 *
1958 * Since setuid only affects the current process, and since the SELinux
1959 * controls are not based on the Linux identity attributes, SELinux does not
1960 * need to control this operation. However, SELinux does control the use of
1961 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1962 */
1963
Eric Paris6a9de492012-01-03 12:25:14 -05001964static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1965 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
1967 int rc;
1968
Eric Paris6a9de492012-01-03 12:25:14 -05001969 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 if (rc)
1971 return rc;
1972
Eric Paris6a9de492012-01-03 12:25:14 -05001973 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974}
1975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1977{
David Howells88e67f32008-11-14 10:39:21 +11001978 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 int rc = 0;
1980
1981 if (!sb)
1982 return 0;
1983
1984 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001985 case Q_SYNC:
1986 case Q_QUOTAON:
1987 case Q_QUOTAOFF:
1988 case Q_SETINFO:
1989 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001990 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001991 break;
1992 case Q_GETFMT:
1993 case Q_GETINFO:
1994 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001995 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001996 break;
1997 default:
1998 rc = 0; /* let the kernel handle invalid cmds */
1999 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 }
2001 return rc;
2002}
2003
2004static int selinux_quota_on(struct dentry *dentry)
2005{
David Howells88e67f32008-11-14 10:39:21 +11002006 const struct cred *cred = current_cred();
2007
Eric Paris2875fa02011-04-28 16:04:24 -04002008 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009}
2010
Eric Paris12b30522010-11-15 18:36:29 -05002011static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012{
2013 int rc;
2014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08002016 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
2017 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04002018 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
2019 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08002020 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
2021 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
2022 /* Set level of messages printed to console */
2023 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04002024 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
2025 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08002026 case SYSLOG_ACTION_CLOSE: /* Close log */
2027 case SYSLOG_ACTION_OPEN: /* Open log */
2028 case SYSLOG_ACTION_READ: /* Read from log */
2029 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
2030 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04002031 default:
2032 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2033 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 }
2035 return rc;
2036}
2037
2038/*
2039 * Check that a process has enough memory to allocate a new virtual
2040 * mapping. 0 means there is enough memory for the allocation to
2041 * succeed and -ENOMEM implies there is not.
2042 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 * Do not audit the selinux permission check, as this is applied to all
2044 * processes that allocate mappings.
2045 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002046static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047{
2048 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Eric Paris6a9de492012-01-03 12:25:14 -05002050 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002051 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 if (rc == 0)
2053 cap_sys_admin = 1;
2054
Alan Cox34b4e4a2007-08-22 14:01:28 -07002055 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056}
2057
2058/* binprm security operations */
2059
David Howellsa6f76f22008-11-14 10:39:24 +11002060static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061{
David Howellsa6f76f22008-11-14 10:39:24 +11002062 const struct task_security_struct *old_tsec;
2063 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002065 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002066 struct selinux_audit_data sad = {0,};
David Howellsa6f76f22008-11-14 10:39:24 +11002067 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 int rc;
2069
Eric Paris200ac532009-02-12 15:01:04 -05002070 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 if (rc)
2072 return rc;
2073
David Howellsa6f76f22008-11-14 10:39:24 +11002074 /* SELinux context only depends on initial program or script and not
2075 * the script interpreter */
2076 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 return 0;
2078
David Howellsa6f76f22008-11-14 10:39:24 +11002079 old_tsec = current_security();
2080 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 isec = inode->i_security;
2082
2083 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002084 new_tsec->sid = old_tsec->sid;
2085 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Michael LeMay28eba5b2006-06-27 02:53:42 -07002087 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002088 new_tsec->create_sid = 0;
2089 new_tsec->keycreate_sid = 0;
2090 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
David Howellsa6f76f22008-11-14 10:39:24 +11002092 if (old_tsec->exec_sid) {
2093 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002095 new_tsec->exec_sid = 0;
Andy Lutomirski397a85e2012-01-30 08:17:26 -08002096
2097 /*
2098 * Minimize confusion: if no_new_privs and a transition is
2099 * explicitly requested, then fail the exec.
2100 */
2101 if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
2102 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 } else {
2104 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002105 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002106 SECCLASS_PROCESS, NULL,
2107 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 if (rc)
2109 return rc;
2110 }
2111
Eric Parisf48b7392011-04-25 12:54:27 -04002112 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002113 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002114 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Andy Lutomirski397a85e2012-01-30 08:17:26 -08002116 if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
2117 (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
David Howellsa6f76f22008-11-14 10:39:24 +11002118 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
David Howellsa6f76f22008-11-14 10:39:24 +11002120 if (new_tsec->sid == old_tsec->sid) {
2121 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2123 if (rc)
2124 return rc;
2125 } else {
2126 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002127 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2129 if (rc)
2130 return rc;
2131
David Howellsa6f76f22008-11-14 10:39:24 +11002132 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2134 if (rc)
2135 return rc;
2136
David Howellsa6f76f22008-11-14 10:39:24 +11002137 /* Check for shared state */
2138 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2139 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2140 SECCLASS_PROCESS, PROCESS__SHARE,
2141 NULL);
2142 if (rc)
2143 return -EPERM;
2144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
David Howellsa6f76f22008-11-14 10:39:24 +11002146 /* Make sure that anyone attempting to ptrace over a task that
2147 * changes its SID has the appropriate permit */
2148 if (bprm->unsafe &
2149 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2150 struct task_struct *tracer;
2151 struct task_security_struct *sec;
2152 u32 ptsid = 0;
2153
2154 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002155 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002156 if (likely(tracer != NULL)) {
2157 sec = __task_cred(tracer)->security;
2158 ptsid = sec->sid;
2159 }
2160 rcu_read_unlock();
2161
2162 if (ptsid != 0) {
2163 rc = avc_has_perm(ptsid, new_tsec->sid,
2164 SECCLASS_PROCESS,
2165 PROCESS__PTRACE, NULL);
2166 if (rc)
2167 return -EPERM;
2168 }
2169 }
2170
2171 /* Clear any possibly unsafe personality bits on exec: */
2172 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 }
2174
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 return 0;
2176}
2177
Eric Paris828dfe12008-04-17 13:17:49 -04002178static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179{
Paul Moore5fb49872010-04-22 14:46:19 -04002180 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002181 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 int atsecure = 0;
2183
David Howells275bb412008-11-14 10:39:19 +11002184 sid = tsec->sid;
2185 osid = tsec->osid;
2186
2187 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 /* Enable secure mode for SIDs transitions unless
2189 the noatsecure permission is granted between
2190 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002191 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002192 SECCLASS_PROCESS,
2193 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 }
2195
Eric Paris200ac532009-02-12 15:01:04 -05002196 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197}
2198
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002200static inline void flush_unauthorized_files(const struct cred *cred,
2201 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202{
Thomas Liu2bf49692009-07-14 12:14:09 -04002203 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002204 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002206 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002207 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002209 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002211 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002213 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002214 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002215 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002216 struct inode *inode;
2217
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 /* Revalidate access to controlling tty.
2219 Use inode_has_perm on the tty inode directly rather
2220 than using file_has_perm, as this particular open
2221 file may belong to another process and we are only
2222 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002223 file_priv = list_first_entry(&tty->tty_files,
2224 struct tty_file_private, list);
2225 file = file_priv->file;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002226 inode = file->f_path.dentry->d_inode;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07002227 if (inode_has_perm_noadp(cred, inode,
2228 FILE__READ | FILE__WRITE, 0)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002229 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 }
2231 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002232 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002233 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002235 /* Reset controlling tty. */
2236 if (drop_tty)
2237 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 /* Revalidate access to inherited open files. */
2240
Eric Parisf48b7392011-04-25 12:54:27 -04002241 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002242 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
2244 spin_lock(&files->file_lock);
2245 for (;;) {
2246 unsigned long set, i;
2247 int fd;
2248
2249 j++;
2250 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002251 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002252 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 break;
David Howells1fd36ad2012-02-16 17:49:54 +00002254 set = fdt->open_fds[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 if (!set)
2256 continue;
2257 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002258 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if (set & 1) {
2260 file = fget(i);
2261 if (!file)
2262 continue;
David Howells88e67f32008-11-14 10:39:21 +11002263 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 file,
2265 file_to_av(file))) {
2266 sys_close(i);
2267 fd = get_unused_fd();
2268 if (fd != i) {
2269 if (fd >= 0)
2270 put_unused_fd(fd);
2271 fput(file);
2272 continue;
2273 }
2274 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002275 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 } else {
David Howells745ca242008-11-14 10:39:22 +11002277 devnull = dentry_open(
2278 dget(selinux_null),
2279 mntget(selinuxfs_mount),
2280 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002281 if (IS_ERR(devnull)) {
2282 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 put_unused_fd(fd);
2284 fput(file);
2285 continue;
2286 }
2287 }
2288 fd_install(fd, devnull);
2289 }
2290 fput(file);
2291 }
2292 }
2293 spin_lock(&files->file_lock);
2294
2295 }
2296 spin_unlock(&files->file_lock);
2297}
2298
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299/*
David Howellsa6f76f22008-11-14 10:39:24 +11002300 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 */
David Howellsa6f76f22008-11-14 10:39:24 +11002302static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303{
David Howellsa6f76f22008-11-14 10:39:24 +11002304 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 int rc, i;
2307
David Howellsa6f76f22008-11-14 10:39:24 +11002308 new_tsec = bprm->cred->security;
2309 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 return;
2311
2312 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002313 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
David Howellsa6f76f22008-11-14 10:39:24 +11002315 /* Always clear parent death signal on SID transitions. */
2316 current->pdeath_signal = 0;
2317
2318 /* Check whether the new SID can inherit resource limits from the old
2319 * SID. If not, reset all soft limits to the lower of the current
2320 * task's hard limit and the init task's soft limit.
2321 *
2322 * Note that the setting of hard limits (even to lower them) can be
2323 * controlled by the setrlimit check. The inclusion of the init task's
2324 * soft limit into the computation is to avoid resetting soft limits
2325 * higher than the default soft limit for cases where the default is
2326 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2327 */
2328 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2329 PROCESS__RLIMITINH, NULL);
2330 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002331 /* protect against do_prlimit() */
2332 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002333 for (i = 0; i < RLIM_NLIMITS; i++) {
2334 rlim = current->signal->rlim + i;
2335 initrlim = init_task.signal->rlim + i;
2336 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2337 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002338 task_unlock(current);
2339 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002340 }
2341}
2342
2343/*
2344 * Clean up the process immediately after the installation of new credentials
2345 * due to exec
2346 */
2347static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2348{
2349 const struct task_security_struct *tsec = current_security();
2350 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002351 u32 osid, sid;
2352 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002353
David Howellsa6f76f22008-11-14 10:39:24 +11002354 osid = tsec->osid;
2355 sid = tsec->sid;
2356
2357 if (sid == osid)
2358 return;
2359
2360 /* Check whether the new SID can inherit signal state from the old SID.
2361 * If not, clear itimers to avoid subsequent signal generation and
2362 * flush and unblock signals.
2363 *
2364 * This must occur _after_ the task SID has been updated so that any
2365 * kill done after the flush will be checked against the new SID.
2366 */
2367 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if (rc) {
2369 memset(&itimer, 0, sizeof itimer);
2370 for (i = 0; i < 3; i++)
2371 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002373 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2374 __flush_signals(current);
2375 flush_signal_handlers(current, 1);
2376 sigemptyset(&current->blocked);
2377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 spin_unlock_irq(&current->sighand->siglock);
2379 }
2380
David Howellsa6f76f22008-11-14 10:39:24 +11002381 /* Wake up the parent if it is waiting so that it can recheck
2382 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002383 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002384 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002385 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386}
2387
2388/* superblock security operations */
2389
2390static int selinux_sb_alloc_security(struct super_block *sb)
2391{
2392 return superblock_alloc_security(sb);
2393}
2394
2395static void selinux_sb_free_security(struct super_block *sb)
2396{
2397 superblock_free_security(sb);
2398}
2399
2400static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2401{
2402 if (plen > olen)
2403 return 0;
2404
2405 return !memcmp(prefix, option, plen);
2406}
2407
2408static inline int selinux_option(char *option, int len)
2409{
Eric Paris832cbd92008-04-01 13:24:09 -04002410 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2411 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2412 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002413 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2414 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415}
2416
2417static inline void take_option(char **to, char *from, int *first, int len)
2418{
2419 if (!*first) {
2420 **to = ',';
2421 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002422 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 *first = 0;
2424 memcpy(*to, from, len);
2425 *to += len;
2426}
2427
Eric Paris828dfe12008-04-17 13:17:49 -04002428static inline void take_selinux_option(char **to, char *from, int *first,
2429 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002430{
2431 int current_size = 0;
2432
2433 if (!*first) {
2434 **to = '|';
2435 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002436 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002437 *first = 0;
2438
2439 while (current_size < len) {
2440 if (*from != '"') {
2441 **to = *from;
2442 *to += 1;
2443 }
2444 from += 1;
2445 current_size += 1;
2446 }
2447}
2448
Eric Parise0007522008-03-05 10:31:54 -05002449static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
2451 int fnosec, fsec, rc = 0;
2452 char *in_save, *in_curr, *in_end;
2453 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002454 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 in_curr = orig;
2457 sec_curr = copy;
2458
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2460 if (!nosec) {
2461 rc = -ENOMEM;
2462 goto out;
2463 }
2464
2465 nosec_save = nosec;
2466 fnosec = fsec = 1;
2467 in_save = in_end = orig;
2468
2469 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002470 if (*in_end == '"')
2471 open_quote = !open_quote;
2472 if ((*in_end == ',' && open_quote == 0) ||
2473 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 int len = in_end - in_curr;
2475
2476 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002477 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 else
2479 take_option(&nosec, in_curr, &fnosec, len);
2480
2481 in_curr = in_end + 1;
2482 }
2483 } while (*in_end++);
2484
Eric Paris6931dfc2005-06-30 02:58:51 -07002485 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002486 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487out:
2488 return rc;
2489}
2490
Eric Paris026eb162011-03-03 16:09:14 -05002491static int selinux_sb_remount(struct super_block *sb, void *data)
2492{
2493 int rc, i, *flags;
2494 struct security_mnt_opts opts;
2495 char *secdata, **mount_options;
2496 struct superblock_security_struct *sbsec = sb->s_security;
2497
2498 if (!(sbsec->flags & SE_SBINITIALIZED))
2499 return 0;
2500
2501 if (!data)
2502 return 0;
2503
2504 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2505 return 0;
2506
2507 security_init_mnt_opts(&opts);
2508 secdata = alloc_secdata();
2509 if (!secdata)
2510 return -ENOMEM;
2511 rc = selinux_sb_copy_data(data, secdata);
2512 if (rc)
2513 goto out_free_secdata;
2514
2515 rc = selinux_parse_opts_str(secdata, &opts);
2516 if (rc)
2517 goto out_free_secdata;
2518
2519 mount_options = opts.mnt_opts;
2520 flags = opts.mnt_opts_flags;
2521
2522 for (i = 0; i < opts.num_mnt_opts; i++) {
2523 u32 sid;
2524 size_t len;
2525
2526 if (flags[i] == SE_SBLABELSUPP)
2527 continue;
2528 len = strlen(mount_options[i]);
2529 rc = security_context_to_sid(mount_options[i], len, &sid);
2530 if (rc) {
2531 printk(KERN_WARNING "SELinux: security_context_to_sid"
2532 "(%s) failed for (dev %s, type %s) errno=%d\n",
2533 mount_options[i], sb->s_id, sb->s_type->name, rc);
2534 goto out_free_opts;
2535 }
2536 rc = -EINVAL;
2537 switch (flags[i]) {
2538 case FSCONTEXT_MNT:
2539 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2540 goto out_bad_option;
2541 break;
2542 case CONTEXT_MNT:
2543 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2544 goto out_bad_option;
2545 break;
2546 case ROOTCONTEXT_MNT: {
2547 struct inode_security_struct *root_isec;
2548 root_isec = sb->s_root->d_inode->i_security;
2549
2550 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2551 goto out_bad_option;
2552 break;
2553 }
2554 case DEFCONTEXT_MNT:
2555 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2556 goto out_bad_option;
2557 break;
2558 default:
2559 goto out_free_opts;
2560 }
2561 }
2562
2563 rc = 0;
2564out_free_opts:
2565 security_free_mnt_opts(&opts);
2566out_free_secdata:
2567 free_secdata(secdata);
2568 return rc;
2569out_bad_option:
2570 printk(KERN_WARNING "SELinux: unable to change security options "
2571 "during remount (dev %s, type=%s)\n", sb->s_id,
2572 sb->s_type->name);
2573 goto out_free_opts;
2574}
2575
James Morris12204e22008-12-19 10:44:42 +11002576static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577{
David Howells88e67f32008-11-14 10:39:21 +11002578 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002579 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002580 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 int rc;
2582
2583 rc = superblock_doinit(sb, data);
2584 if (rc)
2585 return rc;
2586
James Morris74192242008-12-19 11:41:10 +11002587 /* Allow all mounts performed by the kernel */
2588 if (flags & MS_KERNMOUNT)
2589 return 0;
2590
Eric Parisa2694342011-04-25 13:10:27 -04002591 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002592 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002593 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002594 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595}
2596
David Howells726c3342006-06-23 02:02:58 -07002597static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598{
David Howells88e67f32008-11-14 10:39:21 +11002599 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002600 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002601 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602
Eric Parisa2694342011-04-25 13:10:27 -04002603 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002604 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002605 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002606 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607}
2608
Eric Paris828dfe12008-04-17 13:17:49 -04002609static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002610 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002611 char *type,
2612 unsigned long flags,
2613 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614{
David Howells88e67f32008-11-14 10:39:21 +11002615 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
2617 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002618 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002619 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 else
Eric Paris2875fa02011-04-28 16:04:24 -04002621 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622}
2623
2624static int selinux_umount(struct vfsmount *mnt, int flags)
2625{
David Howells88e67f32008-11-14 10:39:21 +11002626 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
David Howells88e67f32008-11-14 10:39:21 +11002628 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002629 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630}
2631
2632/* inode security operations */
2633
2634static int selinux_inode_alloc_security(struct inode *inode)
2635{
2636 return inode_alloc_security(inode);
2637}
2638
2639static void selinux_inode_free_security(struct inode *inode)
2640{
2641 inode_free_security(inode);
2642}
2643
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002644static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002645 const struct qstr *qstr, char **name,
2646 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002647{
Paul Moore5fb49872010-04-22 14:46:19 -04002648 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002649 struct inode_security_struct *dsec;
2650 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002651 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002652 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002653 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002654
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002655 dsec = dir->i_security;
2656 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002657
David Howells275bb412008-11-14 10:39:19 +11002658 sid = tsec->sid;
2659 newsid = tsec->create_sid;
2660
Eric Paris415103f2010-12-02 16:13:40 -05002661 if ((sbsec->flags & SE_SBINITIALIZED) &&
2662 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2663 newsid = sbsec->mntpoint_sid;
2664 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002665 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002666 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002667 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002668 if (rc) {
2669 printk(KERN_WARNING "%s: "
2670 "security_transition_sid failed, rc=%d (dev=%s "
2671 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002672 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002673 -rc, inode->i_sb->s_id, inode->i_ino);
2674 return rc;
2675 }
2676 }
2677
Eric Paris296fddf2006-09-25 23:32:00 -07002678 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002679 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002680 struct inode_security_struct *isec = inode->i_security;
2681 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2682 isec->sid = newsid;
2683 isec->initialized = 1;
2684 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002685
David P. Quigleycd895962009-01-16 09:22:04 -05002686 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002687 return -EOPNOTSUPP;
2688
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002689 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002690 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002691 if (!namep)
2692 return -ENOMEM;
2693 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002694 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002695
2696 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002697 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002698 if (rc) {
2699 kfree(namep);
2700 return rc;
2701 }
2702 *value = context;
2703 *len = clen;
2704 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002705
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002706 return 0;
2707}
2708
Al Viro4acdaf22011-07-26 01:42:34 -04002709static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710{
Amir Samuelov6a22e462014-05-26 11:44:06 +03002711 int ret;
2712
2713 ret = pft_inode_create(dir, dentry, mode);
2714 if (ret < 0)
2715 return ret;
2716
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return may_create(dir, dentry, SECCLASS_FILE);
2718}
2719
Amir Samuelov6a22e462014-05-26 11:44:06 +03002720static int selinux_inode_post_create(struct inode *dir, struct dentry *dentry,
2721 umode_t mode)
2722{
2723 int ret;
2724
2725 ret = pft_inode_post_create(dir, dentry, mode);
2726
2727 return ret;
2728}
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2731{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return may_link(dir, old_dentry, MAY_LINK);
2733}
2734
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2736{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 return may_link(dir, dentry, MAY_UNLINK);
2738}
2739
2740static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2741{
2742 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2743}
2744
Al Viro18bb1db2011-07-26 01:41:39 -04002745static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746{
2747 return may_create(dir, dentry, SECCLASS_DIR);
2748}
2749
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2751{
2752 return may_link(dir, dentry, MAY_RMDIR);
2753}
2754
Al Viro1a67aaf2011-07-26 01:52:52 -04002755static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2758}
2759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002761 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762{
Amir Samuelov6a22e462014-05-26 11:44:06 +03002763 int rc;
2764
2765 rc = pft_inode_rename(old_inode, old_dentry, new_inode, new_dentry);
2766 if (rc)
2767 return rc;
2768
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2770}
2771
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772static int selinux_inode_readlink(struct dentry *dentry)
2773{
David Howells88e67f32008-11-14 10:39:21 +11002774 const struct cred *cred = current_cred();
2775
Eric Paris2875fa02011-04-28 16:04:24 -04002776 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777}
2778
2779static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2780{
David Howells88e67f32008-11-14 10:39:21 +11002781 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Eric Paris2875fa02011-04-28 16:04:24 -04002783 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784}
2785
Al Viroe74f71e2011-06-20 19:38:15 -04002786static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787{
David Howells88e67f32008-11-14 10:39:21 +11002788 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002789 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002790 struct selinux_audit_data sad = {0,};
Eric Parisb782e0a2010-07-23 11:44:03 -04002791 u32 perms;
2792 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002793 unsigned flags = mask & MAY_NOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
Eric Parisb782e0a2010-07-23 11:44:03 -04002795 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002796 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2797
Eric Parisb782e0a2010-07-23 11:44:03 -04002798 /* No permission to check. Existence test. */
2799 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Eric Parisf48b7392011-04-25 12:54:27 -04002802 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002803 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002804 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002805
2806 if (from_access)
Eric Paris3b3b0e42012-04-03 09:37:02 -07002807 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
Eric Parisb782e0a2010-07-23 11:44:03 -04002808
2809 perms = file_mask_to_av(inode->i_mode, mask);
2810
Eric Paris9ade0cf2011-04-25 16:26:29 -04002811 return inode_has_perm(cred, inode, perms, &ad, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812}
2813
2814static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2815{
David Howells88e67f32008-11-14 10:39:21 +11002816 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002817 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002819 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2820 if (ia_valid & ATTR_FORCE) {
2821 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2822 ATTR_FORCE);
2823 if (!ia_valid)
2824 return 0;
2825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002827 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2828 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002829 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
Eric Paris2875fa02011-04-28 16:04:24 -04002831 return dentry_has_perm(cred, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832}
2833
2834static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2835{
David Howells88e67f32008-11-14 10:39:21 +11002836 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002837 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002838
Eric Paris2875fa02011-04-28 16:04:24 -04002839 path.dentry = dentry;
2840 path.mnt = mnt;
2841
2842 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843}
2844
David Howells8f0cfa52008-04-29 00:59:41 -07002845static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002846{
David Howells88e67f32008-11-14 10:39:21 +11002847 const struct cred *cred = current_cred();
2848
Amir Samuelov6a22e462014-05-26 11:44:06 +03002849 if (pft_inode_set_xattr(dentry, name) < 0)
2850 return -EACCES;
2851
2852
Serge E. Hallynb5376772007-10-16 23:31:36 -07002853 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2854 sizeof XATTR_SECURITY_PREFIX - 1)) {
2855 if (!strcmp(name, XATTR_NAME_CAPS)) {
2856 if (!capable(CAP_SETFCAP))
2857 return -EPERM;
2858 } else if (!capable(CAP_SYS_ADMIN)) {
2859 /* A different attribute in the security namespace.
2860 Restrict to administrator. */
2861 return -EPERM;
2862 }
2863 }
2864
2865 /* Not an attribute we recognize, so just check the
2866 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002867 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002868}
2869
David Howells8f0cfa52008-04-29 00:59:41 -07002870static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2871 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 struct inode *inode = dentry->d_inode;
2874 struct inode_security_struct *isec = inode->i_security;
2875 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002876 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002877 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11002878 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 int rc = 0;
2880
Serge E. Hallynb5376772007-10-16 23:31:36 -07002881 if (strcmp(name, XATTR_NAME_SELINUX))
2882 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002885 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 return -EOPNOTSUPP;
2887
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002888 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 return -EPERM;
2890
Eric Parisa2694342011-04-25 13:10:27 -04002891 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002892 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002893 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
David Howells275bb412008-11-14 10:39:19 +11002895 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 FILE__RELABELFROM, &ad);
2897 if (rc)
2898 return rc;
2899
2900 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002901 if (rc == -EINVAL) {
2902 if (!capable(CAP_MAC_ADMIN))
2903 return rc;
2904 rc = security_context_to_sid_force(value, size, &newsid);
2905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 if (rc)
2907 return rc;
2908
David Howells275bb412008-11-14 10:39:19 +11002909 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 FILE__RELABELTO, &ad);
2911 if (rc)
2912 return rc;
2913
David Howells275bb412008-11-14 10:39:19 +11002914 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002915 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 if (rc)
2917 return rc;
2918
2919 return avc_has_perm(newsid,
2920 sbsec->sid,
2921 SECCLASS_FILESYSTEM,
2922 FILESYSTEM__ASSOCIATE,
2923 &ad);
2924}
2925
David Howells8f0cfa52008-04-29 00:59:41 -07002926static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002927 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002928 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929{
2930 struct inode *inode = dentry->d_inode;
2931 struct inode_security_struct *isec = inode->i_security;
2932 u32 newsid;
2933 int rc;
2934
2935 if (strcmp(name, XATTR_NAME_SELINUX)) {
2936 /* Not an attribute we recognize, so nothing to do. */
2937 return;
2938 }
2939
Stephen Smalley12b29f32008-05-07 13:03:20 -04002940 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002942 printk(KERN_ERR "SELinux: unable to map context to SID"
2943 "for (%s, %lu), rc=%d\n",
2944 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 return;
2946 }
2947
2948 isec->sid = newsid;
2949 return;
2950}
2951
David Howells8f0cfa52008-04-29 00:59:41 -07002952static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953{
David Howells88e67f32008-11-14 10:39:21 +11002954 const struct cred *cred = current_cred();
2955
Eric Paris2875fa02011-04-28 16:04:24 -04002956 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957}
2958
Eric Paris828dfe12008-04-17 13:17:49 -04002959static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960{
David Howells88e67f32008-11-14 10:39:21 +11002961 const struct cred *cred = current_cred();
2962
Eric Paris2875fa02011-04-28 16:04:24 -04002963 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964}
2965
David Howells8f0cfa52008-04-29 00:59:41 -07002966static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002968 if (strcmp(name, XATTR_NAME_SELINUX))
2969 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971 /* No one is allowed to remove a SELinux security label.
2972 You can change the label, but all data must be labeled. */
2973 return -EACCES;
2974}
2975
James Morrisd381d8a2005-10-30 14:59:22 -08002976/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002977 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002978 *
2979 * Permission check is handled by selinux_inode_getxattr hook.
2980 */
David P. Quigley42492592008-02-04 22:29:39 -08002981static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982{
David P. Quigley42492592008-02-04 22:29:39 -08002983 u32 size;
2984 int error;
2985 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002988 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2989 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002991 /*
2992 * If the caller has CAP_MAC_ADMIN, then get the raw context
2993 * value even if it is not defined by current policy; otherwise,
2994 * use the in-core value under current policy.
2995 * Use the non-auditing forms of the permission checks since
2996 * getxattr may be called by unprivileged processes commonly
2997 * and lack of permission just means that we fall back to the
2998 * in-core context value, not a denial.
2999 */
Eric Paris6a9de492012-01-03 12:25:14 -05003000 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00003001 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04003002 if (!error)
3003 error = security_sid_to_context_force(isec->sid, &context,
3004 &size);
3005 else
3006 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08003007 if (error)
3008 return error;
3009 error = size;
3010 if (alloc) {
3011 *buffer = context;
3012 goto out_nofree;
3013 }
3014 kfree(context);
3015out_nofree:
3016 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017}
3018
3019static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04003020 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021{
3022 struct inode_security_struct *isec = inode->i_security;
3023 u32 newsid;
3024 int rc;
3025
3026 if (strcmp(name, XATTR_SELINUX_SUFFIX))
3027 return -EOPNOTSUPP;
3028
3029 if (!value || !size)
3030 return -EACCES;
3031
Eric Paris828dfe12008-04-17 13:17:49 -04003032 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 if (rc)
3034 return rc;
3035
3036 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04003037 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return 0;
3039}
3040
3041static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
3042{
3043 const int len = sizeof(XATTR_NAME_SELINUX);
3044 if (buffer && len <= buffer_size)
3045 memcpy(buffer, XATTR_NAME_SELINUX, len);
3046 return len;
3047}
3048
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02003049static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
3050{
3051 struct inode_security_struct *isec = inode->i_security;
3052 *secid = isec->sid;
3053}
3054
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055/* file security operations */
3056
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003057static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058{
David Howells88e67f32008-11-14 10:39:21 +11003059 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08003060 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
3063 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
3064 mask |= MAY_APPEND;
3065
Paul Moore389fb802009-03-27 17:10:34 -04003066 return file_has_perm(cred, file,
3067 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068}
3069
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003070static int selinux_file_permission(struct file *file, int mask)
3071{
Stephen Smalley20dda182009-06-22 14:54:53 -04003072 struct inode *inode = file->f_path.dentry->d_inode;
3073 struct file_security_struct *fsec = file->f_security;
3074 struct inode_security_struct *isec = inode->i_security;
3075 u32 sid = current_sid();
Amir Samuelov6a22e462014-05-26 11:44:06 +03003076 int ret;
Stephen Smalley20dda182009-06-22 14:54:53 -04003077
Paul Moore389fb802009-03-27 17:10:34 -04003078 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003079 /* No permission to check. Existence test. */
3080 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003081
Amir Samuelov6a22e462014-05-26 11:44:06 +03003082 ret = pft_file_permission(file, mask);
3083 if (ret < 0)
3084 return ret;
3085
Stephen Smalley20dda182009-06-22 14:54:53 -04003086 if (sid == fsec->sid && fsec->isid == isec->sid &&
3087 fsec->pseqno == avc_policy_seqno())
3088 /* No change since dentry_open check. */
3089 return 0;
3090
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003091 return selinux_revalidate_file_permission(file, mask);
3092}
3093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094static int selinux_file_alloc_security(struct file *file)
3095{
3096 return file_alloc_security(file);
3097}
3098
3099static void selinux_file_free_security(struct file *file)
3100{
3101 file_free_security(file);
3102}
3103
Jeff Vander Stoep581be712015-07-10 17:19:56 -04003104/*
3105 * Check whether a task has the ioctl permission and cmd
3106 * operation to an inode.
3107 */
3108int ioctl_has_perm(const struct cred *cred, struct file *file,
3109 u32 requested, u16 cmd)
3110{
3111 struct common_audit_data ad;
3112 struct file_security_struct *fsec = file->f_security;
3113 struct inode *inode = file->f_path.dentry->d_inode;
3114 struct inode_security_struct *isec = inode->i_security;
3115 struct lsm_ioctlop_audit ioctl;
3116 u32 ssid = cred_sid(cred);
3117 struct selinux_audit_data sad = {0,};
3118 int rc;
3119 u8 driver = cmd >> 8;
3120 u8 xperm = cmd & 0xff;
3121
3122 COMMON_AUDIT_DATA_INIT(&ad, IOCTL_OP);
3123 ad.u.op = &ioctl;
3124 ad.u.op->cmd = cmd;
3125 ad.selinux_audit_data = &sad;
3126 ad.u.op->path = file->f_path;
3127
3128 if (ssid != fsec->sid) {
3129 rc = avc_has_perm(ssid, fsec->sid,
3130 SECCLASS_FD,
3131 FD__USE,
3132 &ad);
3133 if (rc)
3134 goto out;
3135 }
3136
3137 if (unlikely(IS_PRIVATE(inode)))
3138 return 0;
3139
3140 rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
3141 requested, driver, xperm, &ad);
3142out:
3143 return rc;
3144}
3145
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3147 unsigned long arg)
3148{
David Howells88e67f32008-11-14 10:39:21 +11003149 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05003150 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
Eric Paris0b24dcb2011-02-25 15:39:20 -05003152 switch (cmd) {
3153 case FIONREAD:
3154 /* fall through */
3155 case FIBMAP:
3156 /* fall through */
3157 case FIGETBSZ:
3158 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003159 case FS_IOC_GETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003160 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003161 case FS_IOC_GETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003162 error = file_has_perm(cred, file, FILE__GETATTR);
3163 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
Al Viro2f99c362012-03-23 16:04:05 -04003165 case FS_IOC_SETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003166 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003167 case FS_IOC_SETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003168 error = file_has_perm(cred, file, FILE__SETATTR);
3169 break;
3170
3171 /* sys_ioctl() checks */
3172 case FIONBIO:
3173 /* fall through */
3174 case FIOASYNC:
3175 error = file_has_perm(cred, file, 0);
3176 break;
3177
3178 case KDSKBENT:
3179 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05003180 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3181 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003182 break;
3183
3184 /* default case assumes that the command will go
3185 * to the file's ioctl() function.
3186 */
3187 default:
Jeff Vander Stoep581be712015-07-10 17:19:56 -04003188 error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003189 }
3190 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191}
3192
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003193static int default_noexec;
3194
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3196{
David Howells88e67f32008-11-14 10:39:21 +11003197 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003198 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003199
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003200 if (default_noexec &&
3201 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 /*
3203 * We are making executable an anonymous mapping or a
3204 * private file mapping that will also be writable.
3205 * This has an additional check.
3206 */
David Howellsd84f4f92008-11-14 10:39:23 +11003207 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003209 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
3212 if (file) {
3213 /* read access is always possible with a mapping */
3214 u32 av = FILE__READ;
3215
3216 /* write access only matters if the mapping is shared */
3217 if (shared && (prot & PROT_WRITE))
3218 av |= FILE__WRITE;
3219
3220 if (prot & PROT_EXEC)
3221 av |= FILE__EXECUTE;
3222
David Howells88e67f32008-11-14 10:39:21 +11003223 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 }
David Howellsd84f4f92008-11-14 10:39:23 +11003225
3226error:
3227 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228}
3229
3230static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003231 unsigned long prot, unsigned long flags,
3232 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
Eric Parised032182007-06-28 15:55:21 -04003234 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003235 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
Eric Paris84336d1a2009-07-31 12:54:05 -04003237 /*
3238 * notice that we are intentionally putting the SELinux check before
3239 * the secondary cap_file_mmap check. This is such a likely attempt
3240 * at bad behaviour/exploit that we always want to get the AVC, even
3241 * if DAC would have also denied the operation.
3242 */
Eric Parisa2551df2009-07-31 12:54:11 -04003243 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003244 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3245 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003246 if (rc)
3247 return rc;
3248 }
3249
3250 /* do DAC check on address space usage */
3251 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003252 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 return rc;
3254
3255 if (selinux_checkreqprot)
3256 prot = reqprot;
3257
3258 return file_map_prot_check(file, prot,
3259 (flags & MAP_TYPE) == MAP_SHARED);
3260}
3261
3262static int selinux_file_mprotect(struct vm_area_struct *vma,
3263 unsigned long reqprot,
3264 unsigned long prot)
3265{
David Howells88e67f32008-11-14 10:39:21 +11003266 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
3268 if (selinux_checkreqprot)
3269 prot = reqprot;
3270
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003271 if (default_noexec &&
3272 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003273 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003274 if (vma->vm_start >= vma->vm_mm->start_brk &&
3275 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003276 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003277 } else if (!vma->vm_file &&
3278 vma->vm_start <= vma->vm_mm->start_stack &&
3279 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003280 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003281 } else if (vma->vm_file && vma->anon_vma) {
3282 /*
3283 * We are making executable a file mapping that has
3284 * had some COW done. Since pages might have been
3285 * written, check ability to execute the possibly
3286 * modified content. This typically should only
3287 * occur for text relocations.
3288 */
David Howellsd84f4f92008-11-14 10:39:23 +11003289 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003290 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003291 if (rc)
3292 return rc;
3293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294
3295 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3296}
3297
3298static int selinux_file_lock(struct file *file, unsigned int cmd)
3299{
David Howells88e67f32008-11-14 10:39:21 +11003300 const struct cred *cred = current_cred();
3301
3302 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303}
3304
3305static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3306 unsigned long arg)
3307{
David Howells88e67f32008-11-14 10:39:21 +11003308 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 int err = 0;
3310
3311 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003312 case F_SETFL:
3313 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3314 err = -EINVAL;
3315 break;
3316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317
Eric Paris828dfe12008-04-17 13:17:49 -04003318 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003319 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003321 }
3322 /* fall through */
3323 case F_SETOWN:
3324 case F_SETSIG:
3325 case F_GETFL:
3326 case F_GETOWN:
3327 case F_GETSIG:
3328 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003329 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003330 break;
3331 case F_GETLK:
3332 case F_SETLK:
3333 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003335 case F_GETLK64:
3336 case F_SETLK64:
3337 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003339 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3340 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003342 }
David Howells88e67f32008-11-14 10:39:21 +11003343 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003344 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 }
3346
3347 return err;
3348}
3349
3350static int selinux_file_set_fowner(struct file *file)
3351{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 struct file_security_struct *fsec;
3353
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003355 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356
3357 return 0;
3358}
3359
3360static int selinux_file_send_sigiotask(struct task_struct *tsk,
3361 struct fown_struct *fown, int signum)
3362{
Eric Paris828dfe12008-04-17 13:17:49 -04003363 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003364 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 struct file_security_struct *fsec;
3367
3368 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003369 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 fsec = file->f_security;
3372
3373 if (!signum)
3374 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3375 else
3376 perm = signal_to_av(signum);
3377
David Howells275bb412008-11-14 10:39:19 +11003378 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 SECCLASS_PROCESS, perm, NULL);
3380}
3381
3382static int selinux_file_receive(struct file *file)
3383{
David Howells88e67f32008-11-14 10:39:21 +11003384 const struct cred *cred = current_cred();
3385
3386 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387}
3388
David Howells745ca242008-11-14 10:39:22 +11003389static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003390{
3391 struct file_security_struct *fsec;
3392 struct inode *inode;
3393 struct inode_security_struct *isec;
Amir Samuelov6a22e462014-05-26 11:44:06 +03003394 int ret;
3395
3396 ret = pft_file_open(file, cred);
3397 if (ret < 0)
3398 return ret;
David Howellsd84f4f92008-11-14 10:39:23 +11003399
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003400 inode = file->f_path.dentry->d_inode;
3401 fsec = file->f_security;
3402 isec = inode->i_security;
3403 /*
3404 * Save inode label and policy sequence number
3405 * at open-time so that selinux_file_permission
3406 * can determine whether revalidation is necessary.
3407 * Task label is already saved in the file security
3408 * struct as its SID.
3409 */
3410 fsec->isid = isec->sid;
3411 fsec->pseqno = avc_policy_seqno();
3412 /*
3413 * Since the inode label or policy seqno may have changed
3414 * between the selinux_inode_permission check and the saving
3415 * of state above, recheck that access is still permitted.
3416 * Otherwise, access might never be revalidated against the
3417 * new inode label or new policy.
3418 * This check is not redundant - do not remove.
3419 */
Linus Torvalds95f4efb2011-06-08 15:11:56 -07003420 return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003421}
3422
Amir Samuelov6a22e462014-05-26 11:44:06 +03003423static int selinux_file_close(struct file *file)
3424{
3425 return pft_file_close(file);
3426}
3427
3428static bool selinux_allow_merge_bio(struct bio *bio1, struct bio *bio2)
3429{
3430 return pft_allow_merge_bio(bio1, bio2);
3431}
3432
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433/* task security operations */
3434
3435static int selinux_task_create(unsigned long clone_flags)
3436{
David Howells3b11a1d2008-11-14 10:39:26 +11003437 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438}
3439
David Howellsf1752ee2008-11-14 10:39:17 +11003440/*
David Howellsee18d642009-09-02 09:14:21 +01003441 * allocate the SELinux part of blank credentials
3442 */
3443static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3444{
3445 struct task_security_struct *tsec;
3446
3447 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3448 if (!tsec)
3449 return -ENOMEM;
3450
3451 cred->security = tsec;
3452 return 0;
3453}
3454
3455/*
David Howellsf1752ee2008-11-14 10:39:17 +11003456 * detach and free the LSM part of a set of credentials
3457 */
3458static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
David Howellsf1752ee2008-11-14 10:39:17 +11003460 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003461
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003462 /*
3463 * cred->security == NULL if security_cred_alloc_blank() or
3464 * security_prepare_creds() returned an error.
3465 */
3466 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003467 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003468 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469}
3470
David Howellsd84f4f92008-11-14 10:39:23 +11003471/*
3472 * prepare a new set of credentials for modification
3473 */
3474static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3475 gfp_t gfp)
3476{
3477 const struct task_security_struct *old_tsec;
3478 struct task_security_struct *tsec;
3479
3480 old_tsec = old->security;
3481
3482 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3483 if (!tsec)
3484 return -ENOMEM;
3485
3486 new->security = tsec;
3487 return 0;
3488}
3489
3490/*
David Howellsee18d642009-09-02 09:14:21 +01003491 * transfer the SELinux data to a blank set of creds
3492 */
3493static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3494{
3495 const struct task_security_struct *old_tsec = old->security;
3496 struct task_security_struct *tsec = new->security;
3497
3498 *tsec = *old_tsec;
3499}
3500
3501/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003502 * set the security data for a kernel service
3503 * - all the creation contexts are set to unlabelled
3504 */
3505static int selinux_kernel_act_as(struct cred *new, u32 secid)
3506{
3507 struct task_security_struct *tsec = new->security;
3508 u32 sid = current_sid();
3509 int ret;
3510
3511 ret = avc_has_perm(sid, secid,
3512 SECCLASS_KERNEL_SERVICE,
3513 KERNEL_SERVICE__USE_AS_OVERRIDE,
3514 NULL);
3515 if (ret == 0) {
3516 tsec->sid = secid;
3517 tsec->create_sid = 0;
3518 tsec->keycreate_sid = 0;
3519 tsec->sockcreate_sid = 0;
3520 }
3521 return ret;
3522}
3523
3524/*
3525 * set the file creation context in a security record to the same as the
3526 * objective context of the specified inode
3527 */
3528static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3529{
3530 struct inode_security_struct *isec = inode->i_security;
3531 struct task_security_struct *tsec = new->security;
3532 u32 sid = current_sid();
3533 int ret;
3534
3535 ret = avc_has_perm(sid, isec->sid,
3536 SECCLASS_KERNEL_SERVICE,
3537 KERNEL_SERVICE__CREATE_FILES_AS,
3538 NULL);
3539
3540 if (ret == 0)
3541 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003542 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003543}
3544
Eric Parisdd8dbf22009-11-03 16:35:32 +11003545static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003546{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003547 u32 sid;
3548 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003549 struct selinux_audit_data sad = {0,};
Eric Parisdd8dbf22009-11-03 16:35:32 +11003550
3551 sid = task_sid(current);
3552
3553 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003554 ad.selinux_audit_data = &sad;
Eric Parisdd8dbf22009-11-03 16:35:32 +11003555 ad.u.kmod_name = kmod_name;
3556
3557 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3558 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003559}
3560
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3562{
David Howells3b11a1d2008-11-14 10:39:26 +11003563 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564}
3565
3566static int selinux_task_getpgid(struct task_struct *p)
3567{
David Howells3b11a1d2008-11-14 10:39:26 +11003568 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569}
3570
3571static int selinux_task_getsid(struct task_struct *p)
3572{
David Howells3b11a1d2008-11-14 10:39:26 +11003573 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574}
3575
David Quigleyf9008e42006-06-30 01:55:46 -07003576static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3577{
David Howells275bb412008-11-14 10:39:19 +11003578 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003579}
3580
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581static int selinux_task_setnice(struct task_struct *p, int nice)
3582{
3583 int rc;
3584
Eric Paris200ac532009-02-12 15:01:04 -05003585 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 if (rc)
3587 return rc;
3588
David Howells3b11a1d2008-11-14 10:39:26 +11003589 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590}
3591
James Morris03e68062006-06-23 02:03:58 -07003592static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3593{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003594 int rc;
3595
Eric Paris200ac532009-02-12 15:01:04 -05003596 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003597 if (rc)
3598 return rc;
3599
David Howells3b11a1d2008-11-14 10:39:26 +11003600 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003601}
3602
David Quigleya1836a42006-06-30 01:55:49 -07003603static int selinux_task_getioprio(struct task_struct *p)
3604{
David Howells3b11a1d2008-11-14 10:39:26 +11003605 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003606}
3607
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003608static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3609 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003611 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
3613 /* Control the ability to change the hard limit (whether
3614 lowering or raising it), so that the hard limit can
3615 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003616 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003618 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
3620 return 0;
3621}
3622
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003623static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003625 int rc;
3626
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003627 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003628 if (rc)
3629 return rc;
3630
David Howells3b11a1d2008-11-14 10:39:26 +11003631 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632}
3633
3634static int selinux_task_getscheduler(struct task_struct *p)
3635{
David Howells3b11a1d2008-11-14 10:39:26 +11003636 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637}
3638
David Quigley35601542006-06-23 02:04:01 -07003639static int selinux_task_movememory(struct task_struct *p)
3640{
David Howells3b11a1d2008-11-14 10:39:26 +11003641 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003642}
3643
David Quigleyf9008e42006-06-30 01:55:46 -07003644static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3645 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646{
3647 u32 perm;
3648 int rc;
3649
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 if (!sig)
3651 perm = PROCESS__SIGNULL; /* null signal; existence test */
3652 else
3653 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003654 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003655 rc = avc_has_perm(secid, task_sid(p),
3656 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003657 else
David Howells3b11a1d2008-11-14 10:39:26 +11003658 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003659 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660}
3661
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662static int selinux_task_wait(struct task_struct *p)
3663{
Eric Paris8a535142007-10-22 16:10:31 -04003664 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665}
3666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667static void selinux_task_to_inode(struct task_struct *p,
3668 struct inode *inode)
3669{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003671 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
David Howells275bb412008-11-14 10:39:19 +11003673 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675}
3676
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003678static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003679 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680{
3681 int offset, ihlen, ret = -EINVAL;
3682 struct iphdr _iph, *ih;
3683
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003684 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3686 if (ih == NULL)
3687 goto out;
3688
3689 ihlen = ih->ihl * 4;
3690 if (ihlen < sizeof(_iph))
3691 goto out;
3692
Eric Paris48c62af2012-04-02 13:15:44 -04003693 ad->u.net->v4info.saddr = ih->saddr;
3694 ad->u.net->v4info.daddr = ih->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 ret = 0;
3696
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003697 if (proto)
3698 *proto = ih->protocol;
3699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003701 case IPPROTO_TCP: {
3702 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Eric Paris828dfe12008-04-17 13:17:49 -04003704 if (ntohs(ih->frag_off) & IP_OFFSET)
3705 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706
3707 offset += ihlen;
3708 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3709 if (th == NULL)
3710 break;
3711
Eric Paris48c62af2012-04-02 13:15:44 -04003712 ad->u.net->sport = th->source;
3713 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
Eric Paris828dfe12008-04-17 13:17:49 -04003717 case IPPROTO_UDP: {
3718 struct udphdr _udph, *uh;
3719
3720 if (ntohs(ih->frag_off) & IP_OFFSET)
3721 break;
3722
3723 offset += ihlen;
3724 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3725 if (uh == NULL)
3726 break;
3727
Eric Paris48c62af2012-04-02 13:15:44 -04003728 ad->u.net->sport = uh->source;
3729 ad->u.net->dport = uh->dest;
Eric Paris828dfe12008-04-17 13:17:49 -04003730 break;
3731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
James Morris2ee92d42006-11-13 16:09:01 -08003733 case IPPROTO_DCCP: {
3734 struct dccp_hdr _dccph, *dh;
3735
3736 if (ntohs(ih->frag_off) & IP_OFFSET)
3737 break;
3738
3739 offset += ihlen;
3740 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3741 if (dh == NULL)
3742 break;
3743
Eric Paris48c62af2012-04-02 13:15:44 -04003744 ad->u.net->sport = dh->dccph_sport;
3745 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003746 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003747 }
James Morris2ee92d42006-11-13 16:09:01 -08003748
Eric Paris828dfe12008-04-17 13:17:49 -04003749 default:
3750 break;
3751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752out:
3753 return ret;
3754}
3755
3756#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3757
3758/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003759static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003760 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761{
3762 u8 nexthdr;
3763 int ret = -EINVAL, offset;
3764 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003765 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003767 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3769 if (ip6 == NULL)
3770 goto out;
3771
Eric Paris48c62af2012-04-02 13:15:44 -04003772 ad->u.net->v6info.saddr = ip6->saddr;
3773 ad->u.net->v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 ret = 0;
3775
3776 nexthdr = ip6->nexthdr;
3777 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003778 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 if (offset < 0)
3780 goto out;
3781
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003782 if (proto)
3783 *proto = nexthdr;
3784
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 switch (nexthdr) {
3786 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003787 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788
3789 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3790 if (th == NULL)
3791 break;
3792
Eric Paris48c62af2012-04-02 13:15:44 -04003793 ad->u.net->sport = th->source;
3794 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 break;
3796 }
3797
3798 case IPPROTO_UDP: {
3799 struct udphdr _udph, *uh;
3800
3801 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3802 if (uh == NULL)
3803 break;
3804
Eric Paris48c62af2012-04-02 13:15:44 -04003805 ad->u.net->sport = uh->source;
3806 ad->u.net->dport = uh->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 break;
3808 }
3809
James Morris2ee92d42006-11-13 16:09:01 -08003810 case IPPROTO_DCCP: {
3811 struct dccp_hdr _dccph, *dh;
3812
3813 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3814 if (dh == NULL)
3815 break;
3816
Eric Paris48c62af2012-04-02 13:15:44 -04003817 ad->u.net->sport = dh->dccph_sport;
3818 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003819 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003820 }
James Morris2ee92d42006-11-13 16:09:01 -08003821
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 /* includes fragments */
3823 default:
3824 break;
3825 }
3826out:
3827 return ret;
3828}
3829
3830#endif /* IPV6 */
3831
Thomas Liu2bf49692009-07-14 12:14:09 -04003832static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003833 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834{
David Howellscf9481e2008-07-27 21:31:07 +10003835 char *addrp;
3836 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837
Eric Paris48c62af2012-04-02 13:15:44 -04003838 switch (ad->u.net->family) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003840 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003841 if (ret)
3842 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003843 addrp = (char *)(src ? &ad->u.net->v4info.saddr :
3844 &ad->u.net->v4info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003845 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
3847#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3848 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003849 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003850 if (ret)
3851 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003852 addrp = (char *)(src ? &ad->u.net->v6info.saddr :
3853 &ad->u.net->v6info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003854 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855#endif /* IPV6 */
3856 default:
David Howellscf9481e2008-07-27 21:31:07 +10003857 addrp = NULL;
3858 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 }
3860
David Howellscf9481e2008-07-27 21:31:07 +10003861parse_error:
3862 printk(KERN_WARNING
3863 "SELinux: failure in selinux_parse_skb(),"
3864 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003866
3867okay:
3868 if (_addrp)
3869 *_addrp = addrp;
3870 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871}
3872
Paul Moore4f6a9932007-03-01 14:35:22 -05003873/**
Paul Moore220deb92008-01-29 08:38:23 -05003874 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003875 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003876 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003877 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003878 *
3879 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003880 * Check the various different forms of network peer labeling and determine
3881 * the peer label/SID for the packet; most of the magic actually occurs in
3882 * the security server function security_net_peersid_cmp(). The function
3883 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3884 * or -EACCES if @sid is invalid due to inconsistencies with the different
3885 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003886 *
3887 */
Paul Moore220deb92008-01-29 08:38:23 -05003888static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003889{
Paul Moore71f1cb02008-01-29 08:51:16 -05003890 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003891 u32 xfrm_sid;
3892 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003893 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003894
3895 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003896 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003897
Paul Moore71f1cb02008-01-29 08:51:16 -05003898 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3899 if (unlikely(err)) {
3900 printk(KERN_WARNING
3901 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3902 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003903 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003904 }
Paul Moore220deb92008-01-29 08:38:23 -05003905
3906 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003907}
3908
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003910
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003911static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3912 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003913{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003914 if (tsec->sockcreate_sid > SECSID_NULL) {
3915 *socksid = tsec->sockcreate_sid;
3916 return 0;
3917 }
3918
3919 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3920 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003921}
3922
Paul Moore253bfae2010-04-22 14:46:19 -04003923static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924{
Paul Moore253bfae2010-04-22 14:46:19 -04003925 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003926 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003927 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003928 struct lsm_network_audit net = {0,};
Paul Moore253bfae2010-04-22 14:46:19 -04003929 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930
Satya Durga Srinivasu Prabhala90280652013-09-24 15:23:48 -07003931 if (unlikely(!sksec)) {
3932 pr_warn("SELinux: sksec is NULL, socket is already freed\n");
3933 return -EINVAL;
3934 }
3935
Paul Moore253bfae2010-04-22 14:46:19 -04003936 if (sksec->sid == SECINITSID_KERNEL)
3937 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
Thomas Liu2bf49692009-07-14 12:14:09 -04003939 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003940 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003941 ad.u.net = &net;
3942 ad.u.net->sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943
Paul Moore253bfae2010-04-22 14:46:19 -04003944 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945}
3946
3947static int selinux_socket_create(int family, int type,
3948 int protocol, int kern)
3949{
Paul Moore5fb49872010-04-22 14:46:19 -04003950 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003951 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003952 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003953 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954
3955 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003956 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957
David Howells275bb412008-11-14 10:39:19 +11003958 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003959 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3960 if (rc)
3961 return rc;
3962
Paul Moored4f2d972010-04-22 14:46:18 -04003963 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964}
3965
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003966static int selinux_socket_post_create(struct socket *sock, int family,
3967 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968{
Paul Moore5fb49872010-04-22 14:46:19 -04003969 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003970 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003971 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003972 int err = 0;
3973
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003974 isec->sclass = socket_type_to_security_class(family, type, protocol);
3975
David Howells275bb412008-11-14 10:39:19 +11003976 if (kern)
3977 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003978 else {
3979 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3980 if (err)
3981 return err;
3982 }
David Howells275bb412008-11-14 10:39:19 +11003983
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 isec->initialized = 1;
3985
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003986 if (sock->sk) {
3987 sksec = sock->sk->sk_security;
3988 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003989 sksec->sclass = isec->sclass;
Paul Moore389fb802009-03-27 17:10:34 -04003990 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003991 }
3992
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003993 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994}
3995
3996/* Range of port numbers used to automatically bind.
3997 Need to determine whether we should perform a name_bind
3998 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999
4000static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
4001{
Paul Moore253bfae2010-04-22 14:46:19 -04004002 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 u16 family;
4004 int err;
4005
Paul Moore253bfae2010-04-22 14:46:19 -04004006 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 if (err)
4008 goto out;
4009
4010 /*
4011 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04004012 * Multiple address binding for SCTP is not supported yet: we just
4013 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 */
Paul Moore253bfae2010-04-22 14:46:19 -04004015 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 if (family == PF_INET || family == PF_INET6) {
4017 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04004018 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004019 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004020 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004021 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 struct sockaddr_in *addr4 = NULL;
4023 struct sockaddr_in6 *addr6 = NULL;
4024 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10004025 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 if (family == PF_INET) {
4028 addr4 = (struct sockaddr_in *)address;
4029 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 addrp = (char *)&addr4->sin_addr.s_addr;
4031 } else {
4032 addr6 = (struct sockaddr_in6 *)address;
4033 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 addrp = (char *)&addr6->sin6_addr.s6_addr;
4035 }
4036
Stephen Hemminger227b60f2007-10-10 17:30:46 -07004037 if (snum) {
4038 int low, high;
4039
4040 inet_get_local_port_range(&low, &high);
4041
4042 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04004043 err = sel_netport_sid(sk->sk_protocol,
4044 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07004045 if (err)
4046 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04004047 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004048 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004049 ad.u.net = &net;
4050 ad.u.net->sport = htons(snum);
4051 ad.u.net->family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04004052 err = avc_has_perm(sksec->sid, sid,
4053 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07004054 SOCKET__NAME_BIND, &ad);
4055 if (err)
4056 goto out;
4057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 }
Eric Paris828dfe12008-04-17 13:17:49 -04004059
Paul Moore253bfae2010-04-22 14:46:19 -04004060 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04004061 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 node_perm = TCP_SOCKET__NODE_BIND;
4063 break;
Eric Paris828dfe12008-04-17 13:17:49 -04004064
James Morris13402582005-09-30 14:24:34 -04004065 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 node_perm = UDP_SOCKET__NODE_BIND;
4067 break;
James Morris2ee92d42006-11-13 16:09:01 -08004068
4069 case SECCLASS_DCCP_SOCKET:
4070 node_perm = DCCP_SOCKET__NODE_BIND;
4071 break;
4072
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 default:
4074 node_perm = RAWIP_SOCKET__NODE_BIND;
4075 break;
4076 }
Eric Paris828dfe12008-04-17 13:17:49 -04004077
Paul Moore224dfbd2008-01-29 08:38:13 -05004078 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 if (err)
4080 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04004081
Thomas Liu2bf49692009-07-14 12:14:09 -04004082 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004083 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004084 ad.u.net = &net;
4085 ad.u.net->sport = htons(snum);
4086 ad.u.net->family = family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087
4088 if (family == PF_INET)
Eric Paris48c62af2012-04-02 13:15:44 -04004089 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 else
Eric Paris48c62af2012-04-02 13:15:44 -04004091 ad.u.net->v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
Paul Moore253bfae2010-04-22 14:46:19 -04004093 err = avc_has_perm(sksec->sid, sid,
4094 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 if (err)
4096 goto out;
4097 }
4098out:
4099 return err;
4100}
4101
4102static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
4103{
Paul Moore014ab192008-10-10 10:16:33 -04004104 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04004105 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 int err;
4107
Paul Moore253bfae2010-04-22 14:46:19 -04004108 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 if (err)
4110 return err;
4111
4112 /*
James Morris2ee92d42006-11-13 16:09:01 -08004113 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 */
Paul Moore253bfae2010-04-22 14:46:19 -04004115 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
4116 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04004117 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004118 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004119 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 struct sockaddr_in *addr4 = NULL;
4121 struct sockaddr_in6 *addr6 = NULL;
4122 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08004123 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
4125 if (sk->sk_family == PF_INET) {
4126 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07004127 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 return -EINVAL;
4129 snum = ntohs(addr4->sin_port);
4130 } else {
4131 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07004132 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 return -EINVAL;
4134 snum = ntohs(addr6->sin6_port);
4135 }
4136
Paul Moore3e112172008-04-10 10:48:14 -04004137 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 if (err)
4139 goto out;
4140
Paul Moore253bfae2010-04-22 14:46:19 -04004141 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08004142 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
4143
Thomas Liu2bf49692009-07-14 12:14:09 -04004144 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004145 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004146 ad.u.net = &net;
4147 ad.u.net->dport = htons(snum);
4148 ad.u.net->family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04004149 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 if (err)
4151 goto out;
4152 }
4153
Paul Moore014ab192008-10-10 10:16:33 -04004154 err = selinux_netlbl_socket_connect(sk, address);
4155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156out:
4157 return err;
4158}
4159
4160static int selinux_socket_listen(struct socket *sock, int backlog)
4161{
Paul Moore253bfae2010-04-22 14:46:19 -04004162 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163}
4164
4165static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
4166{
4167 int err;
4168 struct inode_security_struct *isec;
4169 struct inode_security_struct *newisec;
4170
Paul Moore253bfae2010-04-22 14:46:19 -04004171 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 if (err)
4173 return err;
4174
4175 newisec = SOCK_INODE(newsock)->i_security;
4176
4177 isec = SOCK_INODE(sock)->i_security;
4178 newisec->sclass = isec->sclass;
4179 newisec->sid = isec->sid;
4180 newisec->initialized = 1;
4181
4182 return 0;
4183}
4184
4185static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04004186 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187{
Paul Moore253bfae2010-04-22 14:46:19 -04004188 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189}
4190
4191static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4192 int size, int flags)
4193{
Paul Moore253bfae2010-04-22 14:46:19 -04004194 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195}
4196
4197static int selinux_socket_getsockname(struct socket *sock)
4198{
Paul Moore253bfae2010-04-22 14:46:19 -04004199 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200}
4201
4202static int selinux_socket_getpeername(struct socket *sock)
4203{
Paul Moore253bfae2010-04-22 14:46:19 -04004204 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205}
4206
Eric Paris828dfe12008-04-17 13:17:49 -04004207static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208{
Paul Mooref8687af2006-10-30 15:22:15 -08004209 int err;
4210
Paul Moore253bfae2010-04-22 14:46:19 -04004211 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08004212 if (err)
4213 return err;
4214
4215 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216}
4217
4218static int selinux_socket_getsockopt(struct socket *sock, int level,
4219 int optname)
4220{
Paul Moore253bfae2010-04-22 14:46:19 -04004221 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222}
4223
4224static int selinux_socket_shutdown(struct socket *sock, int how)
4225{
Paul Moore253bfae2010-04-22 14:46:19 -04004226 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227}
4228
David S. Miller3610cda2011-01-05 15:38:53 -08004229static int selinux_socket_unix_stream_connect(struct sock *sock,
4230 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 struct sock *newsk)
4232{
David S. Miller3610cda2011-01-05 15:38:53 -08004233 struct sk_security_struct *sksec_sock = sock->sk_security;
4234 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004235 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004236 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004237 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004238 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 int err;
4240
Thomas Liu2bf49692009-07-14 12:14:09 -04004241 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004242 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004243 ad.u.net = &net;
4244 ad.u.net->sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245
Paul Moore4d1e2452010-04-22 14:46:18 -04004246 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4247 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4249 if (err)
4250 return err;
4251
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004253 sksec_new->peer_sid = sksec_sock->sid;
4254 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4255 &sksec_new->sid);
4256 if (err)
4257 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004258
Paul Moore4d1e2452010-04-22 14:46:18 -04004259 /* connecting socket */
4260 sksec_sock->peer_sid = sksec_new->sid;
4261
4262 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263}
4264
4265static int selinux_socket_unix_may_send(struct socket *sock,
4266 struct socket *other)
4267{
Paul Moore253bfae2010-04-22 14:46:19 -04004268 struct sk_security_struct *ssec = sock->sk->sk_security;
4269 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004270 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004271 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004272 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273
Thomas Liu2bf49692009-07-14 12:14:09 -04004274 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004275 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004276 ad.u.net = &net;
4277 ad.u.net->sk = other->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
Paul Moore253bfae2010-04-22 14:46:19 -04004279 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4280 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281}
4282
Paul Mooreeffad8d2008-01-29 08:49:27 -05004283static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4284 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004285 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004286{
4287 int err;
4288 u32 if_sid;
4289 u32 node_sid;
4290
4291 err = sel_netif_sid(ifindex, &if_sid);
4292 if (err)
4293 return err;
4294 err = avc_has_perm(peer_sid, if_sid,
4295 SECCLASS_NETIF, NETIF__INGRESS, ad);
4296 if (err)
4297 return err;
4298
4299 err = sel_netnode_sid(addrp, family, &node_sid);
4300 if (err)
4301 return err;
4302 return avc_has_perm(peer_sid, node_sid,
4303 SECCLASS_NODE, NODE__RECVFROM, ad);
4304}
4305
Paul Moore220deb92008-01-29 08:38:23 -05004306static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004307 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004308{
Paul Moore277d3422008-12-31 12:54:11 -05004309 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004310 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004311 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004312 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004313 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004314 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004315 char *addrp;
4316
Thomas Liu2bf49692009-07-14 12:14:09 -04004317 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004318 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004319 ad.u.net = &net;
4320 ad.u.net->netif = skb->skb_iif;
4321 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004322 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4323 if (err)
4324 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004325
Paul Moore58bfbb52009-03-27 17:10:41 -04004326 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004327 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004328 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004329 if (err)
4330 return err;
4331 }
Paul Moore220deb92008-01-29 08:38:23 -05004332
Steffen Klassertb9679a72011-02-23 12:55:21 +01004333 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4334 if (err)
4335 return err;
4336 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004337
James Morris4e5ab4c2006-06-09 00:33:33 -07004338 return err;
4339}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004340
James Morris4e5ab4c2006-06-09 00:33:33 -07004341static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4342{
Paul Moore220deb92008-01-29 08:38:23 -05004343 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004344 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004345 u16 family = sk->sk_family;
4346 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004347 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004348 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004349 struct lsm_network_audit net = {0,};
Paul Moore220deb92008-01-29 08:38:23 -05004350 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004351 u8 secmark_active;
4352 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004353
James Morris4e5ab4c2006-06-09 00:33:33 -07004354 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004355 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004356
4357 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004358 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004359 family = PF_INET;
4360
Paul Moored8395c82008-10-10 10:16:30 -04004361 /* If any sort of compatibility mode is enabled then handoff processing
4362 * to the selinux_sock_rcv_skb_compat() function to deal with the
4363 * special handling. We do this in an attempt to keep this function
4364 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004365 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004366 return selinux_sock_rcv_skb_compat(sk, skb, family);
4367
4368 secmark_active = selinux_secmark_enabled();
4369 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4370 if (!secmark_active && !peerlbl_active)
4371 return 0;
4372
Thomas Liu2bf49692009-07-14 12:14:09 -04004373 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004374 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004375 ad.u.net = &net;
4376 ad.u.net->netif = skb->skb_iif;
4377 ad.u.net->family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004378 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004379 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004380 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004381
Paul Moored8395c82008-10-10 10:16:30 -04004382 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004383 u32 peer_sid;
4384
4385 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4386 if (err)
4387 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004388 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004389 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004390 if (err) {
4391 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004392 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004393 }
Paul Moored621d352008-01-29 08:43:36 -05004394 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4395 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004396 if (err)
4397 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004398 }
4399
Paul Moored8395c82008-10-10 10:16:30 -04004400 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004401 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4402 PACKET__RECV, &ad);
4403 if (err)
4404 return err;
4405 }
4406
Paul Moored621d352008-01-29 08:43:36 -05004407 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408}
4409
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004410static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4411 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412{
4413 int err = 0;
4414 char *scontext;
4415 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004416 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004417 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Paul Moore253bfae2010-04-22 14:46:19 -04004419 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4420 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004421 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004422 if (peer_sid == SECSID_NULL)
4423 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004425 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004427 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428
4429 if (scontext_len > len) {
4430 err = -ERANGE;
4431 goto out_len;
4432 }
4433
4434 if (copy_to_user(optval, scontext, scontext_len))
4435 err = -EFAULT;
4436
4437out_len:
4438 if (put_user(scontext_len, optlen))
4439 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 return err;
4442}
4443
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004444static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004445{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004446 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004447 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004448
Paul Mooreaa862902008-10-10 10:16:29 -04004449 if (skb && skb->protocol == htons(ETH_P_IP))
4450 family = PF_INET;
4451 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4452 family = PF_INET6;
4453 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004454 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004455 else
4456 goto out;
4457
4458 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004459 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004460 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004461 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004462
Paul Moore75e22912008-01-29 08:38:04 -05004463out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004464 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004465 if (peer_secid == SECSID_NULL)
4466 return -EINVAL;
4467 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004468}
4469
Al Viro7d877f32005-10-21 03:20:43 -04004470static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471{
Paul Moore84914b72010-04-22 14:46:18 -04004472 struct sk_security_struct *sksec;
4473
4474 sksec = kzalloc(sizeof(*sksec), priority);
4475 if (!sksec)
4476 return -ENOMEM;
4477
4478 sksec->peer_sid = SECINITSID_UNLABELED;
4479 sksec->sid = SECINITSID_UNLABELED;
4480 selinux_netlbl_sk_security_reset(sksec);
4481 sk->sk_security = sksec;
4482
4483 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484}
4485
4486static void selinux_sk_free_security(struct sock *sk)
4487{
Paul Moore84914b72010-04-22 14:46:18 -04004488 struct sk_security_struct *sksec = sk->sk_security;
4489
4490 sk->sk_security = NULL;
4491 selinux_netlbl_sk_security_free(sksec);
4492 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493}
4494
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004495static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4496{
Eric Parisdd3e7832010-04-07 15:08:46 -04004497 struct sk_security_struct *sksec = sk->sk_security;
4498 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004499
Eric Parisdd3e7832010-04-07 15:08:46 -04004500 newsksec->sid = sksec->sid;
4501 newsksec->peer_sid = sksec->peer_sid;
4502 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004503
Eric Parisdd3e7832010-04-07 15:08:46 -04004504 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004505}
4506
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004507static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004508{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004509 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004510 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004511 else {
4512 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004513
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004514 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004515 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004516}
4517
Eric Paris828dfe12008-04-17 13:17:49 -04004518static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004519{
4520 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4521 struct sk_security_struct *sksec = sk->sk_security;
4522
David Woodhouse2148ccc2006-09-29 15:50:25 -07004523 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4524 sk->sk_family == PF_UNIX)
4525 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004526 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004527}
4528
Adrian Bunk9a673e52006-08-15 00:03:53 -07004529static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4530 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004531{
4532 struct sk_security_struct *sksec = sk->sk_security;
4533 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004534 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004535 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004536 u32 peersid;
4537
Paul Mooreaa862902008-10-10 10:16:29 -04004538 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4539 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4540 family = PF_INET;
4541
4542 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004543 if (err)
4544 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004545 if (peersid == SECSID_NULL) {
4546 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004547 req->peer_secid = SECSID_NULL;
Paul Moore389fb802009-03-27 17:10:34 -04004548 } else {
4549 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4550 if (err)
4551 return err;
4552 req->secid = newsid;
4553 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004554 }
4555
Paul Moore389fb802009-03-27 17:10:34 -04004556 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004557}
4558
Adrian Bunk9a673e52006-08-15 00:03:53 -07004559static void selinux_inet_csk_clone(struct sock *newsk,
4560 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004561{
4562 struct sk_security_struct *newsksec = newsk->sk_security;
4563
4564 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004565 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004566 /* NOTE: Ideally, we should also get the isec->sid for the
4567 new socket in sync, but we don't have the isec available yet.
4568 So we will wait until sock_graft to do it, by which
4569 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004570
Paul Moore9f2ad662006-11-17 17:38:53 -05004571 /* We don't need to take any sort of lock here as we are the only
4572 * thread with access to newsksec */
Paul Moore389fb802009-03-27 17:10:34 -04004573 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004574}
4575
Paul Moore014ab192008-10-10 10:16:33 -04004576static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004577{
Paul Mooreaa862902008-10-10 10:16:29 -04004578 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004579 struct sk_security_struct *sksec = sk->sk_security;
4580
Paul Mooreaa862902008-10-10 10:16:29 -04004581 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4582 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4583 family = PF_INET;
4584
4585 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004586}
4587
Eric Paris2606fd12010-10-13 16:24:41 -04004588static int selinux_secmark_relabel_packet(u32 sid)
4589{
4590 const struct task_security_struct *__tsec;
4591 u32 tsid;
4592
4593 __tsec = current_security();
4594 tsid = __tsec->sid;
4595
4596 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4597}
4598
4599static void selinux_secmark_refcount_inc(void)
4600{
4601 atomic_inc(&selinux_secmark_refcount);
4602}
4603
4604static void selinux_secmark_refcount_dec(void)
4605{
4606 atomic_dec(&selinux_secmark_refcount);
4607}
4608
Adrian Bunk9a673e52006-08-15 00:03:53 -07004609static void selinux_req_classify_flow(const struct request_sock *req,
4610 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004611{
David S. Miller1d28f422011-03-12 00:29:39 -05004612 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004613}
4614
Paul Mooreed6d76e2009-08-28 18:12:49 -04004615static int selinux_tun_dev_create(void)
4616{
4617 u32 sid = current_sid();
4618
4619 /* we aren't taking into account the "sockcreate" SID since the socket
4620 * that is being created here is not a socket in the traditional sense,
4621 * instead it is a private sock, accessible only to the kernel, and
4622 * representing a wide range of network traffic spanning multiple
4623 * connections unlike traditional sockets - check the TUN driver to
4624 * get a better understanding of why this socket is special */
4625
4626 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4627 NULL);
4628}
4629
4630static void selinux_tun_dev_post_create(struct sock *sk)
4631{
4632 struct sk_security_struct *sksec = sk->sk_security;
4633
4634 /* we don't currently perform any NetLabel based labeling here and it
4635 * isn't clear that we would want to do so anyway; while we could apply
4636 * labeling without the support of the TUN user the resulting labeled
4637 * traffic from the other end of the connection would almost certainly
4638 * cause confusion to the TUN user that had no idea network labeling
4639 * protocols were being used */
4640
4641 /* see the comments in selinux_tun_dev_create() about why we don't use
4642 * the sockcreate SID here */
4643
4644 sksec->sid = current_sid();
4645 sksec->sclass = SECCLASS_TUN_SOCKET;
4646}
4647
4648static int selinux_tun_dev_attach(struct sock *sk)
4649{
4650 struct sk_security_struct *sksec = sk->sk_security;
4651 u32 sid = current_sid();
4652 int err;
4653
4654 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4655 TUN_SOCKET__RELABELFROM, NULL);
4656 if (err)
4657 return err;
4658 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4659 TUN_SOCKET__RELABELTO, NULL);
4660 if (err)
4661 return err;
4662
4663 sksec->sid = sid;
4664
4665 return 0;
4666}
4667
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4669{
4670 int err = 0;
4671 u32 perm;
4672 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004673 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004674
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 if (skb->len < NLMSG_SPACE(0)) {
4676 err = -EINVAL;
4677 goto out;
4678 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004679 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004680
Paul Moore253bfae2010-04-22 14:46:19 -04004681 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 if (err) {
4683 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004684 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 "SELinux: unrecognized netlink message"
4686 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004687 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004688 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 err = 0;
4690 }
4691
4692 /* Ignore */
4693 if (err == -ENOENT)
4694 err = 0;
4695 goto out;
4696 }
4697
Paul Moore253bfae2010-04-22 14:46:19 -04004698 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699out:
4700 return err;
4701}
4702
4703#ifdef CONFIG_NETFILTER
4704
Paul Mooreeffad8d2008-01-29 08:49:27 -05004705static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4706 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707{
Paul Mooredfaebe92008-10-10 10:16:31 -04004708 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004709 char *addrp;
4710 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004711 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004712 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004713 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004714 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004715 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004717
Paul Mooreeffad8d2008-01-29 08:49:27 -05004718 if (!selinux_policycap_netpeer)
4719 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004720
Paul Mooreeffad8d2008-01-29 08:49:27 -05004721 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004722 netlbl_active = netlbl_enabled();
4723 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004724 if (!secmark_active && !peerlbl_active)
4725 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004726
Paul Moored8395c82008-10-10 10:16:30 -04004727 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4728 return NF_DROP;
4729
Thomas Liu2bf49692009-07-14 12:14:09 -04004730 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004731 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004732 ad.u.net = &net;
4733 ad.u.net->netif = ifindex;
4734 ad.u.net->family = family;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004735 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4736 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737
Paul Mooredfaebe92008-10-10 10:16:31 -04004738 if (peerlbl_active) {
4739 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4740 peer_sid, &ad);
4741 if (err) {
4742 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004743 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004744 }
4745 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004746
4747 if (secmark_active)
4748 if (avc_has_perm(peer_sid, skb->secmark,
4749 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4750 return NF_DROP;
4751
Paul Moore948bf852008-10-10 10:16:32 -04004752 if (netlbl_active)
4753 /* we do this in the FORWARD path and not the POST_ROUTING
4754 * path because we want to make sure we apply the necessary
4755 * labeling before IPsec is applied so we can leverage AH
4756 * protection */
4757 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4758 return NF_DROP;
4759
Paul Mooreeffad8d2008-01-29 08:49:27 -05004760 return NF_ACCEPT;
4761}
4762
4763static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4764 struct sk_buff *skb,
4765 const struct net_device *in,
4766 const struct net_device *out,
4767 int (*okfn)(struct sk_buff *))
4768{
4769 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4770}
4771
4772#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4773static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4774 struct sk_buff *skb,
4775 const struct net_device *in,
4776 const struct net_device *out,
4777 int (*okfn)(struct sk_buff *))
4778{
4779 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4780}
4781#endif /* IPV6 */
4782
Paul Moore948bf852008-10-10 10:16:32 -04004783static unsigned int selinux_ip_output(struct sk_buff *skb,
4784 u16 family)
4785{
4786 u32 sid;
4787
4788 if (!netlbl_enabled())
4789 return NF_ACCEPT;
4790
4791 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4792 * because we want to make sure we apply the necessary labeling
4793 * before IPsec is applied so we can leverage AH protection */
4794 if (skb->sk) {
4795 struct sk_security_struct *sksec = skb->sk->sk_security;
4796 sid = sksec->sid;
4797 } else
4798 sid = SECINITSID_KERNEL;
4799 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4800 return NF_DROP;
4801
4802 return NF_ACCEPT;
4803}
4804
4805static unsigned int selinux_ipv4_output(unsigned int hooknum,
4806 struct sk_buff *skb,
4807 const struct net_device *in,
4808 const struct net_device *out,
4809 int (*okfn)(struct sk_buff *))
4810{
4811 return selinux_ip_output(skb, PF_INET);
4812}
4813
Paul Mooreeffad8d2008-01-29 08:49:27 -05004814static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4815 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004816 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004817{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004818 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004819 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004820 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004821 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004822 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004823 char *addrp;
4824 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004825
Paul Mooreeffad8d2008-01-29 08:49:27 -05004826 if (sk == NULL)
4827 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004828 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004829
Thomas Liu2bf49692009-07-14 12:14:09 -04004830 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004831 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004832 ad.u.net = &net;
4833 ad.u.net->netif = ifindex;
4834 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004835 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4836 return NF_DROP;
4837
Paul Moore58bfbb52009-03-27 17:10:41 -04004838 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004839 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004840 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004841 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004842
Steffen Klassertb9679a72011-02-23 12:55:21 +01004843 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4844 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004845
Paul Mooreeffad8d2008-01-29 08:49:27 -05004846 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847}
4848
Paul Mooreeffad8d2008-01-29 08:49:27 -05004849static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4850 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004852 u32 secmark_perm;
4853 u32 peer_sid;
4854 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004855 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004856 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004857 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004858 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004859 u8 secmark_active;
4860 u8 peerlbl_active;
4861
Paul Mooreeffad8d2008-01-29 08:49:27 -05004862 /* If any sort of compatibility mode is enabled then handoff processing
4863 * to the selinux_ip_postroute_compat() function to deal with the
4864 * special handling. We do this in an attempt to keep this function
4865 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004866 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004867 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004868#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004869 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4870 * packet transformation so allow the packet to pass without any checks
4871 * since we'll have another chance to perform access control checks
4872 * when the packet is on it's final way out.
4873 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4874 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004875 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004876 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004877#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004878 secmark_active = selinux_secmark_enabled();
4879 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4880 if (!secmark_active && !peerlbl_active)
4881 return NF_ACCEPT;
4882
Paul Moored8395c82008-10-10 10:16:30 -04004883 /* if the packet is being forwarded then get the peer label from the
4884 * packet itself; otherwise check to see if it is from a local
4885 * application or the kernel, if from an application get the peer label
4886 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004887 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004888 if (sk == NULL) {
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004889 if (skb->skb_iif) {
4890 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004891 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004892 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004893 } else {
4894 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004895 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004896 }
Paul Moored8395c82008-10-10 10:16:30 -04004897 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004898 struct sk_security_struct *sksec = sk->sk_security;
4899 peer_sid = sksec->sid;
4900 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004901 }
4902
Thomas Liu2bf49692009-07-14 12:14:09 -04004903 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004904 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004905 ad.u.net = &net;
4906 ad.u.net->netif = ifindex;
4907 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004908 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004909 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004910
Paul Mooreeffad8d2008-01-29 08:49:27 -05004911 if (secmark_active)
4912 if (avc_has_perm(peer_sid, skb->secmark,
4913 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004914 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004915
4916 if (peerlbl_active) {
4917 u32 if_sid;
4918 u32 node_sid;
4919
4920 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004921 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004922 if (avc_has_perm(peer_sid, if_sid,
4923 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004924 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004925
4926 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004927 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004928 if (avc_has_perm(peer_sid, node_sid,
4929 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004930 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004931 }
4932
4933 return NF_ACCEPT;
4934}
4935
4936static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4937 struct sk_buff *skb,
4938 const struct net_device *in,
4939 const struct net_device *out,
4940 int (*okfn)(struct sk_buff *))
4941{
4942 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943}
4944
4945#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004946static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4947 struct sk_buff *skb,
4948 const struct net_device *in,
4949 const struct net_device *out,
4950 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004952 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954#endif /* IPV6 */
4955
4956#endif /* CONFIG_NETFILTER */
4957
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4959{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960 int err;
4961
Eric Paris200ac532009-02-12 15:01:04 -05004962 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 if (err)
4964 return err;
4965
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004966 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967}
4968
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969static int ipc_alloc_security(struct task_struct *task,
4970 struct kern_ipc_perm *perm,
4971 u16 sclass)
4972{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004974 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975
James Morris89d155e2005-10-30 14:59:21 -08004976 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 if (!isec)
4978 return -ENOMEM;
4979
David Howells275bb412008-11-14 10:39:19 +11004980 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004982 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 perm->security = isec;
4984
4985 return 0;
4986}
4987
4988static void ipc_free_security(struct kern_ipc_perm *perm)
4989{
4990 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 perm->security = NULL;
4992 kfree(isec);
4993}
4994
4995static int msg_msg_alloc_security(struct msg_msg *msg)
4996{
4997 struct msg_security_struct *msec;
4998
James Morris89d155e2005-10-30 14:59:21 -08004999 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 if (!msec)
5001 return -ENOMEM;
5002
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 msec->sid = SECINITSID_UNLABELED;
5004 msg->security = msec;
5005
5006 return 0;
5007}
5008
5009static void msg_msg_free_security(struct msg_msg *msg)
5010{
5011 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012
5013 msg->security = NULL;
5014 kfree(msec);
5015}
5016
5017static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07005018 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005021 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005022 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005023 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 isec = ipc_perms->security;
5026
Thomas Liu2bf49692009-07-14 12:14:09 -04005027 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005028 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 ad.u.ipc_id = ipc_perms->key;
5030
David Howells275bb412008-11-14 10:39:19 +11005031 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032}
5033
5034static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
5035{
5036 return msg_msg_alloc_security(msg);
5037}
5038
5039static void selinux_msg_msg_free_security(struct msg_msg *msg)
5040{
5041 msg_msg_free_security(msg);
5042}
5043
5044/* message queue security operations */
5045static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
5046{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005048 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005049 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005050 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 int rc;
5052
5053 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
5054 if (rc)
5055 return rc;
5056
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 isec = msq->q_perm.security;
5058
Thomas Liu2bf49692009-07-14 12:14:09 -04005059 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005060 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005061 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062
David Howells275bb412008-11-14 10:39:19 +11005063 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 MSGQ__CREATE, &ad);
5065 if (rc) {
5066 ipc_free_security(&msq->q_perm);
5067 return rc;
5068 }
5069 return 0;
5070}
5071
5072static void selinux_msg_queue_free_security(struct msg_queue *msq)
5073{
5074 ipc_free_security(&msq->q_perm);
5075}
5076
5077static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
5078{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005080 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005081 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005082 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 isec = msq->q_perm.security;
5085
Thomas Liu2bf49692009-07-14 12:14:09 -04005086 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005087 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 ad.u.ipc_id = msq->q_perm.key;
5089
David Howells275bb412008-11-14 10:39:19 +11005090 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 MSGQ__ASSOCIATE, &ad);
5092}
5093
5094static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
5095{
5096 int err;
5097 int perms;
5098
Eric Paris828dfe12008-04-17 13:17:49 -04005099 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 case IPC_INFO:
5101 case MSG_INFO:
5102 /* No specific object, just general system-wide information. */
5103 return task_has_system(current, SYSTEM__IPC_INFO);
5104 case IPC_STAT:
5105 case MSG_STAT:
5106 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
5107 break;
5108 case IPC_SET:
5109 perms = MSGQ__SETATTR;
5110 break;
5111 case IPC_RMID:
5112 perms = MSGQ__DESTROY;
5113 break;
5114 default:
5115 return 0;
5116 }
5117
Stephen Smalley6af963f2005-05-01 08:58:39 -07005118 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 return err;
5120}
5121
5122static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
5123{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 struct ipc_security_struct *isec;
5125 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005126 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005127 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005128 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 int rc;
5130
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 isec = msq->q_perm.security;
5132 msec = msg->security;
5133
5134 /*
5135 * First time through, need to assign label to the message
5136 */
5137 if (msec->sid == SECINITSID_UNLABELED) {
5138 /*
5139 * Compute new sid based on current process and
5140 * message queue this message will be stored in
5141 */
David Howells275bb412008-11-14 10:39:19 +11005142 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05005143 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 if (rc)
5145 return rc;
5146 }
5147
Thomas Liu2bf49692009-07-14 12:14:09 -04005148 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005149 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 ad.u.ipc_id = msq->q_perm.key;
5151
5152 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005153 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 MSGQ__WRITE, &ad);
5155 if (!rc)
5156 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005157 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5158 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 if (!rc)
5160 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005161 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5162 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163
5164 return rc;
5165}
5166
5167static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5168 struct task_struct *target,
5169 long type, int mode)
5170{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 struct ipc_security_struct *isec;
5172 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005173 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005174 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005175 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 int rc;
5177
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 isec = msq->q_perm.security;
5179 msec = msg->security;
5180
Thomas Liu2bf49692009-07-14 12:14:09 -04005181 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005182 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005183 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184
David Howells275bb412008-11-14 10:39:19 +11005185 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 SECCLASS_MSGQ, MSGQ__READ, &ad);
5187 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005188 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 SECCLASS_MSG, MSG__RECEIVE, &ad);
5190 return rc;
5191}
5192
5193/* Shared Memory security operations */
5194static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5195{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005197 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005198 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005199 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 int rc;
5201
5202 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5203 if (rc)
5204 return rc;
5205
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 isec = shp->shm_perm.security;
5207
Thomas Liu2bf49692009-07-14 12:14:09 -04005208 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005209 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005210 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211
David Howells275bb412008-11-14 10:39:19 +11005212 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 SHM__CREATE, &ad);
5214 if (rc) {
5215 ipc_free_security(&shp->shm_perm);
5216 return rc;
5217 }
5218 return 0;
5219}
5220
5221static void selinux_shm_free_security(struct shmid_kernel *shp)
5222{
5223 ipc_free_security(&shp->shm_perm);
5224}
5225
5226static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5227{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005229 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005230 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005231 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 isec = shp->shm_perm.security;
5234
Thomas Liu2bf49692009-07-14 12:14:09 -04005235 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005236 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 ad.u.ipc_id = shp->shm_perm.key;
5238
David Howells275bb412008-11-14 10:39:19 +11005239 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 SHM__ASSOCIATE, &ad);
5241}
5242
5243/* Note, at this point, shp is locked down */
5244static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5245{
5246 int perms;
5247 int err;
5248
Eric Paris828dfe12008-04-17 13:17:49 -04005249 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 case IPC_INFO:
5251 case SHM_INFO:
5252 /* No specific object, just general system-wide information. */
5253 return task_has_system(current, SYSTEM__IPC_INFO);
5254 case IPC_STAT:
5255 case SHM_STAT:
5256 perms = SHM__GETATTR | SHM__ASSOCIATE;
5257 break;
5258 case IPC_SET:
5259 perms = SHM__SETATTR;
5260 break;
5261 case SHM_LOCK:
5262 case SHM_UNLOCK:
5263 perms = SHM__LOCK;
5264 break;
5265 case IPC_RMID:
5266 perms = SHM__DESTROY;
5267 break;
5268 default:
5269 return 0;
5270 }
5271
Stephen Smalley6af963f2005-05-01 08:58:39 -07005272 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 return err;
5274}
5275
5276static int selinux_shm_shmat(struct shmid_kernel *shp,
5277 char __user *shmaddr, int shmflg)
5278{
5279 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280
5281 if (shmflg & SHM_RDONLY)
5282 perms = SHM__READ;
5283 else
5284 perms = SHM__READ | SHM__WRITE;
5285
Stephen Smalley6af963f2005-05-01 08:58:39 -07005286 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287}
5288
5289/* Semaphore security operations */
5290static int selinux_sem_alloc_security(struct sem_array *sma)
5291{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005293 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005294 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005295 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 int rc;
5297
5298 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5299 if (rc)
5300 return rc;
5301
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 isec = sma->sem_perm.security;
5303
Thomas Liu2bf49692009-07-14 12:14:09 -04005304 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005305 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005306 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307
David Howells275bb412008-11-14 10:39:19 +11005308 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 SEM__CREATE, &ad);
5310 if (rc) {
5311 ipc_free_security(&sma->sem_perm);
5312 return rc;
5313 }
5314 return 0;
5315}
5316
5317static void selinux_sem_free_security(struct sem_array *sma)
5318{
5319 ipc_free_security(&sma->sem_perm);
5320}
5321
5322static int selinux_sem_associate(struct sem_array *sma, int semflg)
5323{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005325 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005326 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005327 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 isec = sma->sem_perm.security;
5330
Thomas Liu2bf49692009-07-14 12:14:09 -04005331 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005332 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 ad.u.ipc_id = sma->sem_perm.key;
5334
David Howells275bb412008-11-14 10:39:19 +11005335 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 SEM__ASSOCIATE, &ad);
5337}
5338
5339/* Note, at this point, sma is locked down */
5340static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5341{
5342 int err;
5343 u32 perms;
5344
Eric Paris828dfe12008-04-17 13:17:49 -04005345 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 case IPC_INFO:
5347 case SEM_INFO:
5348 /* No specific object, just general system-wide information. */
5349 return task_has_system(current, SYSTEM__IPC_INFO);
5350 case GETPID:
5351 case GETNCNT:
5352 case GETZCNT:
5353 perms = SEM__GETATTR;
5354 break;
5355 case GETVAL:
5356 case GETALL:
5357 perms = SEM__READ;
5358 break;
5359 case SETVAL:
5360 case SETALL:
5361 perms = SEM__WRITE;
5362 break;
5363 case IPC_RMID:
5364 perms = SEM__DESTROY;
5365 break;
5366 case IPC_SET:
5367 perms = SEM__SETATTR;
5368 break;
5369 case IPC_STAT:
5370 case SEM_STAT:
5371 perms = SEM__GETATTR | SEM__ASSOCIATE;
5372 break;
5373 default:
5374 return 0;
5375 }
5376
Stephen Smalley6af963f2005-05-01 08:58:39 -07005377 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 return err;
5379}
5380
5381static int selinux_sem_semop(struct sem_array *sma,
5382 struct sembuf *sops, unsigned nsops, int alter)
5383{
5384 u32 perms;
5385
5386 if (alter)
5387 perms = SEM__READ | SEM__WRITE;
5388 else
5389 perms = SEM__READ;
5390
Stephen Smalley6af963f2005-05-01 08:58:39 -07005391 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392}
5393
5394static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5395{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 u32 av = 0;
5397
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 av = 0;
5399 if (flag & S_IRUGO)
5400 av |= IPC__UNIX_READ;
5401 if (flag & S_IWUGO)
5402 av |= IPC__UNIX_WRITE;
5403
5404 if (av == 0)
5405 return 0;
5406
Stephen Smalley6af963f2005-05-01 08:58:39 -07005407 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408}
5409
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005410static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5411{
5412 struct ipc_security_struct *isec = ipcp->security;
5413 *secid = isec->sid;
5414}
5415
Eric Paris828dfe12008-04-17 13:17:49 -04005416static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417{
5418 if (inode)
5419 inode_doinit_with_dentry(inode, dentry);
5420}
5421
5422static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005423 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424{
David Howells275bb412008-11-14 10:39:19 +11005425 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005426 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005428 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429
5430 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005431 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 if (error)
5433 return error;
5434 }
5435
David Howells275bb412008-11-14 10:39:19 +11005436 rcu_read_lock();
5437 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438
5439 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005440 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005442 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005444 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005446 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005447 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005448 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005449 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005450 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 else
David Howells275bb412008-11-14 10:39:19 +11005452 goto invalid;
5453 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454
5455 if (!sid)
5456 return 0;
5457
Al Viro04ff9702007-03-12 16:17:58 +00005458 error = security_sid_to_context(sid, value, &len);
5459 if (error)
5460 return error;
5461 return len;
David Howells275bb412008-11-14 10:39:19 +11005462
5463invalid:
5464 rcu_read_unlock();
5465 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466}
5467
5468static int selinux_setprocattr(struct task_struct *p,
5469 char *name, void *value, size_t size)
5470{
5471 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005472 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005473 struct cred *new;
5474 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 int error;
5476 char *str = value;
5477
5478 if (current != p) {
5479 /* SELinux only allows a process to change its own
5480 security attributes. */
5481 return -EACCES;
5482 }
5483
5484 /*
5485 * Basic control over ability to set these attributes at all.
5486 * current == p, but we'll pass them separately in case the
5487 * above restriction is ever removed.
5488 */
5489 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005490 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005492 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005493 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005494 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005495 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005496 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005498 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 else
5500 error = -EINVAL;
5501 if (error)
5502 return error;
5503
5504 /* Obtain a SID for the context, if one was specified. */
Stephen Smalleye44b57e2017-01-31 11:54:04 -05005505 if (size && str[0] && str[0] != '\n') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 if (str[size-1] == '\n') {
5507 str[size-1] = 0;
5508 size--;
5509 }
5510 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005511 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5512 if (!capable(CAP_MAC_ADMIN))
5513 return error;
5514 error = security_context_to_sid_force(value, size,
5515 &sid);
5516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 if (error)
5518 return error;
5519 }
5520
David Howellsd84f4f92008-11-14 10:39:23 +11005521 new = prepare_creds();
5522 if (!new)
5523 return -ENOMEM;
5524
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 /* Permission checking based on the specified context is
5526 performed during the actual operation (execve,
5527 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005528 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 checks and may_create for the file creation checks. The
5530 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005531 tsec = new->security;
5532 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005534 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005536 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005537 error = may_create_key(sid, p);
5538 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005539 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005540 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005541 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005542 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005543 } else if (!strcmp(name, "current")) {
5544 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005546 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005547
David Howellsd84f4f92008-11-14 10:39:23 +11005548 /* Only allow single threaded processes to change context */
5549 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005550 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005551 error = security_bounded_transition(tsec->sid, sid);
5552 if (error)
5553 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555
5556 /* Check permissions for the transition. */
5557 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005558 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005560 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
5562 /* Check for ptracing, and update the task SID if ok.
5563 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005564 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 task_lock(p);
Tejun Heo06d98472011-06-17 16:50:40 +02005566 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005567 if (tracer)
5568 ptsid = task_sid(tracer);
5569 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570
David Howellsd84f4f92008-11-14 10:39:23 +11005571 if (tracer) {
5572 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5573 PROCESS__PTRACE, NULL);
5574 if (error)
5575 goto abort_change;
5576 }
5577
5578 tsec->sid = sid;
5579 } else {
5580 error = -EINVAL;
5581 goto abort_change;
5582 }
5583
5584 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005586
5587abort_change:
5588 abort_creds(new);
5589 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590}
5591
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005592static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5593{
5594 return security_sid_to_context(secid, secdata, seclen);
5595}
5596
David Howells7bf570d2008-04-29 20:52:51 +01005597static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005598{
5599 return security_context_to_sid(secdata, seclen, secid);
5600}
5601
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005602static void selinux_release_secctx(char *secdata, u32 seclen)
5603{
Paul Moore088999e2007-08-01 11:12:58 -04005604 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005605}
5606
David P. Quigley1ee65e32009-09-03 14:25:57 -04005607/*
5608 * called with inode->i_mutex locked
5609 */
5610static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5611{
5612 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5613}
5614
5615/*
5616 * called with inode->i_mutex locked
5617 */
5618static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5619{
5620 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5621}
5622
5623static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5624{
5625 int len = 0;
5626 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5627 ctx, true);
5628 if (len < 0)
5629 return len;
5630 *ctxlen = len;
5631 return 0;
5632}
Michael LeMayd7200242006-06-22 14:47:17 -07005633#ifdef CONFIG_KEYS
5634
David Howellsd84f4f92008-11-14 10:39:23 +11005635static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005636 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005637{
David Howellsd84f4f92008-11-14 10:39:23 +11005638 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005639 struct key_security_struct *ksec;
5640
5641 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5642 if (!ksec)
5643 return -ENOMEM;
5644
David Howellsd84f4f92008-11-14 10:39:23 +11005645 tsec = cred->security;
5646 if (tsec->keycreate_sid)
5647 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005648 else
David Howellsd84f4f92008-11-14 10:39:23 +11005649 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005650
David Howells275bb412008-11-14 10:39:19 +11005651 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005652 return 0;
5653}
5654
5655static void selinux_key_free(struct key *k)
5656{
5657 struct key_security_struct *ksec = k->security;
5658
5659 k->security = NULL;
5660 kfree(ksec);
5661}
5662
5663static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005664 const struct cred *cred,
5665 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005666{
5667 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005668 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005669 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005670
5671 /* if no specific permissions are requested, we skip the
5672 permission check. No serious, additional covert channels
5673 appear to be created. */
5674 if (perm == 0)
5675 return 0;
5676
David Howellsd84f4f92008-11-14 10:39:23 +11005677 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005678
5679 key = key_ref_to_ptr(key_ref);
5680 ksec = key->security;
5681
5682 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005683}
5684
David Howells70a5bb72008-04-29 01:01:26 -07005685static int selinux_key_getsecurity(struct key *key, char **_buffer)
5686{
5687 struct key_security_struct *ksec = key->security;
5688 char *context = NULL;
5689 unsigned len;
5690 int rc;
5691
5692 rc = security_sid_to_context(ksec->sid, &context, &len);
5693 if (!rc)
5694 rc = len;
5695 *_buffer = context;
5696 return rc;
5697}
5698
Michael LeMayd7200242006-06-22 14:47:17 -07005699#endif
5700
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005702 .name = "selinux",
5703
Stephen Smalley48a23702012-11-05 08:15:34 -05005704 .binder_set_context_mgr = selinux_binder_set_context_mgr,
5705 .binder_transaction = selinux_binder_transaction,
5706 .binder_transfer_binder = selinux_binder_transfer_binder,
5707 .binder_transfer_file = selinux_binder_transfer_file,
5708
Ingo Molnar9e488582009-05-07 19:26:19 +10005709 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005710 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005712 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 .capable = selinux_capable,
5714 .quotactl = selinux_quotactl,
5715 .quota_on = selinux_quota_on,
5716 .syslog = selinux_syslog,
5717 .vm_enough_memory = selinux_vm_enough_memory,
5718
5719 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720
David Howellsa6f76f22008-11-14 10:39:24 +11005721 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005722 .bprm_committing_creds = selinux_bprm_committing_creds,
5723 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 .bprm_secureexec = selinux_bprm_secureexec,
5725
5726 .sb_alloc_security = selinux_sb_alloc_security,
5727 .sb_free_security = selinux_sb_free_security,
5728 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005729 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005730 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005731 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 .sb_statfs = selinux_sb_statfs,
5733 .sb_mount = selinux_mount,
5734 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005735 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005736 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005737 .sb_parse_opts_str = selinux_parse_opts_str,
5738
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739
5740 .inode_alloc_security = selinux_inode_alloc_security,
5741 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005742 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 .inode_create = selinux_inode_create,
Amir Samuelov6a22e462014-05-26 11:44:06 +03005744 .inode_post_create = selinux_inode_post_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 .inode_unlink = selinux_inode_unlink,
5747 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 .inode_rmdir = selinux_inode_rmdir,
5750 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 .inode_readlink = selinux_inode_readlink,
5753 .inode_follow_link = selinux_inode_follow_link,
5754 .inode_permission = selinux_inode_permission,
5755 .inode_setattr = selinux_inode_setattr,
5756 .inode_getattr = selinux_inode_getattr,
5757 .inode_setxattr = selinux_inode_setxattr,
5758 .inode_post_setxattr = selinux_inode_post_setxattr,
5759 .inode_getxattr = selinux_inode_getxattr,
5760 .inode_listxattr = selinux_inode_listxattr,
5761 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005762 .inode_getsecurity = selinux_inode_getsecurity,
5763 .inode_setsecurity = selinux_inode_setsecurity,
5764 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005765 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766
5767 .file_permission = selinux_file_permission,
5768 .file_alloc_security = selinux_file_alloc_security,
5769 .file_free_security = selinux_file_free_security,
5770 .file_ioctl = selinux_file_ioctl,
5771 .file_mmap = selinux_file_mmap,
5772 .file_mprotect = selinux_file_mprotect,
5773 .file_lock = selinux_file_lock,
5774 .file_fcntl = selinux_file_fcntl,
5775 .file_set_fowner = selinux_file_set_fowner,
5776 .file_send_sigiotask = selinux_file_send_sigiotask,
5777 .file_receive = selinux_file_receive,
5778
Eric Paris828dfe12008-04-17 13:17:49 -04005779 .dentry_open = selinux_dentry_open,
Amir Samuelov6a22e462014-05-26 11:44:06 +03005780 .file_close = selinux_file_close,
5781 .allow_merge_bio = selinux_allow_merge_bio,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005782
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005784 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005785 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005786 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005787 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005788 .kernel_act_as = selinux_kernel_act_as,
5789 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005790 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 .task_setpgid = selinux_task_setpgid,
5792 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005793 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005794 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005796 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005797 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 .task_setrlimit = selinux_task_setrlimit,
5799 .task_setscheduler = selinux_task_setscheduler,
5800 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005801 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 .task_kill = selinux_task_kill,
5803 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005804 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805
5806 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005807 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808
5809 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5810 .msg_msg_free_security = selinux_msg_msg_free_security,
5811
5812 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5813 .msg_queue_free_security = selinux_msg_queue_free_security,
5814 .msg_queue_associate = selinux_msg_queue_associate,
5815 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5816 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5817 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5818
5819 .shm_alloc_security = selinux_shm_alloc_security,
5820 .shm_free_security = selinux_shm_free_security,
5821 .shm_associate = selinux_shm_associate,
5822 .shm_shmctl = selinux_shm_shmctl,
5823 .shm_shmat = selinux_shm_shmat,
5824
Eric Paris828dfe12008-04-17 13:17:49 -04005825 .sem_alloc_security = selinux_sem_alloc_security,
5826 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 .sem_associate = selinux_sem_associate,
5828 .sem_semctl = selinux_sem_semctl,
5829 .sem_semop = selinux_sem_semop,
5830
Eric Paris828dfe12008-04-17 13:17:49 -04005831 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832
Eric Paris828dfe12008-04-17 13:17:49 -04005833 .getprocattr = selinux_getprocattr,
5834 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005836 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005837 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005838 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005839 .inode_notifysecctx = selinux_inode_notifysecctx,
5840 .inode_setsecctx = selinux_inode_setsecctx,
5841 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005842
Eric Paris828dfe12008-04-17 13:17:49 -04005843 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 .unix_may_send = selinux_socket_unix_may_send,
5845
5846 .socket_create = selinux_socket_create,
5847 .socket_post_create = selinux_socket_post_create,
5848 .socket_bind = selinux_socket_bind,
5849 .socket_connect = selinux_socket_connect,
5850 .socket_listen = selinux_socket_listen,
5851 .socket_accept = selinux_socket_accept,
5852 .socket_sendmsg = selinux_socket_sendmsg,
5853 .socket_recvmsg = selinux_socket_recvmsg,
5854 .socket_getsockname = selinux_socket_getsockname,
5855 .socket_getpeername = selinux_socket_getpeername,
5856 .socket_getsockopt = selinux_socket_getsockopt,
5857 .socket_setsockopt = selinux_socket_setsockopt,
5858 .socket_shutdown = selinux_socket_shutdown,
5859 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005860 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5861 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 .sk_alloc_security = selinux_sk_alloc_security,
5863 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005864 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005865 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005866 .sock_graft = selinux_sock_graft,
5867 .inet_conn_request = selinux_inet_conn_request,
5868 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005869 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005870 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5871 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5872 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005873 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005874 .tun_dev_create = selinux_tun_dev_create,
5875 .tun_dev_post_create = selinux_tun_dev_post_create,
5876 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005877
5878#ifdef CONFIG_SECURITY_NETWORK_XFRM
5879 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5880 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5881 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005882 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005883 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5884 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005885 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005886 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005887 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005888 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005890
5891#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005892 .key_alloc = selinux_key_alloc,
5893 .key_free = selinux_key_free,
5894 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005895 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005896#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005897
5898#ifdef CONFIG_AUDIT
5899 .audit_rule_init = selinux_audit_rule_init,
5900 .audit_rule_known = selinux_audit_rule_known,
5901 .audit_rule_match = selinux_audit_rule_match,
5902 .audit_rule_free = selinux_audit_rule_free,
5903#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904};
5905
5906static __init int selinux_init(void)
5907{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005908 if (!security_module_enable(&selinux_ops)) {
5909 selinux_enabled = 0;
5910 return 0;
5911 }
5912
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 if (!selinux_enabled) {
5914 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5915 return 0;
5916 }
5917
5918 printk(KERN_INFO "SELinux: Initializing.\n");
5919
5920 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005921 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005923 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5924
James Morris7cae7e22006-03-22 00:09:22 -08005925 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5926 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005927 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 avc_init();
5929
Eric Paris828dfe12008-04-17 13:17:49 -04005930 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 panic("SELinux: Unable to register with kernel.\n");
5932
Eric Paris828dfe12008-04-17 13:17:49 -04005933 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005934 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005935 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005936 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005937
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 return 0;
5939}
5940
Al Viroe8c26252010-03-23 06:36:54 -04005941static void delayed_superblock_init(struct super_block *sb, void *unused)
5942{
5943 superblock_doinit(sb, NULL);
5944}
5945
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946void selinux_complete_init(void)
5947{
Eric Parisfadcdb42007-02-22 18:11:31 -05005948 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949
5950 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005951 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005952 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953}
5954
5955/* SELinux requires early initialization in order to label
5956 all processes and objects when they are created. */
5957security_initcall(selinux_init);
5958
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005959#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
Paul Mooreeffad8d2008-01-29 08:49:27 -05005961static struct nf_hook_ops selinux_ipv4_ops[] = {
5962 {
5963 .hook = selinux_ipv4_postroute,
5964 .owner = THIS_MODULE,
5965 .pf = PF_INET,
5966 .hooknum = NF_INET_POST_ROUTING,
5967 .priority = NF_IP_PRI_SELINUX_LAST,
5968 },
5969 {
5970 .hook = selinux_ipv4_forward,
5971 .owner = THIS_MODULE,
5972 .pf = PF_INET,
5973 .hooknum = NF_INET_FORWARD,
5974 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005975 },
5976 {
5977 .hook = selinux_ipv4_output,
5978 .owner = THIS_MODULE,
5979 .pf = PF_INET,
5980 .hooknum = NF_INET_LOCAL_OUT,
5981 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983};
5984
5985#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5986
Paul Mooreeffad8d2008-01-29 08:49:27 -05005987static struct nf_hook_ops selinux_ipv6_ops[] = {
5988 {
5989 .hook = selinux_ipv6_postroute,
5990 .owner = THIS_MODULE,
5991 .pf = PF_INET6,
5992 .hooknum = NF_INET_POST_ROUTING,
5993 .priority = NF_IP6_PRI_SELINUX_LAST,
5994 },
5995 {
5996 .hook = selinux_ipv6_forward,
5997 .owner = THIS_MODULE,
5998 .pf = PF_INET6,
5999 .hooknum = NF_INET_FORWARD,
6000 .priority = NF_IP6_PRI_SELINUX_FIRST,
6001 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002};
6003
6004#endif /* IPV6 */
6005
6006static int __init selinux_nf_ip_init(void)
6007{
6008 int err = 0;
6009
6010 if (!selinux_enabled)
6011 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05006012
6013 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
6014
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07006015 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
6016 if (err)
6017 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018
6019#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07006020 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
6021 if (err)
6022 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08006024
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025out:
6026 return err;
6027}
6028
6029__initcall(selinux_nf_ip_init);
6030
6031#ifdef CONFIG_SECURITY_SELINUX_DISABLE
6032static void selinux_nf_ip_exit(void)
6033{
Eric Parisfadcdb42007-02-22 18:11:31 -05006034 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07006036 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07006038 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039#endif /* IPV6 */
6040}
6041#endif
6042
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08006043#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044
6045#ifdef CONFIG_SECURITY_SELINUX_DISABLE
6046#define selinux_nf_ip_exit()
6047#endif
6048
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08006049#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050
6051#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04006052static int selinux_disabled;
6053
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054int selinux_disable(void)
6055{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 if (ss_initialized) {
6057 /* Not permitted after initial policy load. */
6058 return -EINVAL;
6059 }
6060
6061 if (selinux_disabled) {
6062 /* Only do this once. */
6063 return -EINVAL;
6064 }
6065
6066 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
6067
6068 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04006069 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08006071 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072
Eric Parisaf8ff042009-09-20 21:23:01 -04006073 /* Try to destroy the avc node cache */
6074 avc_disable();
6075
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 /* Unregister netfilter hooks. */
6077 selinux_nf_ip_exit();
6078
6079 /* Unregister selinuxfs. */
6080 exit_sel_fs();
6081
6082 return 0;
6083}
6084#endif