blob: e9d0a6681a4b76941f9db94ef8516a75c0e133b4 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#include "avc.h"
87#include "objsec.h"
88#include "netif.h"
Paul Moore224dfbd2008-01-29 08:38:13 -050089#include "netnode.h"
Paul Moore3e112172008-04-10 10:48:14 -040090#include "netport.h"
Trent Jaegerd28d1e02005-12-13 23:12:40 -080091#include "xfrm.h"
Paul Moorec60475b2007-02-28 15:14:23 -050092#include "netlabel.h"
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +020093#include "audit.h"
James Morris7b98a582011-08-30 12:52:32 +100094#include "avc_ss.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
David P. Quigley11689d42009-01-16 09:22:03 -050096#define NUM_SEL_MNT_OPTS 5
Eric Parisc9180a52007-11-30 13:00:35 -050097
James Morris20510f22007-10-16 23:31:32 -070098extern struct security_operations *security_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Paul Moored621d352008-01-29 08:43:36 -0500100/* SECMARK reference count */
James Morris56a4ca92011-08-17 11:08:43 +1000101static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
Paul Moored621d352008-01-29 08:43:36 -0500102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
Eric Paris828dfe12008-04-17 13:17:49 -0400104int selinux_enforcing;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106static int __init enforcing_setup(char *str)
107{
Eric Parisf5269712008-05-14 11:27:45 -0400108 unsigned long enforcing;
109 if (!strict_strtoul(str, 0, &enforcing))
110 selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 return 1;
112}
113__setup("enforcing=", enforcing_setup);
114#endif
115
116#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
117int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
118
119static int __init selinux_enabled_setup(char *str)
120{
Eric Parisf5269712008-05-14 11:27:45 -0400121 unsigned long enabled;
122 if (!strict_strtoul(str, 0, &enabled))
123 selinux_enabled = enabled ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 return 1;
125}
126__setup("selinux=", selinux_enabled_setup);
Stephen Smalley30d55282006-05-03 10:52:36 -0400127#else
128int selinux_enabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129#endif
130
Christoph Lametere18b8902006-12-06 20:33:20 -0800131static struct kmem_cache *sel_inode_cache;
James Morris7cae7e22006-03-22 00:09:22 -0800132
Paul Moored621d352008-01-29 08:43:36 -0500133/**
134 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
135 *
136 * Description:
137 * This function checks the SECMARK reference counter to see if any SECMARK
138 * targets are currently configured, if the reference counter is greater than
139 * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
140 * enabled, false (0) if SECMARK is disabled.
141 *
142 */
143static int selinux_secmark_enabled(void)
144{
145 return (atomic_read(&selinux_secmark_refcount) > 0);
146}
147
David Howellsd84f4f92008-11-14 10:39:23 +1100148/*
149 * initialise the security for the init task
150 */
151static void cred_init_security(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
David Howells3b11a1d2008-11-14 10:39:26 +1100153 struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 struct task_security_struct *tsec;
155
James Morris89d155e2005-10-30 14:59:21 -0800156 tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if (!tsec)
David Howellsd84f4f92008-11-14 10:39:23 +1100158 panic("SELinux: Failed to initialize initial task.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
David Howellsd84f4f92008-11-14 10:39:23 +1100160 tsec->osid = tsec->sid = SECINITSID_KERNEL;
David Howellsf1752ee2008-11-14 10:39:17 +1100161 cred->security = tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}
163
David Howells275bb412008-11-14 10:39:19 +1100164/*
David Howells88e67f32008-11-14 10:39:21 +1100165 * get the security ID of a set of credentials
166 */
167static inline u32 cred_sid(const struct cred *cred)
168{
169 const struct task_security_struct *tsec;
170
171 tsec = cred->security;
172 return tsec->sid;
173}
174
175/*
David Howells3b11a1d2008-11-14 10:39:26 +1100176 * get the objective security ID of a task
David Howells275bb412008-11-14 10:39:19 +1100177 */
178static inline u32 task_sid(const struct task_struct *task)
179{
David Howells275bb412008-11-14 10:39:19 +1100180 u32 sid;
181
182 rcu_read_lock();
David Howells88e67f32008-11-14 10:39:21 +1100183 sid = cred_sid(__task_cred(task));
David Howells275bb412008-11-14 10:39:19 +1100184 rcu_read_unlock();
185 return sid;
186}
187
188/*
David Howells3b11a1d2008-11-14 10:39:26 +1100189 * get the subjective security ID of the current task
David Howells275bb412008-11-14 10:39:19 +1100190 */
191static inline u32 current_sid(void)
192{
Paul Moore5fb49872010-04-22 14:46:19 -0400193 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +1100194
195 return tsec->sid;
196}
197
David Howells88e67f32008-11-14 10:39:21 +1100198/* Allocate and free functions for each kind of security blob. */
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200static int inode_alloc_security(struct inode *inode)
201{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +1100203 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Josef Bacika02fe132008-04-04 09:35:05 +1100205 isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (!isec)
207 return -ENOMEM;
208
Eric Paris23970742006-09-25 23:32:01 -0700209 mutex_init(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 INIT_LIST_HEAD(&isec->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 isec->inode = inode;
212 isec->sid = SECINITSID_UNLABELED;
213 isec->sclass = SECCLASS_FILE;
David Howells275bb412008-11-14 10:39:19 +1100214 isec->task_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 inode->i_security = isec;
216
217 return 0;
218}
219
220static void inode_free_security(struct inode *inode)
221{
222 struct inode_security_struct *isec = inode->i_security;
223 struct superblock_security_struct *sbsec = inode->i_sb->s_security;
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 spin_lock(&sbsec->isec_lock);
226 if (!list_empty(&isec->list))
227 list_del_init(&isec->list);
228 spin_unlock(&sbsec->isec_lock);
229
230 inode->i_security = NULL;
James Morris7cae7e22006-03-22 00:09:22 -0800231 kmem_cache_free(sel_inode_cache, isec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
233
234static int file_alloc_security(struct file *file)
235{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 struct file_security_struct *fsec;
David Howells275bb412008-11-14 10:39:19 +1100237 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Stephen Smalley26d2a4b2006-02-01 03:05:55 -0800239 fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (!fsec)
241 return -ENOMEM;
242
David Howells275bb412008-11-14 10:39:19 +1100243 fsec->sid = sid;
244 fsec->fown_sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 file->f_security = fsec;
246
247 return 0;
248}
249
250static void file_free_security(struct file *file)
251{
252 struct file_security_struct *fsec = file->f_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 file->f_security = NULL;
254 kfree(fsec);
255}
256
257static int superblock_alloc_security(struct super_block *sb)
258{
259 struct superblock_security_struct *sbsec;
260
James Morris89d155e2005-10-30 14:59:21 -0800261 sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 if (!sbsec)
263 return -ENOMEM;
264
Eric Parisbc7e9822006-09-25 23:32:02 -0700265 mutex_init(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 INIT_LIST_HEAD(&sbsec->isec_head);
267 spin_lock_init(&sbsec->isec_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 sbsec->sb = sb;
269 sbsec->sid = SECINITSID_UNLABELED;
270 sbsec->def_sid = SECINITSID_FILE;
Eric Parisc312feb2006-07-10 04:43:53 -0700271 sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 sb->s_security = sbsec;
273
274 return 0;
275}
276
277static void superblock_free_security(struct super_block *sb)
278{
279 struct superblock_security_struct *sbsec = sb->s_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sb->s_security = NULL;
281 kfree(sbsec);
282}
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284/* The file system's label must be initialized prior to use. */
285
Stephen Hemminger634a5392010-03-04 21:59:03 -0800286static const char *labeling_behaviors[6] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 "uses xattr",
288 "uses transition SIDs",
289 "uses task SIDs",
290 "uses genfs_contexts",
291 "not configured for labeling",
292 "uses mountpoint labeling",
293};
294
295static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
296
297static inline int inode_doinit(struct inode *inode)
298{
299 return inode_doinit_with_dentry(inode, NULL);
300}
301
302enum {
Eric Paris31e87932007-09-19 17:19:12 -0400303 Opt_error = -1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 Opt_context = 1,
305 Opt_fscontext = 2,
Eric Parisc9180a52007-11-30 13:00:35 -0500306 Opt_defcontext = 3,
307 Opt_rootcontext = 4,
David P. Quigley11689d42009-01-16 09:22:03 -0500308 Opt_labelsupport = 5,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309};
310
Steven Whitehousea447c092008-10-13 10:46:57 +0100311static const match_table_t tokens = {
Eric Paris832cbd92008-04-01 13:24:09 -0400312 {Opt_context, CONTEXT_STR "%s"},
313 {Opt_fscontext, FSCONTEXT_STR "%s"},
314 {Opt_defcontext, DEFCONTEXT_STR "%s"},
315 {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
David P. Quigley11689d42009-01-16 09:22:03 -0500316 {Opt_labelsupport, LABELSUPP_STR},
Eric Paris31e87932007-09-19 17:19:12 -0400317 {Opt_error, NULL},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318};
319
320#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
321
Eric Parisc312feb2006-07-10 04:43:53 -0700322static int may_context_mount_sb_relabel(u32 sid,
323 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100324 const struct cred *cred)
Eric Parisc312feb2006-07-10 04:43:53 -0700325{
David Howells275bb412008-11-14 10:39:19 +1100326 const struct task_security_struct *tsec = cred->security;
Eric Parisc312feb2006-07-10 04:43:53 -0700327 int rc;
328
329 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
330 FILESYSTEM__RELABELFROM, NULL);
331 if (rc)
332 return rc;
333
334 rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
335 FILESYSTEM__RELABELTO, NULL);
336 return rc;
337}
338
Eric Paris08089252006-07-10 04:43:55 -0700339static int may_context_mount_inode_relabel(u32 sid,
340 struct superblock_security_struct *sbsec,
David Howells275bb412008-11-14 10:39:19 +1100341 const struct cred *cred)
Eric Paris08089252006-07-10 04:43:55 -0700342{
David Howells275bb412008-11-14 10:39:19 +1100343 const struct task_security_struct *tsec = cred->security;
Eric Paris08089252006-07-10 04:43:55 -0700344 int rc;
345 rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
346 FILESYSTEM__RELABELFROM, NULL);
347 if (rc)
348 return rc;
349
350 rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
351 FILESYSTEM__ASSOCIATE, NULL);
352 return rc;
353}
354
Eric Parisc9180a52007-11-30 13:00:35 -0500355static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357 struct superblock_security_struct *sbsec = sb->s_security;
358 struct dentry *root = sb->s_root;
Eric Parisc9180a52007-11-30 13:00:35 -0500359 struct inode *root_inode = root->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 int rc = 0;
361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
363 /* Make sure that the xattr handler exists and that no
364 error other than -ENODATA is returned by getxattr on
365 the root directory. -ENODATA is ok, as this may be
366 the first boot of the SELinux kernel before we have
367 assigned xattr values to the filesystem. */
Eric Parisc9180a52007-11-30 13:00:35 -0500368 if (!root_inode->i_op->getxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
370 "xattr support\n", sb->s_id, sb->s_type->name);
371 rc = -EOPNOTSUPP;
372 goto out;
373 }
Eric Parisc9180a52007-11-30 13:00:35 -0500374 rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 if (rc < 0 && rc != -ENODATA) {
376 if (rc == -EOPNOTSUPP)
377 printk(KERN_WARNING "SELinux: (dev %s, type "
378 "%s) has no security xattr handler\n",
379 sb->s_id, sb->s_type->name);
380 else
381 printk(KERN_WARNING "SELinux: (dev %s, type "
382 "%s) getxattr errno %d\n", sb->s_id,
383 sb->s_type->name, -rc);
384 goto out;
385 }
386 }
387
David P. Quigley11689d42009-01-16 09:22:03 -0500388 sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Eric Parisc9180a52007-11-30 13:00:35 -0500390 if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
Eric Parisfadcdb42007-02-22 18:11:31 -0500391 printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 sb->s_id, sb->s_type->name);
Eric Parisc9180a52007-11-30 13:00:35 -0500393 else
Eric Parisfadcdb42007-02-22 18:11:31 -0500394 printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 sb->s_id, sb->s_type->name,
396 labeling_behaviors[sbsec->behavior-1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
David P. Quigley11689d42009-01-16 09:22:03 -0500398 if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
399 sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
400 sbsec->behavior == SECURITY_FS_USE_NONE ||
401 sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
402 sbsec->flags &= ~SE_SBLABELSUPP;
403
David P. Quigleyddd29ec2009-09-09 14:25:37 -0400404 /* Special handling for sysfs. Is genfs but also has setxattr handler*/
405 if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
406 sbsec->flags |= SE_SBLABELSUPP;
407
Stephen Smalley90078112013-05-10 10:16:19 -0400408 /*
409 * Special handling for rootfs. Is genfs but supports
410 * setting SELinux context on in-core inodes.
411 */
412 if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
413 sbsec->flags |= SE_SBLABELSUPP;
414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500416 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 /* Initialize any other inodes associated with the superblock, e.g.
419 inodes created prior to initial policy load or inodes created
420 during get_sb by a pseudo filesystem that directly
421 populates itself. */
422 spin_lock(&sbsec->isec_lock);
423next_inode:
424 if (!list_empty(&sbsec->isec_head)) {
425 struct inode_security_struct *isec =
426 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500427 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 struct inode *inode = isec->inode;
429 spin_unlock(&sbsec->isec_lock);
430 inode = igrab(inode);
431 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500432 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 inode_doinit(inode);
434 iput(inode);
435 }
436 spin_lock(&sbsec->isec_lock);
437 list_del_init(&isec->list);
438 goto next_inode;
439 }
440 spin_unlock(&sbsec->isec_lock);
441out:
Eric Parisc9180a52007-11-30 13:00:35 -0500442 return rc;
443}
444
445/*
446 * This function should allow an FS to ask what it's mount security
447 * options were so it can use those later for submounts, displaying
448 * mount options, or whatever.
449 */
450static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500451 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500452{
453 int rc = 0, i;
454 struct superblock_security_struct *sbsec = sb->s_security;
455 char *context = NULL;
456 u32 len;
457 char tmp;
458
Eric Parise0007522008-03-05 10:31:54 -0500459 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500460
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500461 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500462 return -EINVAL;
463
464 if (!ss_initialized)
465 return -EINVAL;
466
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500467 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500468 /* count the number of mount options for this sb */
469 for (i = 0; i < 8; i++) {
470 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500471 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500472 tmp >>= 1;
473 }
David P. Quigley11689d42009-01-16 09:22:03 -0500474 /* Check if the Label support flag is set */
475 if (sbsec->flags & SE_SBLABELSUPP)
476 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500477
Eric Parise0007522008-03-05 10:31:54 -0500478 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
479 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500480 rc = -ENOMEM;
481 goto out_free;
482 }
483
Eric Parise0007522008-03-05 10:31:54 -0500484 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
485 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500486 rc = -ENOMEM;
487 goto out_free;
488 }
489
490 i = 0;
491 if (sbsec->flags & FSCONTEXT_MNT) {
492 rc = security_sid_to_context(sbsec->sid, &context, &len);
493 if (rc)
494 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500495 opts->mnt_opts[i] = context;
496 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500497 }
498 if (sbsec->flags & CONTEXT_MNT) {
499 rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
500 if (rc)
501 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500502 opts->mnt_opts[i] = context;
503 opts->mnt_opts_flags[i++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500504 }
505 if (sbsec->flags & DEFCONTEXT_MNT) {
506 rc = security_sid_to_context(sbsec->def_sid, &context, &len);
507 if (rc)
508 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500509 opts->mnt_opts[i] = context;
510 opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500511 }
512 if (sbsec->flags & ROOTCONTEXT_MNT) {
513 struct inode *root = sbsec->sb->s_root->d_inode;
514 struct inode_security_struct *isec = root->i_security;
515
516 rc = security_sid_to_context(isec->sid, &context, &len);
517 if (rc)
518 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500519 opts->mnt_opts[i] = context;
520 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500521 }
David P. Quigley11689d42009-01-16 09:22:03 -0500522 if (sbsec->flags & SE_SBLABELSUPP) {
523 opts->mnt_opts[i] = NULL;
524 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
525 }
Eric Parisc9180a52007-11-30 13:00:35 -0500526
Eric Parise0007522008-03-05 10:31:54 -0500527 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500528
529 return 0;
530
531out_free:
Eric Parise0007522008-03-05 10:31:54 -0500532 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500533 return rc;
534}
535
536static int bad_option(struct superblock_security_struct *sbsec, char flag,
537 u32 old_sid, u32 new_sid)
538{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500539 char mnt_flags = sbsec->flags & SE_MNTMASK;
540
Eric Parisc9180a52007-11-30 13:00:35 -0500541 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500542 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500543 if (!(sbsec->flags & flag) ||
544 (old_sid != new_sid))
545 return 1;
546
547 /* check if we were passed the same options twice,
548 * aka someone passed context=a,context=b
549 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500550 if (!(sbsec->flags & SE_SBINITIALIZED))
551 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500552 return 1;
553 return 0;
554}
Eric Parise0007522008-03-05 10:31:54 -0500555
Eric Parisc9180a52007-11-30 13:00:35 -0500556/*
557 * Allow filesystems with binary mount data to explicitly set mount point
558 * labeling information.
559 */
Eric Parise0007522008-03-05 10:31:54 -0500560static int selinux_set_mnt_opts(struct super_block *sb,
561 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500562{
David Howells275bb412008-11-14 10:39:19 +1100563 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500564 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500565 struct superblock_security_struct *sbsec = sb->s_security;
566 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000567 struct inode *inode = sbsec->sb->s_root->d_inode;
568 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500569 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
570 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500571 char **mount_options = opts->mnt_opts;
572 int *flags = opts->mnt_opts_flags;
573 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500574
575 mutex_lock(&sbsec->lock);
576
577 if (!ss_initialized) {
578 if (!num_opts) {
579 /* Defer initialization until selinux_complete_init,
580 after the initial policy is loaded and the security
581 server is ready to handle calls. */
Eric Parisc9180a52007-11-30 13:00:35 -0500582 goto out;
583 }
584 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400585 printk(KERN_WARNING "SELinux: Unable to set superblock options "
586 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500587 goto out;
588 }
589
590 /*
Eric Parise0007522008-03-05 10:31:54 -0500591 * Binary mount data FS will come through this function twice. Once
592 * from an explicit call and once from the generic calls from the vfs.
593 * Since the generic VFS calls will not contain any security mount data
594 * we need to skip the double mount verification.
595 *
596 * This does open a hole in which we will not notice if the first
597 * mount using this sb set explict options and a second mount using
598 * this sb does not set any security options. (The first options
599 * will be used for both mounts)
600 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500601 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500602 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400603 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500604
605 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500606 * parse the mount options, check if they are valid sids.
607 * also check if someone is trying to mount the same sb more
608 * than once with different security options.
609 */
610 for (i = 0; i < num_opts; i++) {
611 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500612
613 if (flags[i] == SE_SBLABELSUPP)
614 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500615 rc = security_context_to_sid(mount_options[i],
616 strlen(mount_options[i]), &sid);
617 if (rc) {
618 printk(KERN_WARNING "SELinux: security_context_to_sid"
619 "(%s) failed for (dev %s, type %s) errno=%d\n",
620 mount_options[i], sb->s_id, name, rc);
621 goto out;
622 }
623 switch (flags[i]) {
624 case FSCONTEXT_MNT:
625 fscontext_sid = sid;
626
627 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
628 fscontext_sid))
629 goto out_double_mount;
630
631 sbsec->flags |= FSCONTEXT_MNT;
632 break;
633 case CONTEXT_MNT:
634 context_sid = sid;
635
636 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
637 context_sid))
638 goto out_double_mount;
639
640 sbsec->flags |= CONTEXT_MNT;
641 break;
642 case ROOTCONTEXT_MNT:
643 rootcontext_sid = sid;
644
645 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
646 rootcontext_sid))
647 goto out_double_mount;
648
649 sbsec->flags |= ROOTCONTEXT_MNT;
650
651 break;
652 case DEFCONTEXT_MNT:
653 defcontext_sid = sid;
654
655 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
656 defcontext_sid))
657 goto out_double_mount;
658
659 sbsec->flags |= DEFCONTEXT_MNT;
660
661 break;
662 default:
663 rc = -EINVAL;
664 goto out;
665 }
666 }
667
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500668 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500669 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500670 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500671 goto out_double_mount;
672 rc = 0;
673 goto out;
674 }
675
James Morris089be432008-07-15 18:32:49 +1000676 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500677 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500678
679 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500680 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500681 if (rc) {
682 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000683 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500684 goto out;
685 }
686
687 /* sets the context of the superblock for the fs being mounted. */
688 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100689 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500690 if (rc)
691 goto out;
692
693 sbsec->sid = fscontext_sid;
694 }
695
696 /*
697 * Switch to using mount point labeling behavior.
698 * sets the label used on all file below the mountpoint, and will set
699 * the superblock context if not already set.
700 */
701 if (context_sid) {
702 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100703 rc = may_context_mount_sb_relabel(context_sid, sbsec,
704 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500705 if (rc)
706 goto out;
707 sbsec->sid = context_sid;
708 } else {
David Howells275bb412008-11-14 10:39:19 +1100709 rc = may_context_mount_inode_relabel(context_sid, sbsec,
710 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500711 if (rc)
712 goto out;
713 }
714 if (!rootcontext_sid)
715 rootcontext_sid = context_sid;
716
717 sbsec->mntpoint_sid = context_sid;
718 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
719 }
720
721 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100722 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
723 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500724 if (rc)
725 goto out;
726
727 root_isec->sid = rootcontext_sid;
728 root_isec->initialized = 1;
729 }
730
731 if (defcontext_sid) {
732 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
733 rc = -EINVAL;
734 printk(KERN_WARNING "SELinux: defcontext option is "
735 "invalid for this filesystem type\n");
736 goto out;
737 }
738
739 if (defcontext_sid != sbsec->def_sid) {
740 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100741 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500742 if (rc)
743 goto out;
744 }
745
746 sbsec->def_sid = defcontext_sid;
747 }
748
749 rc = sb_finish_set_opts(sb);
750out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700751 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500753out_double_mount:
754 rc = -EINVAL;
755 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
756 "security settings for (dev %s, type %s)\n", sb->s_id, name);
757 goto out;
758}
759
760static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
761 struct super_block *newsb)
762{
763 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
764 struct superblock_security_struct *newsbsec = newsb->s_security;
765
766 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
767 int set_context = (oldsbsec->flags & CONTEXT_MNT);
768 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
769
Eric Paris0f5e6422008-04-21 16:24:11 -0400770 /*
771 * if the parent was able to be mounted it clearly had no special lsm
Al Viroe8c26252010-03-23 06:36:54 -0400772 * mount options. thus we can safely deal with this superblock later
Eric Paris0f5e6422008-04-21 16:24:11 -0400773 */
Al Viroe8c26252010-03-23 06:36:54 -0400774 if (!ss_initialized)
Eric Paris0f5e6422008-04-21 16:24:11 -0400775 return;
Eric Parisc9180a52007-11-30 13:00:35 -0500776
Eric Parisc9180a52007-11-30 13:00:35 -0500777 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500778 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500779
Eric Paris5a552612008-04-09 14:08:35 -0400780 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500781 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400782 return;
783
Eric Parisc9180a52007-11-30 13:00:35 -0500784 mutex_lock(&newsbsec->lock);
785
786 newsbsec->flags = oldsbsec->flags;
787
788 newsbsec->sid = oldsbsec->sid;
789 newsbsec->def_sid = oldsbsec->def_sid;
790 newsbsec->behavior = oldsbsec->behavior;
791
792 if (set_context) {
793 u32 sid = oldsbsec->mntpoint_sid;
794
795 if (!set_fscontext)
796 newsbsec->sid = sid;
797 if (!set_rootcontext) {
798 struct inode *newinode = newsb->s_root->d_inode;
799 struct inode_security_struct *newisec = newinode->i_security;
800 newisec->sid = sid;
801 }
802 newsbsec->mntpoint_sid = sid;
803 }
804 if (set_rootcontext) {
805 const struct inode *oldinode = oldsb->s_root->d_inode;
806 const struct inode_security_struct *oldisec = oldinode->i_security;
807 struct inode *newinode = newsb->s_root->d_inode;
808 struct inode_security_struct *newisec = newinode->i_security;
809
810 newisec->sid = oldisec->sid;
811 }
812
813 sb_finish_set_opts(newsb);
814 mutex_unlock(&newsbsec->lock);
815}
816
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200817static int selinux_parse_opts_str(char *options,
818 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500819{
Eric Parise0007522008-03-05 10:31:54 -0500820 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500821 char *context = NULL, *defcontext = NULL;
822 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500823 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500824
Eric Parise0007522008-03-05 10:31:54 -0500825 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500826
827 /* Standard string-based options. */
828 while ((p = strsep(&options, "|")) != NULL) {
829 int token;
830 substring_t args[MAX_OPT_ARGS];
831
832 if (!*p)
833 continue;
834
835 token = match_token(p, tokens, args);
836
837 switch (token) {
838 case Opt_context:
839 if (context || defcontext) {
840 rc = -EINVAL;
841 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
842 goto out_err;
843 }
844 context = match_strdup(&args[0]);
845 if (!context) {
846 rc = -ENOMEM;
847 goto out_err;
848 }
849 break;
850
851 case Opt_fscontext:
852 if (fscontext) {
853 rc = -EINVAL;
854 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
855 goto out_err;
856 }
857 fscontext = match_strdup(&args[0]);
858 if (!fscontext) {
859 rc = -ENOMEM;
860 goto out_err;
861 }
862 break;
863
864 case Opt_rootcontext:
865 if (rootcontext) {
866 rc = -EINVAL;
867 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
868 goto out_err;
869 }
870 rootcontext = match_strdup(&args[0]);
871 if (!rootcontext) {
872 rc = -ENOMEM;
873 goto out_err;
874 }
875 break;
876
877 case Opt_defcontext:
878 if (context || defcontext) {
879 rc = -EINVAL;
880 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
881 goto out_err;
882 }
883 defcontext = match_strdup(&args[0]);
884 if (!defcontext) {
885 rc = -ENOMEM;
886 goto out_err;
887 }
888 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500889 case Opt_labelsupport:
890 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500891 default:
892 rc = -EINVAL;
893 printk(KERN_WARNING "SELinux: unknown mount option\n");
894 goto out_err;
895
896 }
897 }
898
Eric Parise0007522008-03-05 10:31:54 -0500899 rc = -ENOMEM;
900 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
901 if (!opts->mnt_opts)
902 goto out_err;
903
904 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
905 if (!opts->mnt_opts_flags) {
906 kfree(opts->mnt_opts);
907 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500908 }
909
Eric Parise0007522008-03-05 10:31:54 -0500910 if (fscontext) {
911 opts->mnt_opts[num_mnt_opts] = fscontext;
912 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
913 }
914 if (context) {
915 opts->mnt_opts[num_mnt_opts] = context;
916 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
917 }
918 if (rootcontext) {
919 opts->mnt_opts[num_mnt_opts] = rootcontext;
920 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
921 }
922 if (defcontext) {
923 opts->mnt_opts[num_mnt_opts] = defcontext;
924 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
925 }
926
927 opts->num_mnt_opts = num_mnt_opts;
928 return 0;
929
Eric Parisc9180a52007-11-30 13:00:35 -0500930out_err:
931 kfree(context);
932 kfree(defcontext);
933 kfree(fscontext);
934 kfree(rootcontext);
935 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936}
Eric Parise0007522008-03-05 10:31:54 -0500937/*
938 * string mount options parsing and call set the sbsec
939 */
940static int superblock_doinit(struct super_block *sb, void *data)
941{
942 int rc = 0;
943 char *options = data;
944 struct security_mnt_opts opts;
945
946 security_init_mnt_opts(&opts);
947
948 if (!data)
949 goto out;
950
951 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
952
953 rc = selinux_parse_opts_str(options, &opts);
954 if (rc)
955 goto out_err;
956
957out:
958 rc = selinux_set_mnt_opts(sb, &opts);
959
960out_err:
961 security_free_mnt_opts(&opts);
962 return rc;
963}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Adrian Bunk3583a712008-07-22 20:21:23 +0300965static void selinux_write_opts(struct seq_file *m,
966 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000967{
968 int i;
969 char *prefix;
970
971 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -0500972 char *has_comma;
973
974 if (opts->mnt_opts[i])
975 has_comma = strchr(opts->mnt_opts[i], ',');
976 else
977 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +1000978
979 switch (opts->mnt_opts_flags[i]) {
980 case CONTEXT_MNT:
981 prefix = CONTEXT_STR;
982 break;
983 case FSCONTEXT_MNT:
984 prefix = FSCONTEXT_STR;
985 break;
986 case ROOTCONTEXT_MNT:
987 prefix = ROOTCONTEXT_STR;
988 break;
989 case DEFCONTEXT_MNT:
990 prefix = DEFCONTEXT_STR;
991 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500992 case SE_SBLABELSUPP:
993 seq_putc(m, ',');
994 seq_puts(m, LABELSUPP_STR);
995 continue;
Eric Paris2069f452008-07-04 09:47:13 +1000996 default:
997 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -0400998 return;
Eric Paris2069f452008-07-04 09:47:13 +1000999 };
1000 /* we need a comma before each option */
1001 seq_putc(m, ',');
1002 seq_puts(m, prefix);
1003 if (has_comma)
1004 seq_putc(m, '\"');
1005 seq_puts(m, opts->mnt_opts[i]);
1006 if (has_comma)
1007 seq_putc(m, '\"');
1008 }
1009}
1010
1011static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1012{
1013 struct security_mnt_opts opts;
1014 int rc;
1015
1016 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001017 if (rc) {
1018 /* before policy load we may get EINVAL, don't show anything */
1019 if (rc == -EINVAL)
1020 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001021 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001022 }
Eric Paris2069f452008-07-04 09:47:13 +10001023
1024 selinux_write_opts(m, &opts);
1025
1026 security_free_mnt_opts(&opts);
1027
1028 return rc;
1029}
1030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031static inline u16 inode_mode_to_security_class(umode_t mode)
1032{
1033 switch (mode & S_IFMT) {
1034 case S_IFSOCK:
1035 return SECCLASS_SOCK_FILE;
1036 case S_IFLNK:
1037 return SECCLASS_LNK_FILE;
1038 case S_IFREG:
1039 return SECCLASS_FILE;
1040 case S_IFBLK:
1041 return SECCLASS_BLK_FILE;
1042 case S_IFDIR:
1043 return SECCLASS_DIR;
1044 case S_IFCHR:
1045 return SECCLASS_CHR_FILE;
1046 case S_IFIFO:
1047 return SECCLASS_FIFO_FILE;
1048
1049 }
1050
1051 return SECCLASS_FILE;
1052}
1053
James Morris13402582005-09-30 14:24:34 -04001054static inline int default_protocol_stream(int protocol)
1055{
1056 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1057}
1058
1059static inline int default_protocol_dgram(int protocol)
1060{
1061 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1062}
1063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1065{
1066 switch (family) {
1067 case PF_UNIX:
1068 switch (type) {
1069 case SOCK_STREAM:
1070 case SOCK_SEQPACKET:
1071 return SECCLASS_UNIX_STREAM_SOCKET;
1072 case SOCK_DGRAM:
1073 return SECCLASS_UNIX_DGRAM_SOCKET;
1074 }
1075 break;
1076 case PF_INET:
1077 case PF_INET6:
1078 switch (type) {
1079 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001080 if (default_protocol_stream(protocol))
1081 return SECCLASS_TCP_SOCKET;
1082 else
1083 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001085 if (default_protocol_dgram(protocol))
1086 return SECCLASS_UDP_SOCKET;
1087 else
1088 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001089 case SOCK_DCCP:
1090 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001091 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 return SECCLASS_RAWIP_SOCKET;
1093 }
1094 break;
1095 case PF_NETLINK:
1096 switch (protocol) {
1097 case NETLINK_ROUTE:
1098 return SECCLASS_NETLINK_ROUTE_SOCKET;
1099 case NETLINK_FIREWALL:
1100 return SECCLASS_NETLINK_FIREWALL_SOCKET;
Pavel Emelyanov7f1fb602011-12-06 07:56:43 +00001101 case NETLINK_SOCK_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1103 case NETLINK_NFLOG:
1104 return SECCLASS_NETLINK_NFLOG_SOCKET;
1105 case NETLINK_XFRM:
1106 return SECCLASS_NETLINK_XFRM_SOCKET;
1107 case NETLINK_SELINUX:
1108 return SECCLASS_NETLINK_SELINUX_SOCKET;
1109 case NETLINK_AUDIT:
1110 return SECCLASS_NETLINK_AUDIT_SOCKET;
1111 case NETLINK_IP6_FW:
1112 return SECCLASS_NETLINK_IP6FW_SOCKET;
1113 case NETLINK_DNRTMSG:
1114 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001115 case NETLINK_KOBJECT_UEVENT:
1116 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 default:
1118 return SECCLASS_NETLINK_SOCKET;
1119 }
1120 case PF_PACKET:
1121 return SECCLASS_PACKET_SOCKET;
1122 case PF_KEY:
1123 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001124 case PF_APPLETALK:
1125 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 }
1127
1128 return SECCLASS_SOCKET;
1129}
1130
1131#ifdef CONFIG_PROC_FS
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001132static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 u16 tclass,
1134 u32 *sid)
1135{
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001136 int rc;
1137 char *buffer, *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Eric Paris828dfe12008-04-17 13:17:49 -04001139 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (!buffer)
1141 return -ENOMEM;
1142
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001143 path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
1144 if (IS_ERR(path))
1145 rc = PTR_ERR(path);
1146 else {
1147 /* each process gets a /proc/PID/ entry. Strip off the
1148 * PID part to get a valid selinux labeling.
1149 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
1150 while (path[1] >= '0' && path[1] <= '9') {
1151 path[1] = '/';
1152 path++;
1153 }
1154 rc = security_genfs_sid("proc", path, tclass, sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 free_page((unsigned long)buffer);
1157 return rc;
1158}
1159#else
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001160static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 u16 tclass,
1162 u32 *sid)
1163{
1164 return -EINVAL;
1165}
1166#endif
1167
1168/* The inode's security attributes must be initialized before first use. */
1169static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1170{
1171 struct superblock_security_struct *sbsec = NULL;
1172 struct inode_security_struct *isec = inode->i_security;
1173 u32 sid;
1174 struct dentry *dentry;
1175#define INITCONTEXTLEN 255
1176 char *context = NULL;
1177 unsigned len = 0;
1178 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180 if (isec->initialized)
1181 goto out;
1182
Eric Paris23970742006-09-25 23:32:01 -07001183 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001185 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
1187 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001188 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 /* Defer initialization until selinux_complete_init,
1190 after the initial policy is loaded and the security
1191 server is ready to handle calls. */
1192 spin_lock(&sbsec->isec_lock);
1193 if (list_empty(&isec->list))
1194 list_add(&isec->list, &sbsec->isec_head);
1195 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001196 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 }
1198
1199 switch (sbsec->behavior) {
1200 case SECURITY_FS_USE_XATTR:
1201 if (!inode->i_op->getxattr) {
1202 isec->sid = sbsec->def_sid;
1203 break;
1204 }
1205
1206 /* Need a dentry, since the xattr API requires one.
1207 Life would be simpler if we could just pass the inode. */
1208 if (opt_dentry) {
1209 /* Called from d_instantiate or d_splice_alias. */
1210 dentry = dget(opt_dentry);
1211 } else {
1212 /* Called from selinux_complete_init, try to find a dentry. */
1213 dentry = d_find_alias(inode);
1214 }
1215 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001216 /*
1217 * this is can be hit on boot when a file is accessed
1218 * before the policy is loaded. When we load policy we
1219 * may find inodes that have no dentry on the
1220 * sbsec->isec_head list. No reason to complain as these
1221 * will get fixed up the next time we go through
1222 * inode_doinit with a dentry, before these inodes could
1223 * be used again by userspace.
1224 */
Eric Paris23970742006-09-25 23:32:01 -07001225 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 }
1227
1228 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001229 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 if (!context) {
1231 rc = -ENOMEM;
1232 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001233 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001235 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1237 context, len);
1238 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001239 kfree(context);
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 /* Need a larger buffer. Query for the right size. */
1242 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1243 NULL, 0);
1244 if (rc < 0) {
1245 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001246 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001249 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 if (!context) {
1251 rc = -ENOMEM;
1252 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001253 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001255 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 rc = inode->i_op->getxattr(dentry,
1257 XATTR_NAME_SELINUX,
1258 context, len);
1259 }
1260 dput(dentry);
1261 if (rc < 0) {
1262 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001263 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001264 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 -rc, inode->i_sb->s_id, inode->i_ino);
1266 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001267 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 }
1269 /* Map ENODATA to the default file SID */
1270 sid = sbsec->def_sid;
1271 rc = 0;
1272 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001273 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001274 sbsec->def_sid,
1275 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001277 char *dev = inode->i_sb->s_id;
1278 unsigned long ino = inode->i_ino;
1279
1280 if (rc == -EINVAL) {
1281 if (printk_ratelimit())
1282 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1283 "context=%s. This indicates you may need to relabel the inode or the "
1284 "filesystem in question.\n", ino, dev, context);
1285 } else {
1286 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1287 "returned %d for dev=%s ino=%ld\n",
1288 __func__, context, -rc, dev, ino);
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 kfree(context);
1291 /* Leave with the unlabeled SID */
1292 rc = 0;
1293 break;
1294 }
1295 }
1296 kfree(context);
1297 isec->sid = sid;
1298 break;
1299 case SECURITY_FS_USE_TASK:
1300 isec->sid = isec->task_sid;
1301 break;
1302 case SECURITY_FS_USE_TRANS:
1303 /* Default to the fs SID. */
1304 isec->sid = sbsec->sid;
1305
1306 /* Try to obtain a transition SID. */
1307 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Eric Paris652bb9b2011-02-01 11:05:40 -05001308 rc = security_transition_sid(isec->task_sid, sbsec->sid,
1309 isec->sclass, NULL, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001311 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 isec->sid = sid;
1313 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001314 case SECURITY_FS_USE_MNTPOINT:
1315 isec->sid = sbsec->mntpoint_sid;
1316 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001318 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 isec->sid = sbsec->sid;
1320
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001321 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001322 if (opt_dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001324 rc = selinux_proc_get_sid(opt_dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 isec->sclass,
1326 &sid);
1327 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001328 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 isec->sid = sid;
1330 }
1331 }
1332 break;
1333 }
1334
1335 isec->initialized = 1;
1336
Eric Paris23970742006-09-25 23:32:01 -07001337out_unlock:
1338 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339out:
1340 if (isec->sclass == SECCLASS_FILE)
1341 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 return rc;
1343}
1344
1345/* Convert a Linux signal to an access vector. */
1346static inline u32 signal_to_av(int sig)
1347{
1348 u32 perm = 0;
1349
1350 switch (sig) {
1351 case SIGCHLD:
1352 /* Commonly granted from child to parent. */
1353 perm = PROCESS__SIGCHLD;
1354 break;
1355 case SIGKILL:
1356 /* Cannot be caught or ignored */
1357 perm = PROCESS__SIGKILL;
1358 break;
1359 case SIGSTOP:
1360 /* Cannot be caught or ignored */
1361 perm = PROCESS__SIGSTOP;
1362 break;
1363 default:
1364 /* All other signals. */
1365 perm = PROCESS__SIGNAL;
1366 break;
1367 }
1368
1369 return perm;
1370}
1371
David Howells275bb412008-11-14 10:39:19 +11001372/*
David Howellsd84f4f92008-11-14 10:39:23 +11001373 * Check permission between a pair of credentials
1374 * fork check, ptrace check, etc.
1375 */
1376static int cred_has_perm(const struct cred *actor,
1377 const struct cred *target,
1378 u32 perms)
1379{
1380 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1381
1382 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1383}
1384
1385/*
David Howells88e67f32008-11-14 10:39:21 +11001386 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001387 * fork check, ptrace check, etc.
1388 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001389 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001390 */
1391static int task_has_perm(const struct task_struct *tsk1,
1392 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 u32 perms)
1394{
David Howells275bb412008-11-14 10:39:19 +11001395 const struct task_security_struct *__tsec1, *__tsec2;
1396 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
David Howells275bb412008-11-14 10:39:19 +11001398 rcu_read_lock();
1399 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1400 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1401 rcu_read_unlock();
1402 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403}
1404
David Howells3b11a1d2008-11-14 10:39:26 +11001405/*
1406 * Check permission between current and another task, e.g. signal checks,
1407 * fork check, ptrace check, etc.
1408 * current is the actor and tsk2 is the target
1409 * - this uses current's subjective creds
1410 */
1411static int current_has_perm(const struct task_struct *tsk,
1412 u32 perms)
1413{
1414 u32 sid, tsid;
1415
1416 sid = current_sid();
1417 tsid = task_sid(tsk);
1418 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1419}
1420
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001421#if CAP_LAST_CAP > 63
1422#error Fix SELinux to handle capabilities > 63.
1423#endif
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425/* Check whether a task is allowed to use a capability. */
Eric Paris6a9de492012-01-03 12:25:14 -05001426static int cred_has_capability(const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001427 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428{
Thomas Liu2bf49692009-07-14 12:14:09 -04001429 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001430 struct selinux_audit_data sad = {0,};
Eric Paris06112162008-11-11 22:02:50 +11001431 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001432 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001433 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001434 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001435 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
Thomas Liu2bf49692009-07-14 12:14:09 -04001437 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001438 ad.selinux_audit_data = &sad;
Eric Paris6a9de492012-01-03 12:25:14 -05001439 ad.tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 ad.u.cap = cap;
1441
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001442 switch (CAP_TO_INDEX(cap)) {
1443 case 0:
1444 sclass = SECCLASS_CAPABILITY;
1445 break;
1446 case 1:
1447 sclass = SECCLASS_CAPABILITY2;
1448 break;
1449 default:
1450 printk(KERN_ERR
1451 "SELinux: out of range capability %d\n", cap);
1452 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001453 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001454 }
Eric Paris06112162008-11-11 22:02:50 +11001455
David Howells275bb412008-11-14 10:39:19 +11001456 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001457 if (audit == SECURITY_CAP_AUDIT) {
1458 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1459 if (rc2)
1460 return rc2;
1461 }
Eric Paris06112162008-11-11 22:02:50 +11001462 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463}
1464
1465/* Check whether a task is allowed to use a system operation. */
1466static int task_has_system(struct task_struct *tsk,
1467 u32 perms)
1468{
David Howells275bb412008-11-14 10:39:19 +11001469 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
David Howells275bb412008-11-14 10:39:19 +11001471 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 SECCLASS_SYSTEM, perms, NULL);
1473}
1474
1475/* Check whether a task has a particular permission to an inode.
1476 The 'adp' parameter is optional and allows other audit
1477 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001478static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 struct inode *inode,
1480 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001481 struct common_audit_data *adp,
1482 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001485 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
David Howellse0e81732009-09-02 09:13:40 +01001487 validate_creds(cred);
1488
Eric Paris828dfe12008-04-17 13:17:49 -04001489 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001490 return 0;
1491
David Howells88e67f32008-11-14 10:39:21 +11001492 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 isec = inode->i_security;
1494
Eric Paris9ade0cf2011-04-25 16:26:29 -04001495 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496}
1497
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001498static int inode_has_perm_noadp(const struct cred *cred,
1499 struct inode *inode,
1500 u32 perms,
1501 unsigned flags)
1502{
1503 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001504 struct selinux_audit_data sad = {0,};
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001505
1506 COMMON_AUDIT_DATA_INIT(&ad, INODE);
1507 ad.u.inode = inode;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001508 ad.selinux_audit_data = &sad;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07001509 return inode_has_perm(cred, inode, perms, &ad, flags);
1510}
1511
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512/* Same as inode_has_perm, but pass explicit audit data containing
1513 the dentry to help the auditing code to more easily generate the
1514 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001515static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 struct dentry *dentry,
1517 u32 av)
1518{
1519 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001520 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001521 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001522
Eric Paris2875fa02011-04-28 16:04:24 -04001523 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1524 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001525 ad.selinux_audit_data = &sad;
Eric Paris2875fa02011-04-28 16:04:24 -04001526 return inode_has_perm(cred, inode, av, &ad, 0);
1527}
1528
1529/* Same as inode_has_perm, but pass explicit audit data containing
1530 the path to help the auditing code to more easily generate the
1531 pathname if needed. */
1532static inline int path_has_perm(const struct cred *cred,
1533 struct path *path,
1534 u32 av)
1535{
1536 struct inode *inode = path->dentry->d_inode;
1537 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001538 struct selinux_audit_data sad = {0,};
Eric Paris2875fa02011-04-28 16:04:24 -04001539
Eric Parisf48b7392011-04-25 12:54:27 -04001540 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001541 ad.u.path = *path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001542 ad.selinux_audit_data = &sad;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001543 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544}
1545
1546/* Check whether a task can use an open file descriptor to
1547 access an inode in a given way. Check access to the
1548 descriptor itself, and then use dentry_has_perm to
1549 check a particular permission to the file.
1550 Access to the descriptor is implicitly granted if it
1551 has the same SID as the process. If av is zero, then
1552 access to the file is not checked, e.g. for cases
1553 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001554static int file_has_perm(const struct cred *cred,
1555 struct file *file,
1556 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001559 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001560 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001561 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001562 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 int rc;
1564
Eric Parisf48b7392011-04-25 12:54:27 -04001565 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1566 ad.u.path = file->f_path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001567 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
David Howells275bb412008-11-14 10:39:19 +11001569 if (sid != fsec->sid) {
1570 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 SECCLASS_FD,
1572 FD__USE,
1573 &ad);
1574 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001575 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 }
1577
1578 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001579 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001581 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
David Howells88e67f32008-11-14 10:39:21 +11001583out:
1584 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585}
1586
1587/* Check whether a task can create a file. */
1588static int may_create(struct inode *dir,
1589 struct dentry *dentry,
1590 u16 tclass)
1591{
Paul Moore5fb49872010-04-22 14:46:19 -04001592 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 struct inode_security_struct *dsec;
1594 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001595 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001596 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001597 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 int rc;
1599
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 dsec = dir->i_security;
1601 sbsec = dir->i_sb->s_security;
1602
David Howells275bb412008-11-14 10:39:19 +11001603 sid = tsec->sid;
1604 newsid = tsec->create_sid;
1605
Eric Parisa2694342011-04-25 13:10:27 -04001606 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1607 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001608 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
David Howells275bb412008-11-14 10:39:19 +11001610 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 DIR__ADD_NAME | DIR__SEARCH,
1612 &ad);
1613 if (rc)
1614 return rc;
1615
David P. Quigleycd895962009-01-16 09:22:04 -05001616 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001617 rc = security_transition_sid(sid, dsec->sid, tclass,
1618 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 if (rc)
1620 return rc;
1621 }
1622
David Howells275bb412008-11-14 10:39:19 +11001623 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 if (rc)
1625 return rc;
1626
1627 return avc_has_perm(newsid, sbsec->sid,
1628 SECCLASS_FILESYSTEM,
1629 FILESYSTEM__ASSOCIATE, &ad);
1630}
1631
Michael LeMay4eb582c2006-06-26 00:24:57 -07001632/* Check whether a task can create a key. */
1633static int may_create_key(u32 ksid,
1634 struct task_struct *ctx)
1635{
David Howells275bb412008-11-14 10:39:19 +11001636 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001637
David Howells275bb412008-11-14 10:39:19 +11001638 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001639}
1640
Eric Paris828dfe12008-04-17 13:17:49 -04001641#define MAY_LINK 0
1642#define MAY_UNLINK 1
1643#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
1645/* Check whether a task can link, unlink, or rmdir a file/directory. */
1646static int may_link(struct inode *dir,
1647 struct dentry *dentry,
1648 int kind)
1649
1650{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001652 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001653 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001654 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 u32 av;
1656 int rc;
1657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 dsec = dir->i_security;
1659 isec = dentry->d_inode->i_security;
1660
Eric Parisa2694342011-04-25 13:10:27 -04001661 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1662 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001663 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
1665 av = DIR__SEARCH;
1666 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001667 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 if (rc)
1669 return rc;
1670
1671 switch (kind) {
1672 case MAY_LINK:
1673 av = FILE__LINK;
1674 break;
1675 case MAY_UNLINK:
1676 av = FILE__UNLINK;
1677 break;
1678 case MAY_RMDIR:
1679 av = DIR__RMDIR;
1680 break;
1681 default:
Eric Paris744ba352008-04-17 11:52:44 -04001682 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1683 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 return 0;
1685 }
1686
David Howells275bb412008-11-14 10:39:19 +11001687 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 return rc;
1689}
1690
1691static inline int may_rename(struct inode *old_dir,
1692 struct dentry *old_dentry,
1693 struct inode *new_dir,
1694 struct dentry *new_dentry)
1695{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001697 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001698 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001699 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 u32 av;
1701 int old_is_dir, new_is_dir;
1702 int rc;
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 old_dsec = old_dir->i_security;
1705 old_isec = old_dentry->d_inode->i_security;
1706 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1707 new_dsec = new_dir->i_security;
1708
Eric Parisa2694342011-04-25 13:10:27 -04001709 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001710 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
Eric Parisa2694342011-04-25 13:10:27 -04001712 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001713 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1715 if (rc)
1716 return rc;
David Howells275bb412008-11-14 10:39:19 +11001717 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 old_isec->sclass, FILE__RENAME, &ad);
1719 if (rc)
1720 return rc;
1721 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001722 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 old_isec->sclass, DIR__REPARENT, &ad);
1724 if (rc)
1725 return rc;
1726 }
1727
Eric Parisa2694342011-04-25 13:10:27 -04001728 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 av = DIR__ADD_NAME | DIR__SEARCH;
1730 if (new_dentry->d_inode)
1731 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001732 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 if (rc)
1734 return rc;
1735 if (new_dentry->d_inode) {
1736 new_isec = new_dentry->d_inode->i_security;
1737 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001738 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 new_isec->sclass,
1740 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1741 if (rc)
1742 return rc;
1743 }
1744
1745 return 0;
1746}
1747
1748/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001749static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 struct super_block *sb,
1751 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001752 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001755 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001758 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759}
1760
1761/* Convert a Linux mode and permission mask to an access vector. */
1762static inline u32 file_mask_to_av(int mode, int mask)
1763{
1764 u32 av = 0;
1765
Al Virodba19c62011-07-25 20:49:29 -04001766 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 if (mask & MAY_EXEC)
1768 av |= FILE__EXECUTE;
1769 if (mask & MAY_READ)
1770 av |= FILE__READ;
1771
1772 if (mask & MAY_APPEND)
1773 av |= FILE__APPEND;
1774 else if (mask & MAY_WRITE)
1775 av |= FILE__WRITE;
1776
1777 } else {
1778 if (mask & MAY_EXEC)
1779 av |= DIR__SEARCH;
1780 if (mask & MAY_WRITE)
1781 av |= DIR__WRITE;
1782 if (mask & MAY_READ)
1783 av |= DIR__READ;
1784 }
1785
1786 return av;
1787}
1788
1789/* Convert a Linux file to an access vector. */
1790static inline u32 file_to_av(struct file *file)
1791{
1792 u32 av = 0;
1793
1794 if (file->f_mode & FMODE_READ)
1795 av |= FILE__READ;
1796 if (file->f_mode & FMODE_WRITE) {
1797 if (file->f_flags & O_APPEND)
1798 av |= FILE__APPEND;
1799 else
1800 av |= FILE__WRITE;
1801 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001802 if (!av) {
1803 /*
1804 * Special file opened with flags 3 for ioctl-only use.
1805 */
1806 av = FILE__IOCTL;
1807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
1809 return av;
1810}
1811
Eric Paris8b6a5a32008-10-29 17:06:46 -04001812/*
1813 * Convert a file to an access vector and include the correct open
1814 * open permission.
1815 */
1816static inline u32 open_file_to_av(struct file *file)
1817{
1818 u32 av = file_to_av(file);
1819
Eric Paris49b7b8d2010-07-23 11:44:09 -04001820 if (selinux_policycap_openperm)
1821 av |= FILE__OPEN;
1822
Eric Paris8b6a5a32008-10-29 17:06:46 -04001823 return av;
1824}
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826/* Hook functions begin here. */
1827
Stephen Smalley84ab2cd2012-11-05 08:15:34 -05001828static int selinux_binder_set_context_mgr(struct task_struct *mgr)
1829{
1830 u32 mysid = current_sid();
1831 u32 mgrsid = task_sid(mgr);
1832
1833 return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL);
1834}
1835
1836static int selinux_binder_transaction(struct task_struct *from, struct task_struct *to)
1837{
1838 u32 mysid = current_sid();
1839 u32 fromsid = task_sid(from);
1840 u32 tosid = task_sid(to);
1841 int rc;
1842
1843 if (mysid != fromsid) {
1844 rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL);
1845 if (rc)
1846 return rc;
1847 }
1848
1849 return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL);
1850}
1851
1852static int selinux_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
1853{
1854 u32 fromsid = task_sid(from);
1855 u32 tosid = task_sid(to);
1856 return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
1857}
1858
1859static int selinux_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
1860{
1861 u32 sid = task_sid(to);
1862 struct file_security_struct *fsec = file->f_security;
1863 struct inode *inode = file->f_path.dentry->d_inode;
1864 struct inode_security_struct *isec = inode->i_security;
1865 struct common_audit_data ad;
1866 struct selinux_audit_data sad = {0,};
1867 int rc;
1868
1869 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1870 ad.u.path = file->f_path;
1871 ad.selinux_audit_data = &sad;
1872
1873 if (sid != fsec->sid) {
1874 rc = avc_has_perm(sid, fsec->sid,
1875 SECCLASS_FD,
1876 FD__USE,
1877 &ad);
1878 if (rc)
1879 return rc;
1880 }
1881
1882 if (unlikely(IS_PRIVATE(inode)))
1883 return 0;
1884
1885 return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
1886 &ad);
1887}
1888
Ingo Molnar9e488582009-05-07 19:26:19 +10001889static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001890 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 int rc;
1893
Ingo Molnar9e488582009-05-07 19:26:19 +10001894 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (rc)
1896 return rc;
1897
Eric Paris69f594a2012-01-03 12:25:15 -05001898 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001899 u32 sid = current_sid();
1900 u32 csid = task_sid(child);
1901 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001902 }
1903
David Howells3b11a1d2008-11-14 10:39:26 +11001904 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001905}
1906
1907static int selinux_ptrace_traceme(struct task_struct *parent)
1908{
1909 int rc;
1910
Eric Paris200ac532009-02-12 15:01:04 -05001911 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001912 if (rc)
1913 return rc;
1914
1915 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916}
1917
1918static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001919 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
1921 int error;
1922
David Howells3b11a1d2008-11-14 10:39:26 +11001923 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (error)
1925 return error;
1926
Eric Paris200ac532009-02-12 15:01:04 -05001927 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928}
1929
David Howellsd84f4f92008-11-14 10:39:23 +11001930static int selinux_capset(struct cred *new, const struct cred *old,
1931 const kernel_cap_t *effective,
1932 const kernel_cap_t *inheritable,
1933 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934{
1935 int error;
1936
Eric Paris200ac532009-02-12 15:01:04 -05001937 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001938 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 if (error)
1940 return error;
1941
David Howellsd84f4f92008-11-14 10:39:23 +11001942 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943}
1944
James Morris5626d3e2009-01-30 10:05:06 +11001945/*
1946 * (This comment used to live with the selinux_task_setuid hook,
1947 * which was removed).
1948 *
1949 * Since setuid only affects the current process, and since the SELinux
1950 * controls are not based on the Linux identity attributes, SELinux does not
1951 * need to control this operation. However, SELinux does control the use of
1952 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1953 */
1954
Eric Paris6a9de492012-01-03 12:25:14 -05001955static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1956 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957{
1958 int rc;
1959
Eric Paris6a9de492012-01-03 12:25:14 -05001960 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (rc)
1962 return rc;
1963
Eric Paris6a9de492012-01-03 12:25:14 -05001964 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965}
1966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1968{
David Howells88e67f32008-11-14 10:39:21 +11001969 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 int rc = 0;
1971
1972 if (!sb)
1973 return 0;
1974
1975 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001976 case Q_SYNC:
1977 case Q_QUOTAON:
1978 case Q_QUOTAOFF:
1979 case Q_SETINFO:
1980 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001981 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001982 break;
1983 case Q_GETFMT:
1984 case Q_GETINFO:
1985 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001986 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001987 break;
1988 default:
1989 rc = 0; /* let the kernel handle invalid cmds */
1990 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 }
1992 return rc;
1993}
1994
1995static int selinux_quota_on(struct dentry *dentry)
1996{
David Howells88e67f32008-11-14 10:39:21 +11001997 const struct cred *cred = current_cred();
1998
Eric Paris2875fa02011-04-28 16:04:24 -04001999 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000}
2001
Eric Paris12b30522010-11-15 18:36:29 -05002002static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003{
2004 int rc;
2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08002007 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
2008 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04002009 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
2010 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08002011 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
2012 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
2013 /* Set level of messages printed to console */
2014 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04002015 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
2016 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08002017 case SYSLOG_ACTION_CLOSE: /* Close log */
2018 case SYSLOG_ACTION_OPEN: /* Open log */
2019 case SYSLOG_ACTION_READ: /* Read from log */
2020 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
2021 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04002022 default:
2023 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
2024 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026 return rc;
2027}
2028
2029/*
2030 * Check that a process has enough memory to allocate a new virtual
2031 * mapping. 0 means there is enough memory for the allocation to
2032 * succeed and -ENOMEM implies there is not.
2033 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 * Do not audit the selinux permission check, as this is applied to all
2035 * processes that allocate mappings.
2036 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07002037static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038{
2039 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
Eric Paris6a9de492012-01-03 12:25:14 -05002041 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002042 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 if (rc == 0)
2044 cap_sys_admin = 1;
2045
Alan Cox34b4e4a2007-08-22 14:01:28 -07002046 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047}
2048
2049/* binprm security operations */
2050
David Howellsa6f76f22008-11-14 10:39:24 +11002051static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052{
David Howellsa6f76f22008-11-14 10:39:24 +11002053 const struct task_security_struct *old_tsec;
2054 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002056 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002057 struct selinux_audit_data sad = {0,};
David Howellsa6f76f22008-11-14 10:39:24 +11002058 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 int rc;
2060
Eric Paris200ac532009-02-12 15:01:04 -05002061 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc)
2063 return rc;
2064
David Howellsa6f76f22008-11-14 10:39:24 +11002065 /* SELinux context only depends on initial program or script and not
2066 * the script interpreter */
2067 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 return 0;
2069
David Howellsa6f76f22008-11-14 10:39:24 +11002070 old_tsec = current_security();
2071 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 isec = inode->i_security;
2073
2074 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11002075 new_tsec->sid = old_tsec->sid;
2076 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Michael LeMay28eba5b2006-06-27 02:53:42 -07002078 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002079 new_tsec->create_sid = 0;
2080 new_tsec->keycreate_sid = 0;
2081 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
David Howellsa6f76f22008-11-14 10:39:24 +11002083 if (old_tsec->exec_sid) {
2084 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002086 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 } else {
2088 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002089 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002090 SECCLASS_PROCESS, NULL,
2091 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 if (rc)
2093 return rc;
2094 }
2095
Eric Parisf48b7392011-04-25 12:54:27 -04002096 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002097 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002098 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Josef Sipek3d5ff522006-12-08 02:37:38 -08002100 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002101 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
David Howellsa6f76f22008-11-14 10:39:24 +11002103 if (new_tsec->sid == old_tsec->sid) {
2104 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2106 if (rc)
2107 return rc;
2108 } else {
2109 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002110 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2112 if (rc)
2113 return rc;
2114
David Howellsa6f76f22008-11-14 10:39:24 +11002115 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2117 if (rc)
2118 return rc;
2119
David Howellsa6f76f22008-11-14 10:39:24 +11002120 /* Check for shared state */
2121 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2122 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2123 SECCLASS_PROCESS, PROCESS__SHARE,
2124 NULL);
2125 if (rc)
2126 return -EPERM;
2127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
David Howellsa6f76f22008-11-14 10:39:24 +11002129 /* Make sure that anyone attempting to ptrace over a task that
2130 * changes its SID has the appropriate permit */
2131 if (bprm->unsafe &
2132 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2133 struct task_struct *tracer;
2134 struct task_security_struct *sec;
2135 u32 ptsid = 0;
2136
2137 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002138 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002139 if (likely(tracer != NULL)) {
2140 sec = __task_cred(tracer)->security;
2141 ptsid = sec->sid;
2142 }
2143 rcu_read_unlock();
2144
2145 if (ptsid != 0) {
2146 rc = avc_has_perm(ptsid, new_tsec->sid,
2147 SECCLASS_PROCESS,
2148 PROCESS__PTRACE, NULL);
2149 if (rc)
2150 return -EPERM;
2151 }
2152 }
2153
2154 /* Clear any possibly unsafe personality bits on exec: */
2155 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 return 0;
2159}
2160
Eric Paris828dfe12008-04-17 13:17:49 -04002161static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162{
Paul Moore5fb49872010-04-22 14:46:19 -04002163 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002164 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 int atsecure = 0;
2166
David Howells275bb412008-11-14 10:39:19 +11002167 sid = tsec->sid;
2168 osid = tsec->osid;
2169
2170 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 /* Enable secure mode for SIDs transitions unless
2172 the noatsecure permission is granted between
2173 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002174 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002175 SECCLASS_PROCESS,
2176 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 }
2178
Eric Paris200ac532009-02-12 15:01:04 -05002179 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180}
2181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002183static inline void flush_unauthorized_files(const struct cred *cred,
2184 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185{
Thomas Liu2bf49692009-07-14 12:14:09 -04002186 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002187 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002189 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002190 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002192 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002194 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002196 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002197 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002198 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002199 struct inode *inode;
2200
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 /* Revalidate access to controlling tty.
2202 Use inode_has_perm on the tty inode directly rather
2203 than using file_has_perm, as this particular open
2204 file may belong to another process and we are only
2205 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002206 file_priv = list_first_entry(&tty->tty_files,
2207 struct tty_file_private, list);
2208 file = file_priv->file;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002209 inode = file->f_path.dentry->d_inode;
Linus Torvalds95f4efb2011-06-08 15:11:56 -07002210 if (inode_has_perm_noadp(cred, inode,
2211 FILE__READ | FILE__WRITE, 0)) {
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002212 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 }
2214 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002215 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002216 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002218 /* Reset controlling tty. */
2219 if (drop_tty)
2220 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 /* Revalidate access to inherited open files. */
2223
Eric Parisf48b7392011-04-25 12:54:27 -04002224 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002225 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
2227 spin_lock(&files->file_lock);
2228 for (;;) {
2229 unsigned long set, i;
2230 int fd;
2231
2232 j++;
Josh Boyer27cd8f52012-07-25 10:40:34 -04002233 i = j * BITS_PER_LONG;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002234 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002235 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 break;
David Howells1fd36ad2012-02-16 17:49:54 +00002237 set = fdt->open_fds[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 if (!set)
2239 continue;
2240 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002241 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (set & 1) {
2243 file = fget(i);
2244 if (!file)
2245 continue;
David Howells88e67f32008-11-14 10:39:21 +11002246 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 file,
2248 file_to_av(file))) {
2249 sys_close(i);
2250 fd = get_unused_fd();
2251 if (fd != i) {
2252 if (fd >= 0)
2253 put_unused_fd(fd);
2254 fput(file);
2255 continue;
2256 }
2257 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002258 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 } else {
David Howells745ca242008-11-14 10:39:22 +11002260 devnull = dentry_open(
2261 dget(selinux_null),
2262 mntget(selinuxfs_mount),
2263 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002264 if (IS_ERR(devnull)) {
2265 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 put_unused_fd(fd);
2267 fput(file);
2268 continue;
2269 }
2270 }
2271 fd_install(fd, devnull);
2272 }
2273 fput(file);
2274 }
2275 }
2276 spin_lock(&files->file_lock);
2277
2278 }
2279 spin_unlock(&files->file_lock);
2280}
2281
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282/*
David Howellsa6f76f22008-11-14 10:39:24 +11002283 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 */
David Howellsa6f76f22008-11-14 10:39:24 +11002285static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
David Howellsa6f76f22008-11-14 10:39:24 +11002287 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 int rc, i;
2290
David Howellsa6f76f22008-11-14 10:39:24 +11002291 new_tsec = bprm->cred->security;
2292 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 return;
2294
2295 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002296 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
David Howellsa6f76f22008-11-14 10:39:24 +11002298 /* Always clear parent death signal on SID transitions. */
2299 current->pdeath_signal = 0;
2300
2301 /* Check whether the new SID can inherit resource limits from the old
2302 * SID. If not, reset all soft limits to the lower of the current
2303 * task's hard limit and the init task's soft limit.
2304 *
2305 * Note that the setting of hard limits (even to lower them) can be
2306 * controlled by the setrlimit check. The inclusion of the init task's
2307 * soft limit into the computation is to avoid resetting soft limits
2308 * higher than the default soft limit for cases where the default is
2309 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2310 */
2311 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2312 PROCESS__RLIMITINH, NULL);
2313 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002314 /* protect against do_prlimit() */
2315 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002316 for (i = 0; i < RLIM_NLIMITS; i++) {
2317 rlim = current->signal->rlim + i;
2318 initrlim = init_task.signal->rlim + i;
2319 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2320 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002321 task_unlock(current);
2322 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002323 }
2324}
2325
2326/*
2327 * Clean up the process immediately after the installation of new credentials
2328 * due to exec
2329 */
2330static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2331{
2332 const struct task_security_struct *tsec = current_security();
2333 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002334 u32 osid, sid;
2335 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002336
David Howellsa6f76f22008-11-14 10:39:24 +11002337 osid = tsec->osid;
2338 sid = tsec->sid;
2339
2340 if (sid == osid)
2341 return;
2342
2343 /* Check whether the new SID can inherit signal state from the old SID.
2344 * If not, clear itimers to avoid subsequent signal generation and
2345 * flush and unblock signals.
2346 *
2347 * This must occur _after_ the task SID has been updated so that any
2348 * kill done after the flush will be checked against the new SID.
2349 */
2350 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 if (rc) {
2352 memset(&itimer, 0, sizeof itimer);
2353 for (i = 0; i < 3; i++)
2354 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002356 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2357 __flush_signals(current);
2358 flush_signal_handlers(current, 1);
2359 sigemptyset(&current->blocked);
2360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 spin_unlock_irq(&current->sighand->siglock);
2362 }
2363
David Howellsa6f76f22008-11-14 10:39:24 +11002364 /* Wake up the parent if it is waiting so that it can recheck
2365 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002366 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002367 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002368 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369}
2370
2371/* superblock security operations */
2372
2373static int selinux_sb_alloc_security(struct super_block *sb)
2374{
2375 return superblock_alloc_security(sb);
2376}
2377
2378static void selinux_sb_free_security(struct super_block *sb)
2379{
2380 superblock_free_security(sb);
2381}
2382
2383static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2384{
2385 if (plen > olen)
2386 return 0;
2387
2388 return !memcmp(prefix, option, plen);
2389}
2390
2391static inline int selinux_option(char *option, int len)
2392{
Eric Paris832cbd92008-04-01 13:24:09 -04002393 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2394 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2395 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002396 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2397 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398}
2399
2400static inline void take_option(char **to, char *from, int *first, int len)
2401{
2402 if (!*first) {
2403 **to = ',';
2404 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002405 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 *first = 0;
2407 memcpy(*to, from, len);
2408 *to += len;
2409}
2410
Eric Paris828dfe12008-04-17 13:17:49 -04002411static inline void take_selinux_option(char **to, char *from, int *first,
2412 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002413{
2414 int current_size = 0;
2415
2416 if (!*first) {
2417 **to = '|';
2418 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002419 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002420 *first = 0;
2421
2422 while (current_size < len) {
2423 if (*from != '"') {
2424 **to = *from;
2425 *to += 1;
2426 }
2427 from += 1;
2428 current_size += 1;
2429 }
2430}
2431
Eric Parise0007522008-03-05 10:31:54 -05002432static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433{
2434 int fnosec, fsec, rc = 0;
2435 char *in_save, *in_curr, *in_end;
2436 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002437 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
2439 in_curr = orig;
2440 sec_curr = copy;
2441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2443 if (!nosec) {
2444 rc = -ENOMEM;
2445 goto out;
2446 }
2447
2448 nosec_save = nosec;
2449 fnosec = fsec = 1;
2450 in_save = in_end = orig;
2451
2452 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002453 if (*in_end == '"')
2454 open_quote = !open_quote;
2455 if ((*in_end == ',' && open_quote == 0) ||
2456 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 int len = in_end - in_curr;
2458
2459 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002460 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 else
2462 take_option(&nosec, in_curr, &fnosec, len);
2463
2464 in_curr = in_end + 1;
2465 }
2466 } while (*in_end++);
2467
Eric Paris6931dfc2005-06-30 02:58:51 -07002468 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002469 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470out:
2471 return rc;
2472}
2473
Eric Paris026eb162011-03-03 16:09:14 -05002474static int selinux_sb_remount(struct super_block *sb, void *data)
2475{
2476 int rc, i, *flags;
2477 struct security_mnt_opts opts;
2478 char *secdata, **mount_options;
2479 struct superblock_security_struct *sbsec = sb->s_security;
2480
2481 if (!(sbsec->flags & SE_SBINITIALIZED))
2482 return 0;
2483
2484 if (!data)
2485 return 0;
2486
2487 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2488 return 0;
2489
2490 security_init_mnt_opts(&opts);
2491 secdata = alloc_secdata();
2492 if (!secdata)
2493 return -ENOMEM;
2494 rc = selinux_sb_copy_data(data, secdata);
2495 if (rc)
2496 goto out_free_secdata;
2497
2498 rc = selinux_parse_opts_str(secdata, &opts);
2499 if (rc)
2500 goto out_free_secdata;
2501
2502 mount_options = opts.mnt_opts;
2503 flags = opts.mnt_opts_flags;
2504
2505 for (i = 0; i < opts.num_mnt_opts; i++) {
2506 u32 sid;
2507 size_t len;
2508
2509 if (flags[i] == SE_SBLABELSUPP)
2510 continue;
2511 len = strlen(mount_options[i]);
2512 rc = security_context_to_sid(mount_options[i], len, &sid);
2513 if (rc) {
2514 printk(KERN_WARNING "SELinux: security_context_to_sid"
2515 "(%s) failed for (dev %s, type %s) errno=%d\n",
2516 mount_options[i], sb->s_id, sb->s_type->name, rc);
2517 goto out_free_opts;
2518 }
2519 rc = -EINVAL;
2520 switch (flags[i]) {
2521 case FSCONTEXT_MNT:
2522 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2523 goto out_bad_option;
2524 break;
2525 case CONTEXT_MNT:
2526 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2527 goto out_bad_option;
2528 break;
2529 case ROOTCONTEXT_MNT: {
2530 struct inode_security_struct *root_isec;
2531 root_isec = sb->s_root->d_inode->i_security;
2532
2533 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2534 goto out_bad_option;
2535 break;
2536 }
2537 case DEFCONTEXT_MNT:
2538 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2539 goto out_bad_option;
2540 break;
2541 default:
2542 goto out_free_opts;
2543 }
2544 }
2545
2546 rc = 0;
2547out_free_opts:
2548 security_free_mnt_opts(&opts);
2549out_free_secdata:
2550 free_secdata(secdata);
2551 return rc;
2552out_bad_option:
2553 printk(KERN_WARNING "SELinux: unable to change security options "
2554 "during remount (dev %s, type=%s)\n", sb->s_id,
2555 sb->s_type->name);
2556 goto out_free_opts;
2557}
2558
James Morris12204e22008-12-19 10:44:42 +11002559static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560{
David Howells88e67f32008-11-14 10:39:21 +11002561 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002562 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002563 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 int rc;
2565
2566 rc = superblock_doinit(sb, data);
2567 if (rc)
2568 return rc;
2569
James Morris74192242008-12-19 11:41:10 +11002570 /* Allow all mounts performed by the kernel */
2571 if (flags & MS_KERNMOUNT)
2572 return 0;
2573
Eric Parisa2694342011-04-25 13:10:27 -04002574 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002575 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002576 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002577 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578}
2579
David Howells726c3342006-06-23 02:02:58 -07002580static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581{
David Howells88e67f32008-11-14 10:39:21 +11002582 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002583 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002584 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585
Eric Parisa2694342011-04-25 13:10:27 -04002586 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002587 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002588 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002589 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590}
2591
Eric Paris828dfe12008-04-17 13:17:49 -04002592static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002593 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002594 char *type,
2595 unsigned long flags,
2596 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597{
David Howells88e67f32008-11-14 10:39:21 +11002598 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599
2600 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002601 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002602 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 else
Eric Paris2875fa02011-04-28 16:04:24 -04002604 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605}
2606
2607static int selinux_umount(struct vfsmount *mnt, int flags)
2608{
David Howells88e67f32008-11-14 10:39:21 +11002609 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
David Howells88e67f32008-11-14 10:39:21 +11002611 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002612 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613}
2614
2615/* inode security operations */
2616
2617static int selinux_inode_alloc_security(struct inode *inode)
2618{
2619 return inode_alloc_security(inode);
2620}
2621
2622static void selinux_inode_free_security(struct inode *inode)
2623{
2624 inode_free_security(inode);
2625}
2626
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002627static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002628 const struct qstr *qstr, char **name,
2629 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002630{
Paul Moore5fb49872010-04-22 14:46:19 -04002631 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002632 struct inode_security_struct *dsec;
2633 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002634 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002635 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002636 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002637
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002638 dsec = dir->i_security;
2639 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002640
David Howells275bb412008-11-14 10:39:19 +11002641 sid = tsec->sid;
2642 newsid = tsec->create_sid;
2643
Eric Paris415103f2010-12-02 16:13:40 -05002644 if ((sbsec->flags & SE_SBINITIALIZED) &&
2645 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2646 newsid = sbsec->mntpoint_sid;
2647 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002648 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002649 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002650 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002651 if (rc) {
2652 printk(KERN_WARNING "%s: "
2653 "security_transition_sid failed, rc=%d (dev=%s "
2654 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002655 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002656 -rc, inode->i_sb->s_id, inode->i_ino);
2657 return rc;
2658 }
2659 }
2660
Eric Paris296fddf2006-09-25 23:32:00 -07002661 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002662 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002663 struct inode_security_struct *isec = inode->i_security;
2664 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2665 isec->sid = newsid;
2666 isec->initialized = 1;
2667 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002668
David P. Quigleycd895962009-01-16 09:22:04 -05002669 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002670 return -EOPNOTSUPP;
2671
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002672 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002673 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002674 if (!namep)
2675 return -ENOMEM;
2676 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002677 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002678
2679 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002680 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002681 if (rc) {
2682 kfree(namep);
2683 return rc;
2684 }
2685 *value = context;
2686 *len = clen;
2687 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002688
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002689 return 0;
2690}
2691
Al Viro4acdaf22011-07-26 01:42:34 -04002692static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
2694 return may_create(dir, dentry, SECCLASS_FILE);
2695}
2696
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2698{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 return may_link(dir, old_dentry, MAY_LINK);
2700}
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2703{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 return may_link(dir, dentry, MAY_UNLINK);
2705}
2706
2707static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2708{
2709 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2710}
2711
Al Viro18bb1db2011-07-26 01:41:39 -04002712static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713{
2714 return may_create(dir, dentry, SECCLASS_DIR);
2715}
2716
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2718{
2719 return may_link(dir, dentry, MAY_RMDIR);
2720}
2721
Al Viro1a67aaf2011-07-26 01:52:52 -04002722static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2725}
2726
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002728 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2731}
2732
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733static int selinux_inode_readlink(struct dentry *dentry)
2734{
David Howells88e67f32008-11-14 10:39:21 +11002735 const struct cred *cred = current_cred();
2736
Eric Paris2875fa02011-04-28 16:04:24 -04002737 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738}
2739
2740static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2741{
David Howells88e67f32008-11-14 10:39:21 +11002742 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Eric Paris2875fa02011-04-28 16:04:24 -04002744 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745}
2746
Al Viroe74f71e2011-06-20 19:38:15 -04002747static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748{
David Howells88e67f32008-11-14 10:39:21 +11002749 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002750 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002751 struct selinux_audit_data sad = {0,};
Eric Parisb782e0a2010-07-23 11:44:03 -04002752 u32 perms;
2753 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002754 unsigned flags = mask & MAY_NOT_BLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Eric Parisb782e0a2010-07-23 11:44:03 -04002756 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002757 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2758
Eric Parisb782e0a2010-07-23 11:44:03 -04002759 /* No permission to check. Existence test. */
2760 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Eric Parisf48b7392011-04-25 12:54:27 -04002763 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002764 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002765 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002766
2767 if (from_access)
Eric Paris3b3b0e42012-04-03 09:37:02 -07002768 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
Eric Parisb782e0a2010-07-23 11:44:03 -04002769
2770 perms = file_mask_to_av(inode->i_mode, mask);
2771
Eric Paris9ade0cf2011-04-25 16:26:29 -04002772 return inode_has_perm(cred, inode, perms, &ad, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773}
2774
2775static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2776{
David Howells88e67f32008-11-14 10:39:21 +11002777 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002778 unsigned int ia_valid = iattr->ia_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002780 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2781 if (ia_valid & ATTR_FORCE) {
2782 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2783 ATTR_FORCE);
2784 if (!ia_valid)
2785 return 0;
2786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002788 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2789 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002790 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791
Eric Paris2875fa02011-04-28 16:04:24 -04002792 return dentry_has_perm(cred, dentry, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793}
2794
2795static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2796{
David Howells88e67f32008-11-14 10:39:21 +11002797 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002798 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002799
Eric Paris2875fa02011-04-28 16:04:24 -04002800 path.dentry = dentry;
2801 path.mnt = mnt;
2802
2803 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804}
2805
David Howells8f0cfa52008-04-29 00:59:41 -07002806static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002807{
David Howells88e67f32008-11-14 10:39:21 +11002808 const struct cred *cred = current_cred();
2809
Serge E. Hallynb5376772007-10-16 23:31:36 -07002810 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2811 sizeof XATTR_SECURITY_PREFIX - 1)) {
2812 if (!strcmp(name, XATTR_NAME_CAPS)) {
2813 if (!capable(CAP_SETFCAP))
2814 return -EPERM;
2815 } else if (!capable(CAP_SYS_ADMIN)) {
2816 /* A different attribute in the security namespace.
2817 Restrict to administrator. */
2818 return -EPERM;
2819 }
2820 }
2821
2822 /* Not an attribute we recognize, so just check the
2823 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002824 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002825}
2826
David Howells8f0cfa52008-04-29 00:59:41 -07002827static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2828 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 struct inode *inode = dentry->d_inode;
2831 struct inode_security_struct *isec = inode->i_security;
2832 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002833 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002834 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11002835 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 int rc = 0;
2837
Serge E. Hallynb5376772007-10-16 23:31:36 -07002838 if (strcmp(name, XATTR_NAME_SELINUX))
2839 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002842 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 return -EOPNOTSUPP;
2844
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002845 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 return -EPERM;
2847
Eric Parisa2694342011-04-25 13:10:27 -04002848 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002849 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002850 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
David Howells275bb412008-11-14 10:39:19 +11002852 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 FILE__RELABELFROM, &ad);
2854 if (rc)
2855 return rc;
2856
2857 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002858 if (rc == -EINVAL) {
2859 if (!capable(CAP_MAC_ADMIN))
2860 return rc;
2861 rc = security_context_to_sid_force(value, size, &newsid);
2862 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 if (rc)
2864 return rc;
2865
David Howells275bb412008-11-14 10:39:19 +11002866 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 FILE__RELABELTO, &ad);
2868 if (rc)
2869 return rc;
2870
David Howells275bb412008-11-14 10:39:19 +11002871 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002872 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 if (rc)
2874 return rc;
2875
2876 return avc_has_perm(newsid,
2877 sbsec->sid,
2878 SECCLASS_FILESYSTEM,
2879 FILESYSTEM__ASSOCIATE,
2880 &ad);
2881}
2882
David Howells8f0cfa52008-04-29 00:59:41 -07002883static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002884 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002885 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886{
2887 struct inode *inode = dentry->d_inode;
2888 struct inode_security_struct *isec = inode->i_security;
2889 u32 newsid;
2890 int rc;
2891
2892 if (strcmp(name, XATTR_NAME_SELINUX)) {
2893 /* Not an attribute we recognize, so nothing to do. */
2894 return;
2895 }
2896
Stephen Smalley12b29f32008-05-07 13:03:20 -04002897 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002899 printk(KERN_ERR "SELinux: unable to map context to SID"
2900 "for (%s, %lu), rc=%d\n",
2901 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 return;
2903 }
2904
2905 isec->sid = newsid;
2906 return;
2907}
2908
David Howells8f0cfa52008-04-29 00:59:41 -07002909static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910{
David Howells88e67f32008-11-14 10:39:21 +11002911 const struct cred *cred = current_cred();
2912
Eric Paris2875fa02011-04-28 16:04:24 -04002913 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914}
2915
Eric Paris828dfe12008-04-17 13:17:49 -04002916static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917{
David Howells88e67f32008-11-14 10:39:21 +11002918 const struct cred *cred = current_cred();
2919
Eric Paris2875fa02011-04-28 16:04:24 -04002920 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921}
2922
David Howells8f0cfa52008-04-29 00:59:41 -07002923static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002925 if (strcmp(name, XATTR_NAME_SELINUX))
2926 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928 /* No one is allowed to remove a SELinux security label.
2929 You can change the label, but all data must be labeled. */
2930 return -EACCES;
2931}
2932
James Morrisd381d8a2005-10-30 14:59:22 -08002933/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002934 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002935 *
2936 * Permission check is handled by selinux_inode_getxattr hook.
2937 */
David P. Quigley42492592008-02-04 22:29:39 -08002938static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939{
David P. Quigley42492592008-02-04 22:29:39 -08002940 u32 size;
2941 int error;
2942 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002945 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2946 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002948 /*
2949 * If the caller has CAP_MAC_ADMIN, then get the raw context
2950 * value even if it is not defined by current policy; otherwise,
2951 * use the in-core value under current policy.
2952 * Use the non-auditing forms of the permission checks since
2953 * getxattr may be called by unprivileged processes commonly
2954 * and lack of permission just means that we fall back to the
2955 * in-core context value, not a denial.
2956 */
Eric Paris6a9de492012-01-03 12:25:14 -05002957 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002958 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002959 if (!error)
2960 error = security_sid_to_context_force(isec->sid, &context,
2961 &size);
2962 else
2963 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002964 if (error)
2965 return error;
2966 error = size;
2967 if (alloc) {
2968 *buffer = context;
2969 goto out_nofree;
2970 }
2971 kfree(context);
2972out_nofree:
2973 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974}
2975
2976static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002977 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978{
2979 struct inode_security_struct *isec = inode->i_security;
2980 u32 newsid;
2981 int rc;
2982
2983 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2984 return -EOPNOTSUPP;
2985
2986 if (!value || !size)
2987 return -EACCES;
2988
Eric Paris828dfe12008-04-17 13:17:49 -04002989 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 if (rc)
2991 return rc;
2992
2993 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002994 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 return 0;
2996}
2997
2998static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2999{
3000 const int len = sizeof(XATTR_NAME_SELINUX);
3001 if (buffer && len <= buffer_size)
3002 memcpy(buffer, XATTR_NAME_SELINUX, len);
3003 return len;
3004}
3005
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02003006static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
3007{
3008 struct inode_security_struct *isec = inode->i_security;
3009 *secid = isec->sid;
3010}
3011
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012/* file security operations */
3013
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003014static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015{
David Howells88e67f32008-11-14 10:39:21 +11003016 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08003017 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
3020 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
3021 mask |= MAY_APPEND;
3022
Paul Moore389fb802009-03-27 17:10:34 -04003023 return file_has_perm(cred, file,
3024 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025}
3026
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003027static int selinux_file_permission(struct file *file, int mask)
3028{
Stephen Smalley20dda182009-06-22 14:54:53 -04003029 struct inode *inode = file->f_path.dentry->d_inode;
3030 struct file_security_struct *fsec = file->f_security;
3031 struct inode_security_struct *isec = inode->i_security;
3032 u32 sid = current_sid();
3033
Paul Moore389fb802009-03-27 17:10:34 -04003034 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003035 /* No permission to check. Existence test. */
3036 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003037
Stephen Smalley20dda182009-06-22 14:54:53 -04003038 if (sid == fsec->sid && fsec->isid == isec->sid &&
3039 fsec->pseqno == avc_policy_seqno())
3040 /* No change since dentry_open check. */
3041 return 0;
3042
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003043 return selinux_revalidate_file_permission(file, mask);
3044}
3045
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046static int selinux_file_alloc_security(struct file *file)
3047{
3048 return file_alloc_security(file);
3049}
3050
3051static void selinux_file_free_security(struct file *file)
3052{
3053 file_free_security(file);
3054}
3055
3056static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3057 unsigned long arg)
3058{
David Howells88e67f32008-11-14 10:39:21 +11003059 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05003060 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
Eric Paris0b24dcb2011-02-25 15:39:20 -05003062 switch (cmd) {
3063 case FIONREAD:
3064 /* fall through */
3065 case FIBMAP:
3066 /* fall through */
3067 case FIGETBSZ:
3068 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003069 case FS_IOC_GETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003070 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003071 case FS_IOC_GETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003072 error = file_has_perm(cred, file, FILE__GETATTR);
3073 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074
Al Viro2f99c362012-03-23 16:04:05 -04003075 case FS_IOC_SETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003076 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003077 case FS_IOC_SETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003078 error = file_has_perm(cred, file, FILE__SETATTR);
3079 break;
3080
3081 /* sys_ioctl() checks */
3082 case FIONBIO:
3083 /* fall through */
3084 case FIOASYNC:
3085 error = file_has_perm(cred, file, 0);
3086 break;
3087
3088 case KDSKBENT:
3089 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05003090 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3091 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003092 break;
3093
3094 /* default case assumes that the command will go
3095 * to the file's ioctl() function.
3096 */
3097 default:
3098 error = file_has_perm(cred, file, FILE__IOCTL);
3099 }
3100 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101}
3102
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003103static int default_noexec;
3104
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3106{
David Howells88e67f32008-11-14 10:39:21 +11003107 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003108 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003109
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003110 if (default_noexec &&
3111 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 /*
3113 * We are making executable an anonymous mapping or a
3114 * private file mapping that will also be writable.
3115 * This has an additional check.
3116 */
David Howellsd84f4f92008-11-14 10:39:23 +11003117 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003119 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
3122 if (file) {
3123 /* read access is always possible with a mapping */
3124 u32 av = FILE__READ;
3125
3126 /* write access only matters if the mapping is shared */
3127 if (shared && (prot & PROT_WRITE))
3128 av |= FILE__WRITE;
3129
3130 if (prot & PROT_EXEC)
3131 av |= FILE__EXECUTE;
3132
David Howells88e67f32008-11-14 10:39:21 +11003133 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 }
David Howellsd84f4f92008-11-14 10:39:23 +11003135
3136error:
3137 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138}
3139
3140static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003141 unsigned long prot, unsigned long flags,
3142 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143{
Eric Parised032182007-06-28 15:55:21 -04003144 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003145 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
Eric Paris84336d1a2009-07-31 12:54:05 -04003147 /*
3148 * notice that we are intentionally putting the SELinux check before
3149 * the secondary cap_file_mmap check. This is such a likely attempt
3150 * at bad behaviour/exploit that we always want to get the AVC, even
3151 * if DAC would have also denied the operation.
3152 */
Eric Parisa2551df2009-07-31 12:54:11 -04003153 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003154 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3155 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003156 if (rc)
3157 return rc;
3158 }
3159
3160 /* do DAC check on address space usage */
3161 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003162 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 return rc;
3164
3165 if (selinux_checkreqprot)
3166 prot = reqprot;
3167
3168 return file_map_prot_check(file, prot,
3169 (flags & MAP_TYPE) == MAP_SHARED);
3170}
3171
3172static int selinux_file_mprotect(struct vm_area_struct *vma,
3173 unsigned long reqprot,
3174 unsigned long prot)
3175{
David Howells88e67f32008-11-14 10:39:21 +11003176 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
3178 if (selinux_checkreqprot)
3179 prot = reqprot;
3180
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003181 if (default_noexec &&
3182 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003183 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003184 if (vma->vm_start >= vma->vm_mm->start_brk &&
3185 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003186 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003187 } else if (!vma->vm_file &&
3188 vma->vm_start <= vma->vm_mm->start_stack &&
3189 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003190 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003191 } else if (vma->vm_file && vma->anon_vma) {
3192 /*
3193 * We are making executable a file mapping that has
3194 * had some COW done. Since pages might have been
3195 * written, check ability to execute the possibly
3196 * modified content. This typically should only
3197 * occur for text relocations.
3198 */
David Howellsd84f4f92008-11-14 10:39:23 +11003199 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003200 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003201 if (rc)
3202 return rc;
3203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
3205 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3206}
3207
3208static int selinux_file_lock(struct file *file, unsigned int cmd)
3209{
David Howells88e67f32008-11-14 10:39:21 +11003210 const struct cred *cred = current_cred();
3211
3212 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213}
3214
3215static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3216 unsigned long arg)
3217{
David Howells88e67f32008-11-14 10:39:21 +11003218 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 int err = 0;
3220
3221 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003222 case F_SETFL:
3223 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3224 err = -EINVAL;
3225 break;
3226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
Eric Paris828dfe12008-04-17 13:17:49 -04003228 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003229 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003231 }
3232 /* fall through */
3233 case F_SETOWN:
3234 case F_SETSIG:
3235 case F_GETFL:
3236 case F_GETOWN:
3237 case F_GETSIG:
3238 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003239 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003240 break;
3241 case F_GETLK:
3242 case F_SETLK:
3243 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003245 case F_GETLK64:
3246 case F_SETLK64:
3247 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003249 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3250 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003252 }
David Howells88e67f32008-11-14 10:39:21 +11003253 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003254 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 }
3256
3257 return err;
3258}
3259
3260static int selinux_file_set_fowner(struct file *file)
3261{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 struct file_security_struct *fsec;
3263
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003265 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266
3267 return 0;
3268}
3269
3270static int selinux_file_send_sigiotask(struct task_struct *tsk,
3271 struct fown_struct *fown, int signum)
3272{
Eric Paris828dfe12008-04-17 13:17:49 -04003273 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003274 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 struct file_security_struct *fsec;
3277
3278 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003279 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 fsec = file->f_security;
3282
3283 if (!signum)
3284 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3285 else
3286 perm = signal_to_av(signum);
3287
David Howells275bb412008-11-14 10:39:19 +11003288 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 SECCLASS_PROCESS, perm, NULL);
3290}
3291
3292static int selinux_file_receive(struct file *file)
3293{
David Howells88e67f32008-11-14 10:39:21 +11003294 const struct cred *cred = current_cred();
3295
3296 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297}
3298
David Howells745ca242008-11-14 10:39:22 +11003299static int selinux_dentry_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003300{
3301 struct file_security_struct *fsec;
3302 struct inode *inode;
3303 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003304
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003305 inode = file->f_path.dentry->d_inode;
3306 fsec = file->f_security;
3307 isec = inode->i_security;
3308 /*
3309 * Save inode label and policy sequence number
3310 * at open-time so that selinux_file_permission
3311 * can determine whether revalidation is necessary.
3312 * Task label is already saved in the file security
3313 * struct as its SID.
3314 */
3315 fsec->isid = isec->sid;
3316 fsec->pseqno = avc_policy_seqno();
3317 /*
3318 * Since the inode label or policy seqno may have changed
3319 * between the selinux_inode_permission check and the saving
3320 * of state above, recheck that access is still permitted.
3321 * Otherwise, access might never be revalidated against the
3322 * new inode label or new policy.
3323 * This check is not redundant - do not remove.
3324 */
Linus Torvalds95f4efb2011-06-08 15:11:56 -07003325 return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003326}
3327
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328/* task security operations */
3329
3330static int selinux_task_create(unsigned long clone_flags)
3331{
David Howells3b11a1d2008-11-14 10:39:26 +11003332 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333}
3334
David Howellsf1752ee2008-11-14 10:39:17 +11003335/*
David Howellsee18d642009-09-02 09:14:21 +01003336 * allocate the SELinux part of blank credentials
3337 */
3338static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3339{
3340 struct task_security_struct *tsec;
3341
3342 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3343 if (!tsec)
3344 return -ENOMEM;
3345
3346 cred->security = tsec;
3347 return 0;
3348}
3349
3350/*
David Howellsf1752ee2008-11-14 10:39:17 +11003351 * detach and free the LSM part of a set of credentials
3352 */
3353static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354{
David Howellsf1752ee2008-11-14 10:39:17 +11003355 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003356
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003357 /*
3358 * cred->security == NULL if security_cred_alloc_blank() or
3359 * security_prepare_creds() returned an error.
3360 */
3361 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003362 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003363 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364}
3365
David Howellsd84f4f92008-11-14 10:39:23 +11003366/*
3367 * prepare a new set of credentials for modification
3368 */
3369static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3370 gfp_t gfp)
3371{
3372 const struct task_security_struct *old_tsec;
3373 struct task_security_struct *tsec;
3374
3375 old_tsec = old->security;
3376
3377 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3378 if (!tsec)
3379 return -ENOMEM;
3380
3381 new->security = tsec;
3382 return 0;
3383}
3384
3385/*
David Howellsee18d642009-09-02 09:14:21 +01003386 * transfer the SELinux data to a blank set of creds
3387 */
3388static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3389{
3390 const struct task_security_struct *old_tsec = old->security;
3391 struct task_security_struct *tsec = new->security;
3392
3393 *tsec = *old_tsec;
3394}
3395
3396/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003397 * set the security data for a kernel service
3398 * - all the creation contexts are set to unlabelled
3399 */
3400static int selinux_kernel_act_as(struct cred *new, u32 secid)
3401{
3402 struct task_security_struct *tsec = new->security;
3403 u32 sid = current_sid();
3404 int ret;
3405
3406 ret = avc_has_perm(sid, secid,
3407 SECCLASS_KERNEL_SERVICE,
3408 KERNEL_SERVICE__USE_AS_OVERRIDE,
3409 NULL);
3410 if (ret == 0) {
3411 tsec->sid = secid;
3412 tsec->create_sid = 0;
3413 tsec->keycreate_sid = 0;
3414 tsec->sockcreate_sid = 0;
3415 }
3416 return ret;
3417}
3418
3419/*
3420 * set the file creation context in a security record to the same as the
3421 * objective context of the specified inode
3422 */
3423static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3424{
3425 struct inode_security_struct *isec = inode->i_security;
3426 struct task_security_struct *tsec = new->security;
3427 u32 sid = current_sid();
3428 int ret;
3429
3430 ret = avc_has_perm(sid, isec->sid,
3431 SECCLASS_KERNEL_SERVICE,
3432 KERNEL_SERVICE__CREATE_FILES_AS,
3433 NULL);
3434
3435 if (ret == 0)
3436 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003437 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003438}
3439
Eric Parisdd8dbf22009-11-03 16:35:32 +11003440static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003441{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003442 u32 sid;
3443 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003444 struct selinux_audit_data sad = {0,};
Eric Parisdd8dbf22009-11-03 16:35:32 +11003445
3446 sid = task_sid(current);
3447
3448 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003449 ad.selinux_audit_data = &sad;
Eric Parisdd8dbf22009-11-03 16:35:32 +11003450 ad.u.kmod_name = kmod_name;
3451
3452 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3453 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003454}
3455
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3457{
David Howells3b11a1d2008-11-14 10:39:26 +11003458 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459}
3460
3461static int selinux_task_getpgid(struct task_struct *p)
3462{
David Howells3b11a1d2008-11-14 10:39:26 +11003463 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464}
3465
3466static int selinux_task_getsid(struct task_struct *p)
3467{
David Howells3b11a1d2008-11-14 10:39:26 +11003468 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469}
3470
David Quigleyf9008e42006-06-30 01:55:46 -07003471static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3472{
David Howells275bb412008-11-14 10:39:19 +11003473 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003474}
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476static int selinux_task_setnice(struct task_struct *p, int nice)
3477{
3478 int rc;
3479
Eric Paris200ac532009-02-12 15:01:04 -05003480 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 if (rc)
3482 return rc;
3483
David Howells3b11a1d2008-11-14 10:39:26 +11003484 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485}
3486
James Morris03e68062006-06-23 02:03:58 -07003487static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3488{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003489 int rc;
3490
Eric Paris200ac532009-02-12 15:01:04 -05003491 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003492 if (rc)
3493 return rc;
3494
David Howells3b11a1d2008-11-14 10:39:26 +11003495 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003496}
3497
David Quigleya1836a42006-06-30 01:55:49 -07003498static int selinux_task_getioprio(struct task_struct *p)
3499{
David Howells3b11a1d2008-11-14 10:39:26 +11003500 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003501}
3502
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003503static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3504 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003506 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507
3508 /* Control the ability to change the hard limit (whether
3509 lowering or raising it), so that the hard limit can
3510 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003511 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003513 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
3515 return 0;
3516}
3517
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003518static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003520 int rc;
3521
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003522 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003523 if (rc)
3524 return rc;
3525
David Howells3b11a1d2008-11-14 10:39:26 +11003526 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527}
3528
3529static int selinux_task_getscheduler(struct task_struct *p)
3530{
David Howells3b11a1d2008-11-14 10:39:26 +11003531 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532}
3533
David Quigley35601542006-06-23 02:04:01 -07003534static int selinux_task_movememory(struct task_struct *p)
3535{
David Howells3b11a1d2008-11-14 10:39:26 +11003536 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003537}
3538
David Quigleyf9008e42006-06-30 01:55:46 -07003539static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3540 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541{
3542 u32 perm;
3543 int rc;
3544
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 if (!sig)
3546 perm = PROCESS__SIGNULL; /* null signal; existence test */
3547 else
3548 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003549 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003550 rc = avc_has_perm(secid, task_sid(p),
3551 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003552 else
David Howells3b11a1d2008-11-14 10:39:26 +11003553 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003554 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555}
3556
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557static int selinux_task_wait(struct task_struct *p)
3558{
Eric Paris8a535142007-10-22 16:10:31 -04003559 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560}
3561
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562static void selinux_task_to_inode(struct task_struct *p,
3563 struct inode *inode)
3564{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003566 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
David Howells275bb412008-11-14 10:39:19 +11003568 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570}
3571
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003573static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003574 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575{
3576 int offset, ihlen, ret = -EINVAL;
3577 struct iphdr _iph, *ih;
3578
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003579 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3581 if (ih == NULL)
3582 goto out;
3583
3584 ihlen = ih->ihl * 4;
3585 if (ihlen < sizeof(_iph))
3586 goto out;
3587
Eric Paris48c62af2012-04-02 13:15:44 -04003588 ad->u.net->v4info.saddr = ih->saddr;
3589 ad->u.net->v4info.daddr = ih->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 ret = 0;
3591
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003592 if (proto)
3593 *proto = ih->protocol;
3594
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003596 case IPPROTO_TCP: {
3597 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
Eric Paris828dfe12008-04-17 13:17:49 -04003599 if (ntohs(ih->frag_off) & IP_OFFSET)
3600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601
3602 offset += ihlen;
3603 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3604 if (th == NULL)
3605 break;
3606
Eric Paris48c62af2012-04-02 13:15:44 -04003607 ad->u.net->sport = th->source;
3608 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
Eric Paris828dfe12008-04-17 13:17:49 -04003612 case IPPROTO_UDP: {
3613 struct udphdr _udph, *uh;
3614
3615 if (ntohs(ih->frag_off) & IP_OFFSET)
3616 break;
3617
3618 offset += ihlen;
3619 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3620 if (uh == NULL)
3621 break;
3622
Eric Paris48c62af2012-04-02 13:15:44 -04003623 ad->u.net->sport = uh->source;
3624 ad->u.net->dport = uh->dest;
Eric Paris828dfe12008-04-17 13:17:49 -04003625 break;
3626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627
James Morris2ee92d42006-11-13 16:09:01 -08003628 case IPPROTO_DCCP: {
3629 struct dccp_hdr _dccph, *dh;
3630
3631 if (ntohs(ih->frag_off) & IP_OFFSET)
3632 break;
3633
3634 offset += ihlen;
3635 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3636 if (dh == NULL)
3637 break;
3638
Eric Paris48c62af2012-04-02 13:15:44 -04003639 ad->u.net->sport = dh->dccph_sport;
3640 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003641 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003642 }
James Morris2ee92d42006-11-13 16:09:01 -08003643
Eric Paris828dfe12008-04-17 13:17:49 -04003644 default:
3645 break;
3646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647out:
3648 return ret;
3649}
3650
3651#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3652
3653/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003654static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003655 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656{
3657 u8 nexthdr;
3658 int ret = -EINVAL, offset;
3659 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003660 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003662 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3664 if (ip6 == NULL)
3665 goto out;
3666
Eric Paris48c62af2012-04-02 13:15:44 -04003667 ad->u.net->v6info.saddr = ip6->saddr;
3668 ad->u.net->v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 ret = 0;
3670
3671 nexthdr = ip6->nexthdr;
3672 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003673 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 if (offset < 0)
3675 goto out;
3676
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003677 if (proto)
3678 *proto = nexthdr;
3679
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 switch (nexthdr) {
3681 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003682 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
3684 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3685 if (th == NULL)
3686 break;
3687
Eric Paris48c62af2012-04-02 13:15:44 -04003688 ad->u.net->sport = th->source;
3689 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 break;
3691 }
3692
3693 case IPPROTO_UDP: {
3694 struct udphdr _udph, *uh;
3695
3696 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3697 if (uh == NULL)
3698 break;
3699
Eric Paris48c62af2012-04-02 13:15:44 -04003700 ad->u.net->sport = uh->source;
3701 ad->u.net->dport = uh->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 break;
3703 }
3704
James Morris2ee92d42006-11-13 16:09:01 -08003705 case IPPROTO_DCCP: {
3706 struct dccp_hdr _dccph, *dh;
3707
3708 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3709 if (dh == NULL)
3710 break;
3711
Eric Paris48c62af2012-04-02 13:15:44 -04003712 ad->u.net->sport = dh->dccph_sport;
3713 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003714 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003715 }
James Morris2ee92d42006-11-13 16:09:01 -08003716
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 /* includes fragments */
3718 default:
3719 break;
3720 }
3721out:
3722 return ret;
3723}
3724
3725#endif /* IPV6 */
3726
Thomas Liu2bf49692009-07-14 12:14:09 -04003727static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003728 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729{
David Howellscf9481e2008-07-27 21:31:07 +10003730 char *addrp;
3731 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
Eric Paris48c62af2012-04-02 13:15:44 -04003733 switch (ad->u.net->family) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003735 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003736 if (ret)
3737 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003738 addrp = (char *)(src ? &ad->u.net->v4info.saddr :
3739 &ad->u.net->v4info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003740 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
3742#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3743 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003744 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003745 if (ret)
3746 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003747 addrp = (char *)(src ? &ad->u.net->v6info.saddr :
3748 &ad->u.net->v6info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003749 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750#endif /* IPV6 */
3751 default:
David Howellscf9481e2008-07-27 21:31:07 +10003752 addrp = NULL;
3753 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 }
3755
David Howellscf9481e2008-07-27 21:31:07 +10003756parse_error:
3757 printk(KERN_WARNING
3758 "SELinux: failure in selinux_parse_skb(),"
3759 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003761
3762okay:
3763 if (_addrp)
3764 *_addrp = addrp;
3765 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766}
3767
Paul Moore4f6a9932007-03-01 14:35:22 -05003768/**
Paul Moore220deb92008-01-29 08:38:23 -05003769 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003770 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003771 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003772 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003773 *
3774 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003775 * Check the various different forms of network peer labeling and determine
3776 * the peer label/SID for the packet; most of the magic actually occurs in
3777 * the security server function security_net_peersid_cmp(). The function
3778 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3779 * or -EACCES if @sid is invalid due to inconsistencies with the different
3780 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003781 *
3782 */
Paul Moore220deb92008-01-29 08:38:23 -05003783static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003784{
Paul Moore71f1cb02008-01-29 08:51:16 -05003785 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003786 u32 xfrm_sid;
3787 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003788 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003789
3790 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003791 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003792
Paul Moore71f1cb02008-01-29 08:51:16 -05003793 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3794 if (unlikely(err)) {
3795 printk(KERN_WARNING
3796 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3797 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003798 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003799 }
Paul Moore220deb92008-01-29 08:38:23 -05003800
3801 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003802}
3803
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003805
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003806static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3807 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003808{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003809 if (tsec->sockcreate_sid > SECSID_NULL) {
3810 *socksid = tsec->sockcreate_sid;
3811 return 0;
3812 }
3813
3814 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3815 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003816}
3817
Paul Moore253bfae2010-04-22 14:46:19 -04003818static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819{
Paul Moore253bfae2010-04-22 14:46:19 -04003820 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003821 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003822 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003823 struct lsm_network_audit net = {0,};
Paul Moore253bfae2010-04-22 14:46:19 -04003824 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
Paul Moore253bfae2010-04-22 14:46:19 -04003826 if (sksec->sid == SECINITSID_KERNEL)
3827 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
Thomas Liu2bf49692009-07-14 12:14:09 -04003829 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003830 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003831 ad.u.net = &net;
3832 ad.u.net->sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Paul Moore253bfae2010-04-22 14:46:19 -04003834 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835}
3836
3837static int selinux_socket_create(int family, int type,
3838 int protocol, int kern)
3839{
Paul Moore5fb49872010-04-22 14:46:19 -04003840 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003841 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003842 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003843 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844
3845 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003846 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847
David Howells275bb412008-11-14 10:39:19 +11003848 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003849 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3850 if (rc)
3851 return rc;
3852
Paul Moored4f2d972010-04-22 14:46:18 -04003853 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854}
3855
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003856static int selinux_socket_post_create(struct socket *sock, int family,
3857 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858{
Paul Moore5fb49872010-04-22 14:46:19 -04003859 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003860 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003861 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003862 int err = 0;
3863
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003864 isec->sclass = socket_type_to_security_class(family, type, protocol);
3865
David Howells275bb412008-11-14 10:39:19 +11003866 if (kern)
3867 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003868 else {
3869 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3870 if (err)
3871 return err;
3872 }
David Howells275bb412008-11-14 10:39:19 +11003873
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 isec->initialized = 1;
3875
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003876 if (sock->sk) {
3877 sksec = sock->sk->sk_security;
3878 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003879 sksec->sclass = isec->sclass;
Paul Moore389fb802009-03-27 17:10:34 -04003880 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003881 }
3882
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003883 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884}
3885
3886/* Range of port numbers used to automatically bind.
3887 Need to determine whether we should perform a name_bind
3888 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889
3890static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3891{
Paul Moore253bfae2010-04-22 14:46:19 -04003892 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 u16 family;
3894 int err;
3895
Paul Moore253bfae2010-04-22 14:46:19 -04003896 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 if (err)
3898 goto out;
3899
3900 /*
3901 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003902 * Multiple address binding for SCTP is not supported yet: we just
3903 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 */
Paul Moore253bfae2010-04-22 14:46:19 -04003905 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 if (family == PF_INET || family == PF_INET6) {
3907 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003908 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003909 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003910 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003911 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 struct sockaddr_in *addr4 = NULL;
3913 struct sockaddr_in6 *addr6 = NULL;
3914 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003915 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 if (family == PF_INET) {
3918 addr4 = (struct sockaddr_in *)address;
3919 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 addrp = (char *)&addr4->sin_addr.s_addr;
3921 } else {
3922 addr6 = (struct sockaddr_in6 *)address;
3923 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 addrp = (char *)&addr6->sin6_addr.s6_addr;
3925 }
3926
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003927 if (snum) {
3928 int low, high;
3929
3930 inet_get_local_port_range(&low, &high);
3931
3932 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003933 err = sel_netport_sid(sk->sk_protocol,
3934 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003935 if (err)
3936 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003937 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003938 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003939 ad.u.net = &net;
3940 ad.u.net->sport = htons(snum);
3941 ad.u.net->family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003942 err = avc_has_perm(sksec->sid, sid,
3943 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003944 SOCKET__NAME_BIND, &ad);
3945 if (err)
3946 goto out;
3947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 }
Eric Paris828dfe12008-04-17 13:17:49 -04003949
Paul Moore253bfae2010-04-22 14:46:19 -04003950 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003951 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 node_perm = TCP_SOCKET__NODE_BIND;
3953 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003954
James Morris13402582005-09-30 14:24:34 -04003955 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 node_perm = UDP_SOCKET__NODE_BIND;
3957 break;
James Morris2ee92d42006-11-13 16:09:01 -08003958
3959 case SECCLASS_DCCP_SOCKET:
3960 node_perm = DCCP_SOCKET__NODE_BIND;
3961 break;
3962
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 default:
3964 node_perm = RAWIP_SOCKET__NODE_BIND;
3965 break;
3966 }
Eric Paris828dfe12008-04-17 13:17:49 -04003967
Paul Moore224dfbd2008-01-29 08:38:13 -05003968 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 if (err)
3970 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003971
Thomas Liu2bf49692009-07-14 12:14:09 -04003972 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003973 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003974 ad.u.net = &net;
3975 ad.u.net->sport = htons(snum);
3976 ad.u.net->family = family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977
3978 if (family == PF_INET)
Eric Paris48c62af2012-04-02 13:15:44 -04003979 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 else
Eric Paris48c62af2012-04-02 13:15:44 -04003981 ad.u.net->v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
Paul Moore253bfae2010-04-22 14:46:19 -04003983 err = avc_has_perm(sksec->sid, sid,
3984 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 if (err)
3986 goto out;
3987 }
3988out:
3989 return err;
3990}
3991
3992static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3993{
Paul Moore014ab192008-10-10 10:16:33 -04003994 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003995 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 int err;
3997
Paul Moore253bfae2010-04-22 14:46:19 -04003998 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 if (err)
4000 return err;
4001
4002 /*
James Morris2ee92d42006-11-13 16:09:01 -08004003 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 */
Paul Moore253bfae2010-04-22 14:46:19 -04004005 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
4006 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04004007 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004008 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004009 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 struct sockaddr_in *addr4 = NULL;
4011 struct sockaddr_in6 *addr6 = NULL;
4012 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08004013 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
4015 if (sk->sk_family == PF_INET) {
4016 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07004017 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 return -EINVAL;
4019 snum = ntohs(addr4->sin_port);
4020 } else {
4021 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07004022 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 return -EINVAL;
4024 snum = ntohs(addr6->sin6_port);
4025 }
4026
Paul Moore3e112172008-04-10 10:48:14 -04004027 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 if (err)
4029 goto out;
4030
Paul Moore253bfae2010-04-22 14:46:19 -04004031 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08004032 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
4033
Thomas Liu2bf49692009-07-14 12:14:09 -04004034 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004035 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004036 ad.u.net = &net;
4037 ad.u.net->dport = htons(snum);
4038 ad.u.net->family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04004039 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 if (err)
4041 goto out;
4042 }
4043
Paul Moore014ab192008-10-10 10:16:33 -04004044 err = selinux_netlbl_socket_connect(sk, address);
4045
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046out:
4047 return err;
4048}
4049
4050static int selinux_socket_listen(struct socket *sock, int backlog)
4051{
Paul Moore253bfae2010-04-22 14:46:19 -04004052 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053}
4054
4055static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
4056{
4057 int err;
4058 struct inode_security_struct *isec;
4059 struct inode_security_struct *newisec;
4060
Paul Moore253bfae2010-04-22 14:46:19 -04004061 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 if (err)
4063 return err;
4064
4065 newisec = SOCK_INODE(newsock)->i_security;
4066
4067 isec = SOCK_INODE(sock)->i_security;
4068 newisec->sclass = isec->sclass;
4069 newisec->sid = isec->sid;
4070 newisec->initialized = 1;
4071
4072 return 0;
4073}
4074
4075static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04004076 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077{
Paul Moore253bfae2010-04-22 14:46:19 -04004078 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079}
4080
4081static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4082 int size, int flags)
4083{
Paul Moore253bfae2010-04-22 14:46:19 -04004084 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085}
4086
4087static int selinux_socket_getsockname(struct socket *sock)
4088{
Paul Moore253bfae2010-04-22 14:46:19 -04004089 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090}
4091
4092static int selinux_socket_getpeername(struct socket *sock)
4093{
Paul Moore253bfae2010-04-22 14:46:19 -04004094 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095}
4096
Eric Paris828dfe12008-04-17 13:17:49 -04004097static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098{
Paul Mooref8687af2006-10-30 15:22:15 -08004099 int err;
4100
Paul Moore253bfae2010-04-22 14:46:19 -04004101 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08004102 if (err)
4103 return err;
4104
4105 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106}
4107
4108static int selinux_socket_getsockopt(struct socket *sock, int level,
4109 int optname)
4110{
Paul Moore253bfae2010-04-22 14:46:19 -04004111 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112}
4113
4114static int selinux_socket_shutdown(struct socket *sock, int how)
4115{
Paul Moore253bfae2010-04-22 14:46:19 -04004116 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117}
4118
David S. Miller3610cda2011-01-05 15:38:53 -08004119static int selinux_socket_unix_stream_connect(struct sock *sock,
4120 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 struct sock *newsk)
4122{
David S. Miller3610cda2011-01-05 15:38:53 -08004123 struct sk_security_struct *sksec_sock = sock->sk_security;
4124 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004125 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004126 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004127 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004128 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 int err;
4130
Thomas Liu2bf49692009-07-14 12:14:09 -04004131 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004132 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004133 ad.u.net = &net;
4134 ad.u.net->sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135
Paul Moore4d1e2452010-04-22 14:46:18 -04004136 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4137 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4139 if (err)
4140 return err;
4141
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004143 sksec_new->peer_sid = sksec_sock->sid;
4144 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4145 &sksec_new->sid);
4146 if (err)
4147 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004148
Paul Moore4d1e2452010-04-22 14:46:18 -04004149 /* connecting socket */
4150 sksec_sock->peer_sid = sksec_new->sid;
4151
4152 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153}
4154
4155static int selinux_socket_unix_may_send(struct socket *sock,
4156 struct socket *other)
4157{
Paul Moore253bfae2010-04-22 14:46:19 -04004158 struct sk_security_struct *ssec = sock->sk->sk_security;
4159 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004160 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004161 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004162 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Thomas Liu2bf49692009-07-14 12:14:09 -04004164 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004165 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004166 ad.u.net = &net;
4167 ad.u.net->sk = other->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168
Paul Moore253bfae2010-04-22 14:46:19 -04004169 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4170 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171}
4172
Paul Mooreeffad8d2008-01-29 08:49:27 -05004173static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4174 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004175 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004176{
4177 int err;
4178 u32 if_sid;
4179 u32 node_sid;
4180
4181 err = sel_netif_sid(ifindex, &if_sid);
4182 if (err)
4183 return err;
4184 err = avc_has_perm(peer_sid, if_sid,
4185 SECCLASS_NETIF, NETIF__INGRESS, ad);
4186 if (err)
4187 return err;
4188
4189 err = sel_netnode_sid(addrp, family, &node_sid);
4190 if (err)
4191 return err;
4192 return avc_has_perm(peer_sid, node_sid,
4193 SECCLASS_NODE, NODE__RECVFROM, ad);
4194}
4195
Paul Moore220deb92008-01-29 08:38:23 -05004196static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004197 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004198{
Paul Moore277d3422008-12-31 12:54:11 -05004199 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004200 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004201 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004202 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004203 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004204 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004205 char *addrp;
4206
Thomas Liu2bf49692009-07-14 12:14:09 -04004207 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004208 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004209 ad.u.net = &net;
4210 ad.u.net->netif = skb->skb_iif;
4211 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004212 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4213 if (err)
4214 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004215
Paul Moore58bfbb52009-03-27 17:10:41 -04004216 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004217 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004218 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004219 if (err)
4220 return err;
4221 }
Paul Moore220deb92008-01-29 08:38:23 -05004222
Steffen Klassertb9679a72011-02-23 12:55:21 +01004223 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4224 if (err)
4225 return err;
4226 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004227
James Morris4e5ab4c2006-06-09 00:33:33 -07004228 return err;
4229}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004230
James Morris4e5ab4c2006-06-09 00:33:33 -07004231static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4232{
Paul Moore220deb92008-01-29 08:38:23 -05004233 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004234 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004235 u16 family = sk->sk_family;
4236 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004237 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004238 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004239 struct lsm_network_audit net = {0,};
Paul Moore220deb92008-01-29 08:38:23 -05004240 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004241 u8 secmark_active;
4242 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004243
James Morris4e5ab4c2006-06-09 00:33:33 -07004244 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004245 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004246
4247 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004248 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004249 family = PF_INET;
4250
Paul Moored8395c82008-10-10 10:16:30 -04004251 /* If any sort of compatibility mode is enabled then handoff processing
4252 * to the selinux_sock_rcv_skb_compat() function to deal with the
4253 * special handling. We do this in an attempt to keep this function
4254 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004255 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004256 return selinux_sock_rcv_skb_compat(sk, skb, family);
4257
4258 secmark_active = selinux_secmark_enabled();
4259 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4260 if (!secmark_active && !peerlbl_active)
4261 return 0;
4262
Thomas Liu2bf49692009-07-14 12:14:09 -04004263 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004264 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004265 ad.u.net = &net;
4266 ad.u.net->netif = skb->skb_iif;
4267 ad.u.net->family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004268 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004269 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004270 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004271
Paul Moored8395c82008-10-10 10:16:30 -04004272 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004273 u32 peer_sid;
4274
4275 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4276 if (err)
4277 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004278 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004279 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004280 if (err) {
4281 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004282 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004283 }
Paul Moored621d352008-01-29 08:43:36 -05004284 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4285 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004286 if (err)
4287 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004288 }
4289
Paul Moored8395c82008-10-10 10:16:30 -04004290 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004291 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4292 PACKET__RECV, &ad);
4293 if (err)
4294 return err;
4295 }
4296
Paul Moored621d352008-01-29 08:43:36 -05004297 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298}
4299
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004300static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4301 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302{
4303 int err = 0;
4304 char *scontext;
4305 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004306 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004307 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
Paul Moore253bfae2010-04-22 14:46:19 -04004309 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4310 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004311 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004312 if (peer_sid == SECSID_NULL)
4313 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004315 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004317 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
4319 if (scontext_len > len) {
4320 err = -ERANGE;
4321 goto out_len;
4322 }
4323
4324 if (copy_to_user(optval, scontext, scontext_len))
4325 err = -EFAULT;
4326
4327out_len:
4328 if (put_user(scontext_len, optlen))
4329 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 return err;
4332}
4333
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004334static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004335{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004336 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004337 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004338
Paul Mooreaa862902008-10-10 10:16:29 -04004339 if (skb && skb->protocol == htons(ETH_P_IP))
4340 family = PF_INET;
4341 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4342 family = PF_INET6;
4343 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004344 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004345 else
4346 goto out;
4347
4348 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004349 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004350 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004351 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004352
Paul Moore75e22912008-01-29 08:38:04 -05004353out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004354 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004355 if (peer_secid == SECSID_NULL)
4356 return -EINVAL;
4357 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004358}
4359
Al Viro7d877f32005-10-21 03:20:43 -04004360static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361{
Paul Moore84914b72010-04-22 14:46:18 -04004362 struct sk_security_struct *sksec;
4363
4364 sksec = kzalloc(sizeof(*sksec), priority);
4365 if (!sksec)
4366 return -ENOMEM;
4367
4368 sksec->peer_sid = SECINITSID_UNLABELED;
4369 sksec->sid = SECINITSID_UNLABELED;
4370 selinux_netlbl_sk_security_reset(sksec);
4371 sk->sk_security = sksec;
4372
4373 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374}
4375
4376static void selinux_sk_free_security(struct sock *sk)
4377{
Paul Moore84914b72010-04-22 14:46:18 -04004378 struct sk_security_struct *sksec = sk->sk_security;
4379
4380 sk->sk_security = NULL;
4381 selinux_netlbl_sk_security_free(sksec);
4382 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383}
4384
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004385static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4386{
Eric Parisdd3e7832010-04-07 15:08:46 -04004387 struct sk_security_struct *sksec = sk->sk_security;
4388 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004389
Eric Parisdd3e7832010-04-07 15:08:46 -04004390 newsksec->sid = sksec->sid;
4391 newsksec->peer_sid = sksec->peer_sid;
4392 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004393
Eric Parisdd3e7832010-04-07 15:08:46 -04004394 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004395}
4396
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004397static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004398{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004399 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004400 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004401 else {
4402 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004403
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004404 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004405 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004406}
4407
Eric Paris828dfe12008-04-17 13:17:49 -04004408static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004409{
4410 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4411 struct sk_security_struct *sksec = sk->sk_security;
4412
David Woodhouse2148ccc2006-09-29 15:50:25 -07004413 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4414 sk->sk_family == PF_UNIX)
4415 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004416 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004417}
4418
Adrian Bunk9a673e52006-08-15 00:03:53 -07004419static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4420 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004421{
4422 struct sk_security_struct *sksec = sk->sk_security;
4423 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004424 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004425 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004426 u32 peersid;
4427
Paul Mooreaa862902008-10-10 10:16:29 -04004428 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4429 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4430 family = PF_INET;
4431
4432 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004433 if (err)
4434 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004435 if (peersid == SECSID_NULL) {
4436 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004437 req->peer_secid = SECSID_NULL;
Paul Moore389fb802009-03-27 17:10:34 -04004438 } else {
4439 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4440 if (err)
4441 return err;
4442 req->secid = newsid;
4443 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004444 }
4445
Paul Moore389fb802009-03-27 17:10:34 -04004446 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004447}
4448
Adrian Bunk9a673e52006-08-15 00:03:53 -07004449static void selinux_inet_csk_clone(struct sock *newsk,
4450 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004451{
4452 struct sk_security_struct *newsksec = newsk->sk_security;
4453
4454 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004455 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004456 /* NOTE: Ideally, we should also get the isec->sid for the
4457 new socket in sync, but we don't have the isec available yet.
4458 So we will wait until sock_graft to do it, by which
4459 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004460
Paul Moore9f2ad662006-11-17 17:38:53 -05004461 /* We don't need to take any sort of lock here as we are the only
4462 * thread with access to newsksec */
Paul Moore389fb802009-03-27 17:10:34 -04004463 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004464}
4465
Paul Moore014ab192008-10-10 10:16:33 -04004466static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004467{
Paul Mooreaa862902008-10-10 10:16:29 -04004468 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004469 struct sk_security_struct *sksec = sk->sk_security;
4470
Paul Mooreaa862902008-10-10 10:16:29 -04004471 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4472 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4473 family = PF_INET;
4474
4475 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004476}
4477
Eric Paris2606fd12010-10-13 16:24:41 -04004478static int selinux_secmark_relabel_packet(u32 sid)
4479{
4480 const struct task_security_struct *__tsec;
4481 u32 tsid;
4482
4483 __tsec = current_security();
4484 tsid = __tsec->sid;
4485
4486 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4487}
4488
4489static void selinux_secmark_refcount_inc(void)
4490{
4491 atomic_inc(&selinux_secmark_refcount);
4492}
4493
4494static void selinux_secmark_refcount_dec(void)
4495{
4496 atomic_dec(&selinux_secmark_refcount);
4497}
4498
Adrian Bunk9a673e52006-08-15 00:03:53 -07004499static void selinux_req_classify_flow(const struct request_sock *req,
4500 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004501{
David S. Miller1d28f422011-03-12 00:29:39 -05004502 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004503}
4504
Paul Mooreed6d76e2009-08-28 18:12:49 -04004505static int selinux_tun_dev_create(void)
4506{
4507 u32 sid = current_sid();
4508
4509 /* we aren't taking into account the "sockcreate" SID since the socket
4510 * that is being created here is not a socket in the traditional sense,
4511 * instead it is a private sock, accessible only to the kernel, and
4512 * representing a wide range of network traffic spanning multiple
4513 * connections unlike traditional sockets - check the TUN driver to
4514 * get a better understanding of why this socket is special */
4515
4516 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4517 NULL);
4518}
4519
4520static void selinux_tun_dev_post_create(struct sock *sk)
4521{
4522 struct sk_security_struct *sksec = sk->sk_security;
4523
4524 /* we don't currently perform any NetLabel based labeling here and it
4525 * isn't clear that we would want to do so anyway; while we could apply
4526 * labeling without the support of the TUN user the resulting labeled
4527 * traffic from the other end of the connection would almost certainly
4528 * cause confusion to the TUN user that had no idea network labeling
4529 * protocols were being used */
4530
4531 /* see the comments in selinux_tun_dev_create() about why we don't use
4532 * the sockcreate SID here */
4533
4534 sksec->sid = current_sid();
4535 sksec->sclass = SECCLASS_TUN_SOCKET;
4536}
4537
4538static int selinux_tun_dev_attach(struct sock *sk)
4539{
4540 struct sk_security_struct *sksec = sk->sk_security;
4541 u32 sid = current_sid();
4542 int err;
4543
4544 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4545 TUN_SOCKET__RELABELFROM, NULL);
4546 if (err)
4547 return err;
4548 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4549 TUN_SOCKET__RELABELTO, NULL);
4550 if (err)
4551 return err;
4552
4553 sksec->sid = sid;
4554
4555 return 0;
4556}
4557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4559{
4560 int err = 0;
4561 u32 perm;
4562 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004563 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 if (skb->len < NLMSG_SPACE(0)) {
4566 err = -EINVAL;
4567 goto out;
4568 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004569 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004570
Paul Moore253bfae2010-04-22 14:46:19 -04004571 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 if (err) {
4573 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004574 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 "SELinux: unrecognized netlink message"
4576 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004577 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004578 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 err = 0;
4580 }
4581
4582 /* Ignore */
4583 if (err == -ENOENT)
4584 err = 0;
4585 goto out;
4586 }
4587
Paul Moore253bfae2010-04-22 14:46:19 -04004588 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589out:
4590 return err;
4591}
4592
4593#ifdef CONFIG_NETFILTER
4594
Paul Mooreeffad8d2008-01-29 08:49:27 -05004595static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4596 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
Paul Mooredfaebe92008-10-10 10:16:31 -04004598 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004599 char *addrp;
4600 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004601 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004602 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004603 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004604 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004605 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004606 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004607
Paul Mooreeffad8d2008-01-29 08:49:27 -05004608 if (!selinux_policycap_netpeer)
4609 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004610
Paul Mooreeffad8d2008-01-29 08:49:27 -05004611 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004612 netlbl_active = netlbl_enabled();
4613 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004614 if (!secmark_active && !peerlbl_active)
4615 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004616
Paul Moored8395c82008-10-10 10:16:30 -04004617 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4618 return NF_DROP;
4619
Thomas Liu2bf49692009-07-14 12:14:09 -04004620 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004621 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004622 ad.u.net = &net;
4623 ad.u.net->netif = ifindex;
4624 ad.u.net->family = family;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004625 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4626 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
Paul Mooredfaebe92008-10-10 10:16:31 -04004628 if (peerlbl_active) {
4629 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4630 peer_sid, &ad);
4631 if (err) {
4632 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004633 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004634 }
4635 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004636
4637 if (secmark_active)
4638 if (avc_has_perm(peer_sid, skb->secmark,
4639 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4640 return NF_DROP;
4641
Paul Moore948bf852008-10-10 10:16:32 -04004642 if (netlbl_active)
4643 /* we do this in the FORWARD path and not the POST_ROUTING
4644 * path because we want to make sure we apply the necessary
4645 * labeling before IPsec is applied so we can leverage AH
4646 * protection */
4647 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4648 return NF_DROP;
4649
Paul Mooreeffad8d2008-01-29 08:49:27 -05004650 return NF_ACCEPT;
4651}
4652
4653static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4654 struct sk_buff *skb,
4655 const struct net_device *in,
4656 const struct net_device *out,
4657 int (*okfn)(struct sk_buff *))
4658{
4659 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4660}
4661
4662#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4663static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4664 struct sk_buff *skb,
4665 const struct net_device *in,
4666 const struct net_device *out,
4667 int (*okfn)(struct sk_buff *))
4668{
4669 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4670}
4671#endif /* IPV6 */
4672
Paul Moore948bf852008-10-10 10:16:32 -04004673static unsigned int selinux_ip_output(struct sk_buff *skb,
4674 u16 family)
4675{
4676 u32 sid;
4677
4678 if (!netlbl_enabled())
4679 return NF_ACCEPT;
4680
4681 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4682 * because we want to make sure we apply the necessary labeling
4683 * before IPsec is applied so we can leverage AH protection */
4684 if (skb->sk) {
4685 struct sk_security_struct *sksec = skb->sk->sk_security;
4686 sid = sksec->sid;
4687 } else
4688 sid = SECINITSID_KERNEL;
4689 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4690 return NF_DROP;
4691
4692 return NF_ACCEPT;
4693}
4694
4695static unsigned int selinux_ipv4_output(unsigned int hooknum,
4696 struct sk_buff *skb,
4697 const struct net_device *in,
4698 const struct net_device *out,
4699 int (*okfn)(struct sk_buff *))
4700{
4701 return selinux_ip_output(skb, PF_INET);
4702}
4703
Paul Mooreeffad8d2008-01-29 08:49:27 -05004704static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4705 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004706 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004707{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004708 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004709 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004710 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004711 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004712 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004713 char *addrp;
4714 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004715
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 if (sk == NULL)
4717 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004718 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004719
Thomas Liu2bf49692009-07-14 12:14:09 -04004720 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004721 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004722 ad.u.net = &net;
4723 ad.u.net->netif = ifindex;
4724 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004725 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4726 return NF_DROP;
4727
Paul Moore58bfbb52009-03-27 17:10:41 -04004728 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004729 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004730 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004731 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004732
Steffen Klassertb9679a72011-02-23 12:55:21 +01004733 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4734 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004735
Paul Mooreeffad8d2008-01-29 08:49:27 -05004736 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737}
4738
Paul Mooreeffad8d2008-01-29 08:49:27 -05004739static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4740 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004742 u32 secmark_perm;
4743 u32 peer_sid;
4744 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004745 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004746 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004747 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004748 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004749 u8 secmark_active;
4750 u8 peerlbl_active;
4751
Paul Mooreeffad8d2008-01-29 08:49:27 -05004752 /* If any sort of compatibility mode is enabled then handoff processing
4753 * to the selinux_ip_postroute_compat() function to deal with the
4754 * special handling. We do this in an attempt to keep this function
4755 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004756 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004757 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004758#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004759 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4760 * packet transformation so allow the packet to pass without any checks
4761 * since we'll have another chance to perform access control checks
4762 * when the packet is on it's final way out.
4763 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4764 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004765 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004766 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004767#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004768 secmark_active = selinux_secmark_enabled();
4769 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4770 if (!secmark_active && !peerlbl_active)
4771 return NF_ACCEPT;
4772
Paul Moored8395c82008-10-10 10:16:30 -04004773 /* if the packet is being forwarded then get the peer label from the
4774 * packet itself; otherwise check to see if it is from a local
4775 * application or the kernel, if from an application get the peer label
4776 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004777 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004778 if (sk == NULL) {
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004779 if (skb->skb_iif) {
4780 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004781 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004782 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004783 } else {
4784 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004785 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004786 }
Paul Moored8395c82008-10-10 10:16:30 -04004787 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004788 struct sk_security_struct *sksec = sk->sk_security;
4789 peer_sid = sksec->sid;
4790 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004791 }
4792
Thomas Liu2bf49692009-07-14 12:14:09 -04004793 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004794 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004795 ad.u.net = &net;
4796 ad.u.net->netif = ifindex;
4797 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004798 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004799 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004800
Paul Mooreeffad8d2008-01-29 08:49:27 -05004801 if (secmark_active)
4802 if (avc_has_perm(peer_sid, skb->secmark,
4803 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004804 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004805
4806 if (peerlbl_active) {
4807 u32 if_sid;
4808 u32 node_sid;
4809
4810 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004811 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004812 if (avc_has_perm(peer_sid, if_sid,
4813 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004814 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004815
4816 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004817 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004818 if (avc_has_perm(peer_sid, node_sid,
4819 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004820 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004821 }
4822
4823 return NF_ACCEPT;
4824}
4825
4826static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4827 struct sk_buff *skb,
4828 const struct net_device *in,
4829 const struct net_device *out,
4830 int (*okfn)(struct sk_buff *))
4831{
4832 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833}
4834
4835#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004836static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4837 struct sk_buff *skb,
4838 const struct net_device *in,
4839 const struct net_device *out,
4840 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004842 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844#endif /* IPV6 */
4845
4846#endif /* CONFIG_NETFILTER */
4847
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4849{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 int err;
4851
Eric Paris200ac532009-02-12 15:01:04 -05004852 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 if (err)
4854 return err;
4855
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004856 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857}
4858
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859static int ipc_alloc_security(struct task_struct *task,
4860 struct kern_ipc_perm *perm,
4861 u16 sclass)
4862{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004864 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
James Morris89d155e2005-10-30 14:59:21 -08004866 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 if (!isec)
4868 return -ENOMEM;
4869
David Howells275bb412008-11-14 10:39:19 +11004870 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004872 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 perm->security = isec;
4874
4875 return 0;
4876}
4877
4878static void ipc_free_security(struct kern_ipc_perm *perm)
4879{
4880 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 perm->security = NULL;
4882 kfree(isec);
4883}
4884
4885static int msg_msg_alloc_security(struct msg_msg *msg)
4886{
4887 struct msg_security_struct *msec;
4888
James Morris89d155e2005-10-30 14:59:21 -08004889 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 if (!msec)
4891 return -ENOMEM;
4892
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 msec->sid = SECINITSID_UNLABELED;
4894 msg->security = msec;
4895
4896 return 0;
4897}
4898
4899static void msg_msg_free_security(struct msg_msg *msg)
4900{
4901 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902
4903 msg->security = NULL;
4904 kfree(msec);
4905}
4906
4907static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004908 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004911 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004912 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004913 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 isec = ipc_perms->security;
4916
Thomas Liu2bf49692009-07-14 12:14:09 -04004917 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004918 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 ad.u.ipc_id = ipc_perms->key;
4920
David Howells275bb412008-11-14 10:39:19 +11004921 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922}
4923
4924static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4925{
4926 return msg_msg_alloc_security(msg);
4927}
4928
4929static void selinux_msg_msg_free_security(struct msg_msg *msg)
4930{
4931 msg_msg_free_security(msg);
4932}
4933
4934/* message queue security operations */
4935static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4936{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004938 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004939 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004940 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 int rc;
4942
4943 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4944 if (rc)
4945 return rc;
4946
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 isec = msq->q_perm.security;
4948
Thomas Liu2bf49692009-07-14 12:14:09 -04004949 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004950 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04004951 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
David Howells275bb412008-11-14 10:39:19 +11004953 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 MSGQ__CREATE, &ad);
4955 if (rc) {
4956 ipc_free_security(&msq->q_perm);
4957 return rc;
4958 }
4959 return 0;
4960}
4961
4962static void selinux_msg_queue_free_security(struct msg_queue *msq)
4963{
4964 ipc_free_security(&msq->q_perm);
4965}
4966
4967static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4968{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004970 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004971 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004972 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 isec = msq->q_perm.security;
4975
Thomas Liu2bf49692009-07-14 12:14:09 -04004976 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004977 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 ad.u.ipc_id = msq->q_perm.key;
4979
David Howells275bb412008-11-14 10:39:19 +11004980 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 MSGQ__ASSOCIATE, &ad);
4982}
4983
4984static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4985{
4986 int err;
4987 int perms;
4988
Eric Paris828dfe12008-04-17 13:17:49 -04004989 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 case IPC_INFO:
4991 case MSG_INFO:
4992 /* No specific object, just general system-wide information. */
4993 return task_has_system(current, SYSTEM__IPC_INFO);
4994 case IPC_STAT:
4995 case MSG_STAT:
4996 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4997 break;
4998 case IPC_SET:
4999 perms = MSGQ__SETATTR;
5000 break;
5001 case IPC_RMID:
5002 perms = MSGQ__DESTROY;
5003 break;
5004 default:
5005 return 0;
5006 }
5007
Stephen Smalley6af963f2005-05-01 08:58:39 -07005008 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 return err;
5010}
5011
5012static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
5013{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 struct ipc_security_struct *isec;
5015 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005016 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005017 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005018 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 int rc;
5020
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 isec = msq->q_perm.security;
5022 msec = msg->security;
5023
5024 /*
5025 * First time through, need to assign label to the message
5026 */
5027 if (msec->sid == SECINITSID_UNLABELED) {
5028 /*
5029 * Compute new sid based on current process and
5030 * message queue this message will be stored in
5031 */
David Howells275bb412008-11-14 10:39:19 +11005032 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05005033 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 if (rc)
5035 return rc;
5036 }
5037
Thomas Liu2bf49692009-07-14 12:14:09 -04005038 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005039 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 ad.u.ipc_id = msq->q_perm.key;
5041
5042 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005043 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 MSGQ__WRITE, &ad);
5045 if (!rc)
5046 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005047 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5048 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 if (!rc)
5050 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005051 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5052 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053
5054 return rc;
5055}
5056
5057static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5058 struct task_struct *target,
5059 long type, int mode)
5060{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 struct ipc_security_struct *isec;
5062 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005063 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005064 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005065 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 int rc;
5067
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 isec = msq->q_perm.security;
5069 msec = msg->security;
5070
Thomas Liu2bf49692009-07-14 12:14:09 -04005071 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005072 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005073 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074
David Howells275bb412008-11-14 10:39:19 +11005075 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 SECCLASS_MSGQ, MSGQ__READ, &ad);
5077 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005078 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 SECCLASS_MSG, MSG__RECEIVE, &ad);
5080 return rc;
5081}
5082
5083/* Shared Memory security operations */
5084static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5085{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005087 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005088 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005089 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 int rc;
5091
5092 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5093 if (rc)
5094 return rc;
5095
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 isec = shp->shm_perm.security;
5097
Thomas Liu2bf49692009-07-14 12:14:09 -04005098 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005099 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005100 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101
David Howells275bb412008-11-14 10:39:19 +11005102 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 SHM__CREATE, &ad);
5104 if (rc) {
5105 ipc_free_security(&shp->shm_perm);
5106 return rc;
5107 }
5108 return 0;
5109}
5110
5111static void selinux_shm_free_security(struct shmid_kernel *shp)
5112{
5113 ipc_free_security(&shp->shm_perm);
5114}
5115
5116static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5117{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005119 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005120 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005121 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 isec = shp->shm_perm.security;
5124
Thomas Liu2bf49692009-07-14 12:14:09 -04005125 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005126 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 ad.u.ipc_id = shp->shm_perm.key;
5128
David Howells275bb412008-11-14 10:39:19 +11005129 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 SHM__ASSOCIATE, &ad);
5131}
5132
5133/* Note, at this point, shp is locked down */
5134static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5135{
5136 int perms;
5137 int err;
5138
Eric Paris828dfe12008-04-17 13:17:49 -04005139 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 case IPC_INFO:
5141 case SHM_INFO:
5142 /* No specific object, just general system-wide information. */
5143 return task_has_system(current, SYSTEM__IPC_INFO);
5144 case IPC_STAT:
5145 case SHM_STAT:
5146 perms = SHM__GETATTR | SHM__ASSOCIATE;
5147 break;
5148 case IPC_SET:
5149 perms = SHM__SETATTR;
5150 break;
5151 case SHM_LOCK:
5152 case SHM_UNLOCK:
5153 perms = SHM__LOCK;
5154 break;
5155 case IPC_RMID:
5156 perms = SHM__DESTROY;
5157 break;
5158 default:
5159 return 0;
5160 }
5161
Stephen Smalley6af963f2005-05-01 08:58:39 -07005162 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 return err;
5164}
5165
5166static int selinux_shm_shmat(struct shmid_kernel *shp,
5167 char __user *shmaddr, int shmflg)
5168{
5169 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170
5171 if (shmflg & SHM_RDONLY)
5172 perms = SHM__READ;
5173 else
5174 perms = SHM__READ | SHM__WRITE;
5175
Stephen Smalley6af963f2005-05-01 08:58:39 -07005176 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177}
5178
5179/* Semaphore security operations */
5180static int selinux_sem_alloc_security(struct sem_array *sma)
5181{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005183 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005184 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005185 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 int rc;
5187
5188 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5189 if (rc)
5190 return rc;
5191
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 isec = sma->sem_perm.security;
5193
Thomas Liu2bf49692009-07-14 12:14:09 -04005194 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005195 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005196 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197
David Howells275bb412008-11-14 10:39:19 +11005198 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 SEM__CREATE, &ad);
5200 if (rc) {
5201 ipc_free_security(&sma->sem_perm);
5202 return rc;
5203 }
5204 return 0;
5205}
5206
5207static void selinux_sem_free_security(struct sem_array *sma)
5208{
5209 ipc_free_security(&sma->sem_perm);
5210}
5211
5212static int selinux_sem_associate(struct sem_array *sma, int semflg)
5213{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005215 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005216 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005217 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 isec = sma->sem_perm.security;
5220
Thomas Liu2bf49692009-07-14 12:14:09 -04005221 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005222 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 ad.u.ipc_id = sma->sem_perm.key;
5224
David Howells275bb412008-11-14 10:39:19 +11005225 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 SEM__ASSOCIATE, &ad);
5227}
5228
5229/* Note, at this point, sma is locked down */
5230static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5231{
5232 int err;
5233 u32 perms;
5234
Eric Paris828dfe12008-04-17 13:17:49 -04005235 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 case IPC_INFO:
5237 case SEM_INFO:
5238 /* No specific object, just general system-wide information. */
5239 return task_has_system(current, SYSTEM__IPC_INFO);
5240 case GETPID:
5241 case GETNCNT:
5242 case GETZCNT:
5243 perms = SEM__GETATTR;
5244 break;
5245 case GETVAL:
5246 case GETALL:
5247 perms = SEM__READ;
5248 break;
5249 case SETVAL:
5250 case SETALL:
5251 perms = SEM__WRITE;
5252 break;
5253 case IPC_RMID:
5254 perms = SEM__DESTROY;
5255 break;
5256 case IPC_SET:
5257 perms = SEM__SETATTR;
5258 break;
5259 case IPC_STAT:
5260 case SEM_STAT:
5261 perms = SEM__GETATTR | SEM__ASSOCIATE;
5262 break;
5263 default:
5264 return 0;
5265 }
5266
Stephen Smalley6af963f2005-05-01 08:58:39 -07005267 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 return err;
5269}
5270
5271static int selinux_sem_semop(struct sem_array *sma,
5272 struct sembuf *sops, unsigned nsops, int alter)
5273{
5274 u32 perms;
5275
5276 if (alter)
5277 perms = SEM__READ | SEM__WRITE;
5278 else
5279 perms = SEM__READ;
5280
Stephen Smalley6af963f2005-05-01 08:58:39 -07005281 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282}
5283
5284static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5285{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 u32 av = 0;
5287
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 av = 0;
5289 if (flag & S_IRUGO)
5290 av |= IPC__UNIX_READ;
5291 if (flag & S_IWUGO)
5292 av |= IPC__UNIX_WRITE;
5293
5294 if (av == 0)
5295 return 0;
5296
Stephen Smalley6af963f2005-05-01 08:58:39 -07005297 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298}
5299
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005300static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5301{
5302 struct ipc_security_struct *isec = ipcp->security;
5303 *secid = isec->sid;
5304}
5305
Eric Paris828dfe12008-04-17 13:17:49 -04005306static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307{
5308 if (inode)
5309 inode_doinit_with_dentry(inode, dentry);
5310}
5311
5312static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005313 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314{
David Howells275bb412008-11-14 10:39:19 +11005315 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005316 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005318 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319
5320 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005321 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 if (error)
5323 return error;
5324 }
5325
David Howells275bb412008-11-14 10:39:19 +11005326 rcu_read_lock();
5327 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328
5329 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005330 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005332 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005334 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005336 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005337 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005338 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005339 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005340 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 else
David Howells275bb412008-11-14 10:39:19 +11005342 goto invalid;
5343 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
5345 if (!sid)
5346 return 0;
5347
Al Viro04ff9702007-03-12 16:17:58 +00005348 error = security_sid_to_context(sid, value, &len);
5349 if (error)
5350 return error;
5351 return len;
David Howells275bb412008-11-14 10:39:19 +11005352
5353invalid:
5354 rcu_read_unlock();
5355 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356}
5357
5358static int selinux_setprocattr(struct task_struct *p,
5359 char *name, void *value, size_t size)
5360{
5361 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005362 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005363 struct cred *new;
5364 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 int error;
5366 char *str = value;
5367
5368 if (current != p) {
5369 /* SELinux only allows a process to change its own
5370 security attributes. */
5371 return -EACCES;
5372 }
5373
5374 /*
5375 * Basic control over ability to set these attributes at all.
5376 * current == p, but we'll pass them separately in case the
5377 * above restriction is ever removed.
5378 */
5379 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005380 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005382 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005383 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005384 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005385 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005386 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005388 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 else
5390 error = -EINVAL;
5391 if (error)
5392 return error;
5393
5394 /* Obtain a SID for the context, if one was specified. */
5395 if (size && str[1] && str[1] != '\n') {
5396 if (str[size-1] == '\n') {
5397 str[size-1] = 0;
5398 size--;
5399 }
5400 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005401 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5402 if (!capable(CAP_MAC_ADMIN))
5403 return error;
5404 error = security_context_to_sid_force(value, size,
5405 &sid);
5406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 if (error)
5408 return error;
5409 }
5410
David Howellsd84f4f92008-11-14 10:39:23 +11005411 new = prepare_creds();
5412 if (!new)
5413 return -ENOMEM;
5414
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 /* Permission checking based on the specified context is
5416 performed during the actual operation (execve,
5417 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005418 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 checks and may_create for the file creation checks. The
5420 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005421 tsec = new->security;
5422 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005424 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005426 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005427 error = may_create_key(sid, p);
5428 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005429 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005430 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005431 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005432 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005433 } else if (!strcmp(name, "current")) {
5434 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005436 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005437
David Howellsd84f4f92008-11-14 10:39:23 +11005438 /* Only allow single threaded processes to change context */
5439 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005440 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005441 error = security_bounded_transition(tsec->sid, sid);
5442 if (error)
5443 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445
5446 /* Check permissions for the transition. */
5447 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005448 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005450 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451
5452 /* Check for ptracing, and update the task SID if ok.
5453 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005454 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 task_lock(p);
Tejun Heo06d98472011-06-17 16:50:40 +02005456 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005457 if (tracer)
5458 ptsid = task_sid(tracer);
5459 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460
David Howellsd84f4f92008-11-14 10:39:23 +11005461 if (tracer) {
5462 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5463 PROCESS__PTRACE, NULL);
5464 if (error)
5465 goto abort_change;
5466 }
5467
5468 tsec->sid = sid;
5469 } else {
5470 error = -EINVAL;
5471 goto abort_change;
5472 }
5473
5474 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005476
5477abort_change:
5478 abort_creds(new);
5479 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480}
5481
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005482static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5483{
5484 return security_sid_to_context(secid, secdata, seclen);
5485}
5486
David Howells7bf570d2008-04-29 20:52:51 +01005487static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005488{
5489 return security_context_to_sid(secdata, seclen, secid);
5490}
5491
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005492static void selinux_release_secctx(char *secdata, u32 seclen)
5493{
Paul Moore088999e2007-08-01 11:12:58 -04005494 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005495}
5496
David P. Quigley1ee65e32009-09-03 14:25:57 -04005497/*
5498 * called with inode->i_mutex locked
5499 */
5500static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5501{
5502 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5503}
5504
5505/*
5506 * called with inode->i_mutex locked
5507 */
5508static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5509{
5510 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5511}
5512
5513static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5514{
5515 int len = 0;
5516 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5517 ctx, true);
5518 if (len < 0)
5519 return len;
5520 *ctxlen = len;
5521 return 0;
5522}
Michael LeMayd7200242006-06-22 14:47:17 -07005523#ifdef CONFIG_KEYS
5524
David Howellsd84f4f92008-11-14 10:39:23 +11005525static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005526 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005527{
David Howellsd84f4f92008-11-14 10:39:23 +11005528 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005529 struct key_security_struct *ksec;
5530
5531 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5532 if (!ksec)
5533 return -ENOMEM;
5534
David Howellsd84f4f92008-11-14 10:39:23 +11005535 tsec = cred->security;
5536 if (tsec->keycreate_sid)
5537 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005538 else
David Howellsd84f4f92008-11-14 10:39:23 +11005539 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005540
David Howells275bb412008-11-14 10:39:19 +11005541 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005542 return 0;
5543}
5544
5545static void selinux_key_free(struct key *k)
5546{
5547 struct key_security_struct *ksec = k->security;
5548
5549 k->security = NULL;
5550 kfree(ksec);
5551}
5552
5553static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005554 const struct cred *cred,
5555 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005556{
5557 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005558 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005559 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005560
5561 /* if no specific permissions are requested, we skip the
5562 permission check. No serious, additional covert channels
5563 appear to be created. */
5564 if (perm == 0)
5565 return 0;
5566
David Howellsd84f4f92008-11-14 10:39:23 +11005567 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005568
5569 key = key_ref_to_ptr(key_ref);
5570 ksec = key->security;
5571
5572 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005573}
5574
David Howells70a5bb72008-04-29 01:01:26 -07005575static int selinux_key_getsecurity(struct key *key, char **_buffer)
5576{
5577 struct key_security_struct *ksec = key->security;
5578 char *context = NULL;
5579 unsigned len;
5580 int rc;
5581
5582 rc = security_sid_to_context(ksec->sid, &context, &len);
5583 if (!rc)
5584 rc = len;
5585 *_buffer = context;
5586 return rc;
5587}
5588
Michael LeMayd7200242006-06-22 14:47:17 -07005589#endif
5590
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005592 .name = "selinux",
5593
Stephen Smalley84ab2cd2012-11-05 08:15:34 -05005594 .binder_set_context_mgr = selinux_binder_set_context_mgr,
5595 .binder_transaction = selinux_binder_transaction,
5596 .binder_transfer_binder = selinux_binder_transfer_binder,
5597 .binder_transfer_file = selinux_binder_transfer_file,
5598
Ingo Molnar9e488582009-05-07 19:26:19 +10005599 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005600 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005602 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 .capable = selinux_capable,
5604 .quotactl = selinux_quotactl,
5605 .quota_on = selinux_quota_on,
5606 .syslog = selinux_syslog,
5607 .vm_enough_memory = selinux_vm_enough_memory,
5608
5609 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610
David Howellsa6f76f22008-11-14 10:39:24 +11005611 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005612 .bprm_committing_creds = selinux_bprm_committing_creds,
5613 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 .bprm_secureexec = selinux_bprm_secureexec,
5615
5616 .sb_alloc_security = selinux_sb_alloc_security,
5617 .sb_free_security = selinux_sb_free_security,
5618 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005619 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005620 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005621 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 .sb_statfs = selinux_sb_statfs,
5623 .sb_mount = selinux_mount,
5624 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005625 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005626 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005627 .sb_parse_opts_str = selinux_parse_opts_str,
5628
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629
5630 .inode_alloc_security = selinux_inode_alloc_security,
5631 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005632 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 .inode_unlink = selinux_inode_unlink,
5636 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 .inode_rmdir = selinux_inode_rmdir,
5639 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 .inode_readlink = selinux_inode_readlink,
5642 .inode_follow_link = selinux_inode_follow_link,
5643 .inode_permission = selinux_inode_permission,
5644 .inode_setattr = selinux_inode_setattr,
5645 .inode_getattr = selinux_inode_getattr,
5646 .inode_setxattr = selinux_inode_setxattr,
5647 .inode_post_setxattr = selinux_inode_post_setxattr,
5648 .inode_getxattr = selinux_inode_getxattr,
5649 .inode_listxattr = selinux_inode_listxattr,
5650 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005651 .inode_getsecurity = selinux_inode_getsecurity,
5652 .inode_setsecurity = selinux_inode_setsecurity,
5653 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005654 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655
5656 .file_permission = selinux_file_permission,
5657 .file_alloc_security = selinux_file_alloc_security,
5658 .file_free_security = selinux_file_free_security,
5659 .file_ioctl = selinux_file_ioctl,
5660 .file_mmap = selinux_file_mmap,
5661 .file_mprotect = selinux_file_mprotect,
5662 .file_lock = selinux_file_lock,
5663 .file_fcntl = selinux_file_fcntl,
5664 .file_set_fowner = selinux_file_set_fowner,
5665 .file_send_sigiotask = selinux_file_send_sigiotask,
5666 .file_receive = selinux_file_receive,
5667
Eric Paris828dfe12008-04-17 13:17:49 -04005668 .dentry_open = selinux_dentry_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005669
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005671 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005672 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005673 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005674 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005675 .kernel_act_as = selinux_kernel_act_as,
5676 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005677 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 .task_setpgid = selinux_task_setpgid,
5679 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005680 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005681 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005683 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005684 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 .task_setrlimit = selinux_task_setrlimit,
5686 .task_setscheduler = selinux_task_setscheduler,
5687 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005688 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 .task_kill = selinux_task_kill,
5690 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005691 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
5693 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005694 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695
5696 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5697 .msg_msg_free_security = selinux_msg_msg_free_security,
5698
5699 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5700 .msg_queue_free_security = selinux_msg_queue_free_security,
5701 .msg_queue_associate = selinux_msg_queue_associate,
5702 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5703 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5704 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5705
5706 .shm_alloc_security = selinux_shm_alloc_security,
5707 .shm_free_security = selinux_shm_free_security,
5708 .shm_associate = selinux_shm_associate,
5709 .shm_shmctl = selinux_shm_shmctl,
5710 .shm_shmat = selinux_shm_shmat,
5711
Eric Paris828dfe12008-04-17 13:17:49 -04005712 .sem_alloc_security = selinux_sem_alloc_security,
5713 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 .sem_associate = selinux_sem_associate,
5715 .sem_semctl = selinux_sem_semctl,
5716 .sem_semop = selinux_sem_semop,
5717
Eric Paris828dfe12008-04-17 13:17:49 -04005718 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719
Eric Paris828dfe12008-04-17 13:17:49 -04005720 .getprocattr = selinux_getprocattr,
5721 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005723 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005724 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005725 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005726 .inode_notifysecctx = selinux_inode_notifysecctx,
5727 .inode_setsecctx = selinux_inode_setsecctx,
5728 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005729
Eric Paris828dfe12008-04-17 13:17:49 -04005730 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 .unix_may_send = selinux_socket_unix_may_send,
5732
5733 .socket_create = selinux_socket_create,
5734 .socket_post_create = selinux_socket_post_create,
5735 .socket_bind = selinux_socket_bind,
5736 .socket_connect = selinux_socket_connect,
5737 .socket_listen = selinux_socket_listen,
5738 .socket_accept = selinux_socket_accept,
5739 .socket_sendmsg = selinux_socket_sendmsg,
5740 .socket_recvmsg = selinux_socket_recvmsg,
5741 .socket_getsockname = selinux_socket_getsockname,
5742 .socket_getpeername = selinux_socket_getpeername,
5743 .socket_getsockopt = selinux_socket_getsockopt,
5744 .socket_setsockopt = selinux_socket_setsockopt,
5745 .socket_shutdown = selinux_socket_shutdown,
5746 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005747 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5748 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 .sk_alloc_security = selinux_sk_alloc_security,
5750 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005751 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005752 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005753 .sock_graft = selinux_sock_graft,
5754 .inet_conn_request = selinux_inet_conn_request,
5755 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005756 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005757 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5758 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5759 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005760 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005761 .tun_dev_create = selinux_tun_dev_create,
5762 .tun_dev_post_create = selinux_tun_dev_post_create,
5763 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005764
5765#ifdef CONFIG_SECURITY_NETWORK_XFRM
5766 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5767 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5768 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005769 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005770 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5771 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005772 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005773 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005774 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005775 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005777
5778#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005779 .key_alloc = selinux_key_alloc,
5780 .key_free = selinux_key_free,
5781 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005782 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005783#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005784
5785#ifdef CONFIG_AUDIT
5786 .audit_rule_init = selinux_audit_rule_init,
5787 .audit_rule_known = selinux_audit_rule_known,
5788 .audit_rule_match = selinux_audit_rule_match,
5789 .audit_rule_free = selinux_audit_rule_free,
5790#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791};
5792
5793static __init int selinux_init(void)
5794{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005795 if (!security_module_enable(&selinux_ops)) {
5796 selinux_enabled = 0;
5797 return 0;
5798 }
5799
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 if (!selinux_enabled) {
5801 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5802 return 0;
5803 }
5804
5805 printk(KERN_INFO "SELinux: Initializing.\n");
5806
5807 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005808 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005810 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5811
James Morris7cae7e22006-03-22 00:09:22 -08005812 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5813 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005814 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 avc_init();
5816
Eric Paris828dfe12008-04-17 13:17:49 -04005817 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 panic("SELinux: Unable to register with kernel.\n");
5819
Eric Paris828dfe12008-04-17 13:17:49 -04005820 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005821 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005822 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005823 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005824
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 return 0;
5826}
5827
Al Viroe8c26252010-03-23 06:36:54 -04005828static void delayed_superblock_init(struct super_block *sb, void *unused)
5829{
5830 superblock_doinit(sb, NULL);
5831}
5832
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833void selinux_complete_init(void)
5834{
Eric Parisfadcdb42007-02-22 18:11:31 -05005835 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836
5837 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005838 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005839 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840}
5841
5842/* SELinux requires early initialization in order to label
5843 all processes and objects when they are created. */
5844security_initcall(selinux_init);
5845
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005846#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
Paul Mooreeffad8d2008-01-29 08:49:27 -05005848static struct nf_hook_ops selinux_ipv4_ops[] = {
5849 {
5850 .hook = selinux_ipv4_postroute,
5851 .owner = THIS_MODULE,
5852 .pf = PF_INET,
5853 .hooknum = NF_INET_POST_ROUTING,
5854 .priority = NF_IP_PRI_SELINUX_LAST,
5855 },
5856 {
5857 .hook = selinux_ipv4_forward,
5858 .owner = THIS_MODULE,
5859 .pf = PF_INET,
5860 .hooknum = NF_INET_FORWARD,
5861 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005862 },
5863 {
5864 .hook = selinux_ipv4_output,
5865 .owner = THIS_MODULE,
5866 .pf = PF_INET,
5867 .hooknum = NF_INET_LOCAL_OUT,
5868 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870};
5871
5872#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5873
Paul Mooreeffad8d2008-01-29 08:49:27 -05005874static struct nf_hook_ops selinux_ipv6_ops[] = {
5875 {
5876 .hook = selinux_ipv6_postroute,
5877 .owner = THIS_MODULE,
5878 .pf = PF_INET6,
5879 .hooknum = NF_INET_POST_ROUTING,
5880 .priority = NF_IP6_PRI_SELINUX_LAST,
5881 },
5882 {
5883 .hook = selinux_ipv6_forward,
5884 .owner = THIS_MODULE,
5885 .pf = PF_INET6,
5886 .hooknum = NF_INET_FORWARD,
5887 .priority = NF_IP6_PRI_SELINUX_FIRST,
5888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889};
5890
5891#endif /* IPV6 */
5892
5893static int __init selinux_nf_ip_init(void)
5894{
5895 int err = 0;
5896
5897 if (!selinux_enabled)
5898 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005899
5900 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5901
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005902 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5903 if (err)
5904 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905
5906#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005907 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5908 if (err)
5909 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005911
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912out:
5913 return err;
5914}
5915
5916__initcall(selinux_nf_ip_init);
5917
5918#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5919static void selinux_nf_ip_exit(void)
5920{
Eric Parisfadcdb42007-02-22 18:11:31 -05005921 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005923 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005925 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926#endif /* IPV6 */
5927}
5928#endif
5929
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005930#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931
5932#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5933#define selinux_nf_ip_exit()
5934#endif
5935
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005936#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937
5938#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005939static int selinux_disabled;
5940
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941int selinux_disable(void)
5942{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 if (ss_initialized) {
5944 /* Not permitted after initial policy load. */
5945 return -EINVAL;
5946 }
5947
5948 if (selinux_disabled) {
5949 /* Only do this once. */
5950 return -EINVAL;
5951 }
5952
5953 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5954
5955 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005956 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08005958 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959
Eric Parisaf8ff042009-09-20 21:23:01 -04005960 /* Try to destroy the avc node cache */
5961 avc_disable();
5962
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 /* Unregister netfilter hooks. */
5964 selinux_nf_ip_exit();
5965
5966 /* Unregister selinuxfs. */
5967 exit_sel_fs();
5968
5969 return 0;
5970}
5971#endif