blob: 8417a6afaf30c6a82a499deddab24c68b5a52b77 [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 Sharma600634972011-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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 /* Initialize the root inode. */
Eric Parisc9180a52007-11-30 13:00:35 -0500409 rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
411 /* Initialize any other inodes associated with the superblock, e.g.
412 inodes created prior to initial policy load or inodes created
413 during get_sb by a pseudo filesystem that directly
414 populates itself. */
415 spin_lock(&sbsec->isec_lock);
416next_inode:
417 if (!list_empty(&sbsec->isec_head)) {
418 struct inode_security_struct *isec =
419 list_entry(sbsec->isec_head.next,
Eric Parisc9180a52007-11-30 13:00:35 -0500420 struct inode_security_struct, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 struct inode *inode = isec->inode;
422 spin_unlock(&sbsec->isec_lock);
423 inode = igrab(inode);
424 if (inode) {
Eric Parisc9180a52007-11-30 13:00:35 -0500425 if (!IS_PRIVATE(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 inode_doinit(inode);
427 iput(inode);
428 }
429 spin_lock(&sbsec->isec_lock);
430 list_del_init(&isec->list);
431 goto next_inode;
432 }
433 spin_unlock(&sbsec->isec_lock);
434out:
Eric Parisc9180a52007-11-30 13:00:35 -0500435 return rc;
436}
437
438/*
439 * This function should allow an FS to ask what it's mount security
440 * options were so it can use those later for submounts, displaying
441 * mount options, or whatever.
442 */
443static int selinux_get_mnt_opts(const struct super_block *sb,
Eric Parise0007522008-03-05 10:31:54 -0500444 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500445{
446 int rc = 0, i;
447 struct superblock_security_struct *sbsec = sb->s_security;
448 char *context = NULL;
449 u32 len;
450 char tmp;
451
Eric Parise0007522008-03-05 10:31:54 -0500452 security_init_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500453
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500454 if (!(sbsec->flags & SE_SBINITIALIZED))
Eric Parisc9180a52007-11-30 13:00:35 -0500455 return -EINVAL;
456
457 if (!ss_initialized)
458 return -EINVAL;
459
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500460 tmp = sbsec->flags & SE_MNTMASK;
Eric Parisc9180a52007-11-30 13:00:35 -0500461 /* count the number of mount options for this sb */
462 for (i = 0; i < 8; i++) {
463 if (tmp & 0x01)
Eric Parise0007522008-03-05 10:31:54 -0500464 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500465 tmp >>= 1;
466 }
David P. Quigley11689d42009-01-16 09:22:03 -0500467 /* Check if the Label support flag is set */
468 if (sbsec->flags & SE_SBLABELSUPP)
469 opts->num_mnt_opts++;
Eric Parisc9180a52007-11-30 13:00:35 -0500470
Eric Parise0007522008-03-05 10:31:54 -0500471 opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
472 if (!opts->mnt_opts) {
Eric Parisc9180a52007-11-30 13:00:35 -0500473 rc = -ENOMEM;
474 goto out_free;
475 }
476
Eric Parise0007522008-03-05 10:31:54 -0500477 opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
478 if (!opts->mnt_opts_flags) {
Eric Parisc9180a52007-11-30 13:00:35 -0500479 rc = -ENOMEM;
480 goto out_free;
481 }
482
483 i = 0;
484 if (sbsec->flags & FSCONTEXT_MNT) {
485 rc = security_sid_to_context(sbsec->sid, &context, &len);
486 if (rc)
487 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500488 opts->mnt_opts[i] = context;
489 opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500490 }
491 if (sbsec->flags & CONTEXT_MNT) {
492 rc = security_sid_to_context(sbsec->mntpoint_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++] = CONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500497 }
498 if (sbsec->flags & DEFCONTEXT_MNT) {
499 rc = security_sid_to_context(sbsec->def_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++] = DEFCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500504 }
505 if (sbsec->flags & ROOTCONTEXT_MNT) {
506 struct inode *root = sbsec->sb->s_root->d_inode;
507 struct inode_security_struct *isec = root->i_security;
508
509 rc = security_sid_to_context(isec->sid, &context, &len);
510 if (rc)
511 goto out_free;
Eric Parise0007522008-03-05 10:31:54 -0500512 opts->mnt_opts[i] = context;
513 opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
Eric Parisc9180a52007-11-30 13:00:35 -0500514 }
David P. Quigley11689d42009-01-16 09:22:03 -0500515 if (sbsec->flags & SE_SBLABELSUPP) {
516 opts->mnt_opts[i] = NULL;
517 opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
518 }
Eric Parisc9180a52007-11-30 13:00:35 -0500519
Eric Parise0007522008-03-05 10:31:54 -0500520 BUG_ON(i != opts->num_mnt_opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500521
522 return 0;
523
524out_free:
Eric Parise0007522008-03-05 10:31:54 -0500525 security_free_mnt_opts(opts);
Eric Parisc9180a52007-11-30 13:00:35 -0500526 return rc;
527}
528
529static int bad_option(struct superblock_security_struct *sbsec, char flag,
530 u32 old_sid, u32 new_sid)
531{
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500532 char mnt_flags = sbsec->flags & SE_MNTMASK;
533
Eric Parisc9180a52007-11-30 13:00:35 -0500534 /* check if the old mount command had the same options */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500535 if (sbsec->flags & SE_SBINITIALIZED)
Eric Parisc9180a52007-11-30 13:00:35 -0500536 if (!(sbsec->flags & flag) ||
537 (old_sid != new_sid))
538 return 1;
539
540 /* check if we were passed the same options twice,
541 * aka someone passed context=a,context=b
542 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500543 if (!(sbsec->flags & SE_SBINITIALIZED))
544 if (mnt_flags & flag)
Eric Parisc9180a52007-11-30 13:00:35 -0500545 return 1;
546 return 0;
547}
Eric Parise0007522008-03-05 10:31:54 -0500548
Eric Parisc9180a52007-11-30 13:00:35 -0500549/*
550 * Allow filesystems with binary mount data to explicitly set mount point
551 * labeling information.
552 */
Eric Parise0007522008-03-05 10:31:54 -0500553static int selinux_set_mnt_opts(struct super_block *sb,
554 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500555{
David Howells275bb412008-11-14 10:39:19 +1100556 const struct cred *cred = current_cred();
Eric Parisc9180a52007-11-30 13:00:35 -0500557 int rc = 0, i;
Eric Parisc9180a52007-11-30 13:00:35 -0500558 struct superblock_security_struct *sbsec = sb->s_security;
559 const char *name = sb->s_type->name;
James Morris089be432008-07-15 18:32:49 +1000560 struct inode *inode = sbsec->sb->s_root->d_inode;
561 struct inode_security_struct *root_isec = inode->i_security;
Eric Parisc9180a52007-11-30 13:00:35 -0500562 u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
563 u32 defcontext_sid = 0;
Eric Parise0007522008-03-05 10:31:54 -0500564 char **mount_options = opts->mnt_opts;
565 int *flags = opts->mnt_opts_flags;
566 int num_opts = opts->num_mnt_opts;
Eric Parisc9180a52007-11-30 13:00:35 -0500567
568 mutex_lock(&sbsec->lock);
569
570 if (!ss_initialized) {
571 if (!num_opts) {
572 /* Defer initialization until selinux_complete_init,
573 after the initial policy is loaded and the security
574 server is ready to handle calls. */
Eric Parisc9180a52007-11-30 13:00:35 -0500575 goto out;
576 }
577 rc = -EINVAL;
Eric Paris744ba352008-04-17 11:52:44 -0400578 printk(KERN_WARNING "SELinux: Unable to set superblock options "
579 "before the security server is initialized\n");
Eric Parisc9180a52007-11-30 13:00:35 -0500580 goto out;
581 }
582
583 /*
Eric Parise0007522008-03-05 10:31:54 -0500584 * Binary mount data FS will come through this function twice. Once
585 * from an explicit call and once from the generic calls from the vfs.
586 * Since the generic VFS calls will not contain any security mount data
587 * we need to skip the double mount verification.
588 *
589 * This does open a hole in which we will not notice if the first
590 * mount using this sb set explict options and a second mount using
591 * this sb does not set any security options. (The first options
592 * will be used for both mounts)
593 */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500594 if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
Eric Parise0007522008-03-05 10:31:54 -0500595 && (num_opts == 0))
Eric Parisf5269712008-05-14 11:27:45 -0400596 goto out;
Eric Parise0007522008-03-05 10:31:54 -0500597
598 /*
Eric Parisc9180a52007-11-30 13:00:35 -0500599 * parse the mount options, check if they are valid sids.
600 * also check if someone is trying to mount the same sb more
601 * than once with different security options.
602 */
603 for (i = 0; i < num_opts; i++) {
604 u32 sid;
David P. Quigley11689d42009-01-16 09:22:03 -0500605
606 if (flags[i] == SE_SBLABELSUPP)
607 continue;
Eric Parisc9180a52007-11-30 13:00:35 -0500608 rc = security_context_to_sid(mount_options[i],
609 strlen(mount_options[i]), &sid);
610 if (rc) {
611 printk(KERN_WARNING "SELinux: security_context_to_sid"
612 "(%s) failed for (dev %s, type %s) errno=%d\n",
613 mount_options[i], sb->s_id, name, rc);
614 goto out;
615 }
616 switch (flags[i]) {
617 case FSCONTEXT_MNT:
618 fscontext_sid = sid;
619
620 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
621 fscontext_sid))
622 goto out_double_mount;
623
624 sbsec->flags |= FSCONTEXT_MNT;
625 break;
626 case CONTEXT_MNT:
627 context_sid = sid;
628
629 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
630 context_sid))
631 goto out_double_mount;
632
633 sbsec->flags |= CONTEXT_MNT;
634 break;
635 case ROOTCONTEXT_MNT:
636 rootcontext_sid = sid;
637
638 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
639 rootcontext_sid))
640 goto out_double_mount;
641
642 sbsec->flags |= ROOTCONTEXT_MNT;
643
644 break;
645 case DEFCONTEXT_MNT:
646 defcontext_sid = sid;
647
648 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
649 defcontext_sid))
650 goto out_double_mount;
651
652 sbsec->flags |= DEFCONTEXT_MNT;
653
654 break;
655 default:
656 rc = -EINVAL;
657 goto out;
658 }
659 }
660
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500661 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Parisc9180a52007-11-30 13:00:35 -0500662 /* previously mounted with options, but not on this attempt? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500663 if ((sbsec->flags & SE_MNTMASK) && !num_opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500664 goto out_double_mount;
665 rc = 0;
666 goto out;
667 }
668
James Morris089be432008-07-15 18:32:49 +1000669 if (strcmp(sb->s_type->name, "proc") == 0)
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500670 sbsec->flags |= SE_SBPROC;
Eric Parisc9180a52007-11-30 13:00:35 -0500671
672 /* Determine the labeling behavior to use for this filesystem type. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500673 rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
Eric Parisc9180a52007-11-30 13:00:35 -0500674 if (rc) {
675 printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
James Morris089be432008-07-15 18:32:49 +1000676 __func__, sb->s_type->name, rc);
Eric Parisc9180a52007-11-30 13:00:35 -0500677 goto out;
678 }
679
680 /* sets the context of the superblock for the fs being mounted. */
681 if (fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100682 rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500683 if (rc)
684 goto out;
685
686 sbsec->sid = fscontext_sid;
687 }
688
689 /*
690 * Switch to using mount point labeling behavior.
691 * sets the label used on all file below the mountpoint, and will set
692 * the superblock context if not already set.
693 */
694 if (context_sid) {
695 if (!fscontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100696 rc = may_context_mount_sb_relabel(context_sid, sbsec,
697 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500698 if (rc)
699 goto out;
700 sbsec->sid = context_sid;
701 } else {
David Howells275bb412008-11-14 10:39:19 +1100702 rc = may_context_mount_inode_relabel(context_sid, sbsec,
703 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500704 if (rc)
705 goto out;
706 }
707 if (!rootcontext_sid)
708 rootcontext_sid = context_sid;
709
710 sbsec->mntpoint_sid = context_sid;
711 sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
712 }
713
714 if (rootcontext_sid) {
David Howells275bb412008-11-14 10:39:19 +1100715 rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
716 cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500717 if (rc)
718 goto out;
719
720 root_isec->sid = rootcontext_sid;
721 root_isec->initialized = 1;
722 }
723
724 if (defcontext_sid) {
725 if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
726 rc = -EINVAL;
727 printk(KERN_WARNING "SELinux: defcontext option is "
728 "invalid for this filesystem type\n");
729 goto out;
730 }
731
732 if (defcontext_sid != sbsec->def_sid) {
733 rc = may_context_mount_inode_relabel(defcontext_sid,
David Howells275bb412008-11-14 10:39:19 +1100734 sbsec, cred);
Eric Parisc9180a52007-11-30 13:00:35 -0500735 if (rc)
736 goto out;
737 }
738
739 sbsec->def_sid = defcontext_sid;
740 }
741
742 rc = sb_finish_set_opts(sb);
743out:
Eric Parisbc7e9822006-09-25 23:32:02 -0700744 mutex_unlock(&sbsec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return rc;
Eric Parisc9180a52007-11-30 13:00:35 -0500746out_double_mount:
747 rc = -EINVAL;
748 printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
749 "security settings for (dev %s, type %s)\n", sb->s_id, name);
750 goto out;
751}
752
753static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
754 struct super_block *newsb)
755{
756 const struct superblock_security_struct *oldsbsec = oldsb->s_security;
757 struct superblock_security_struct *newsbsec = newsb->s_security;
758
759 int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
760 int set_context = (oldsbsec->flags & CONTEXT_MNT);
761 int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
762
Eric Paris0f5e6422008-04-21 16:24:11 -0400763 /*
764 * if the parent was able to be mounted it clearly had no special lsm
Al Viroe8c26252010-03-23 06:36:54 -0400765 * mount options. thus we can safely deal with this superblock later
Eric Paris0f5e6422008-04-21 16:24:11 -0400766 */
Al Viroe8c26252010-03-23 06:36:54 -0400767 if (!ss_initialized)
Eric Paris0f5e6422008-04-21 16:24:11 -0400768 return;
Eric Parisc9180a52007-11-30 13:00:35 -0500769
Eric Parisc9180a52007-11-30 13:00:35 -0500770 /* how can we clone if the old one wasn't set up?? */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500771 BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
Eric Parisc9180a52007-11-30 13:00:35 -0500772
Eric Paris5a552612008-04-09 14:08:35 -0400773 /* if fs is reusing a sb, just let its options stand... */
David P. Quigley0d90a7e2009-01-16 09:22:02 -0500774 if (newsbsec->flags & SE_SBINITIALIZED)
Eric Paris5a552612008-04-09 14:08:35 -0400775 return;
776
Eric Parisc9180a52007-11-30 13:00:35 -0500777 mutex_lock(&newsbsec->lock);
778
779 newsbsec->flags = oldsbsec->flags;
780
781 newsbsec->sid = oldsbsec->sid;
782 newsbsec->def_sid = oldsbsec->def_sid;
783 newsbsec->behavior = oldsbsec->behavior;
784
785 if (set_context) {
786 u32 sid = oldsbsec->mntpoint_sid;
787
788 if (!set_fscontext)
789 newsbsec->sid = sid;
790 if (!set_rootcontext) {
791 struct inode *newinode = newsb->s_root->d_inode;
792 struct inode_security_struct *newisec = newinode->i_security;
793 newisec->sid = sid;
794 }
795 newsbsec->mntpoint_sid = sid;
796 }
797 if (set_rootcontext) {
798 const struct inode *oldinode = oldsb->s_root->d_inode;
799 const struct inode_security_struct *oldisec = oldinode->i_security;
800 struct inode *newinode = newsb->s_root->d_inode;
801 struct inode_security_struct *newisec = newinode->i_security;
802
803 newisec->sid = oldisec->sid;
804 }
805
806 sb_finish_set_opts(newsb);
807 mutex_unlock(&newsbsec->lock);
808}
809
Adrian Bunk2e1479d2008-03-17 22:29:23 +0200810static int selinux_parse_opts_str(char *options,
811 struct security_mnt_opts *opts)
Eric Parisc9180a52007-11-30 13:00:35 -0500812{
Eric Parise0007522008-03-05 10:31:54 -0500813 char *p;
Eric Parisc9180a52007-11-30 13:00:35 -0500814 char *context = NULL, *defcontext = NULL;
815 char *fscontext = NULL, *rootcontext = NULL;
Eric Parise0007522008-03-05 10:31:54 -0500816 int rc, num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500817
Eric Parise0007522008-03-05 10:31:54 -0500818 opts->num_mnt_opts = 0;
Eric Parisc9180a52007-11-30 13:00:35 -0500819
820 /* Standard string-based options. */
821 while ((p = strsep(&options, "|")) != NULL) {
822 int token;
823 substring_t args[MAX_OPT_ARGS];
824
825 if (!*p)
826 continue;
827
828 token = match_token(p, tokens, args);
829
830 switch (token) {
831 case Opt_context:
832 if (context || defcontext) {
833 rc = -EINVAL;
834 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
835 goto out_err;
836 }
837 context = match_strdup(&args[0]);
838 if (!context) {
839 rc = -ENOMEM;
840 goto out_err;
841 }
842 break;
843
844 case Opt_fscontext:
845 if (fscontext) {
846 rc = -EINVAL;
847 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
848 goto out_err;
849 }
850 fscontext = match_strdup(&args[0]);
851 if (!fscontext) {
852 rc = -ENOMEM;
853 goto out_err;
854 }
855 break;
856
857 case Opt_rootcontext:
858 if (rootcontext) {
859 rc = -EINVAL;
860 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
861 goto out_err;
862 }
863 rootcontext = match_strdup(&args[0]);
864 if (!rootcontext) {
865 rc = -ENOMEM;
866 goto out_err;
867 }
868 break;
869
870 case Opt_defcontext:
871 if (context || defcontext) {
872 rc = -EINVAL;
873 printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
874 goto out_err;
875 }
876 defcontext = match_strdup(&args[0]);
877 if (!defcontext) {
878 rc = -ENOMEM;
879 goto out_err;
880 }
881 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500882 case Opt_labelsupport:
883 break;
Eric Parisc9180a52007-11-30 13:00:35 -0500884 default:
885 rc = -EINVAL;
886 printk(KERN_WARNING "SELinux: unknown mount option\n");
887 goto out_err;
888
889 }
890 }
891
Eric Parise0007522008-03-05 10:31:54 -0500892 rc = -ENOMEM;
893 opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
894 if (!opts->mnt_opts)
895 goto out_err;
896
897 opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
898 if (!opts->mnt_opts_flags) {
899 kfree(opts->mnt_opts);
900 goto out_err;
Eric Parisc9180a52007-11-30 13:00:35 -0500901 }
902
Eric Parise0007522008-03-05 10:31:54 -0500903 if (fscontext) {
904 opts->mnt_opts[num_mnt_opts] = fscontext;
905 opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
906 }
907 if (context) {
908 opts->mnt_opts[num_mnt_opts] = context;
909 opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
910 }
911 if (rootcontext) {
912 opts->mnt_opts[num_mnt_opts] = rootcontext;
913 opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
914 }
915 if (defcontext) {
916 opts->mnt_opts[num_mnt_opts] = defcontext;
917 opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
918 }
919
920 opts->num_mnt_opts = num_mnt_opts;
921 return 0;
922
Eric Parisc9180a52007-11-30 13:00:35 -0500923out_err:
924 kfree(context);
925 kfree(defcontext);
926 kfree(fscontext);
927 kfree(rootcontext);
928 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
Eric Parise0007522008-03-05 10:31:54 -0500930/*
931 * string mount options parsing and call set the sbsec
932 */
933static int superblock_doinit(struct super_block *sb, void *data)
934{
935 int rc = 0;
936 char *options = data;
937 struct security_mnt_opts opts;
938
939 security_init_mnt_opts(&opts);
940
941 if (!data)
942 goto out;
943
944 BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
945
946 rc = selinux_parse_opts_str(options, &opts);
947 if (rc)
948 goto out_err;
949
950out:
951 rc = selinux_set_mnt_opts(sb, &opts);
952
953out_err:
954 security_free_mnt_opts(&opts);
955 return rc;
956}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Adrian Bunk3583a712008-07-22 20:21:23 +0300958static void selinux_write_opts(struct seq_file *m,
959 struct security_mnt_opts *opts)
Eric Paris2069f452008-07-04 09:47:13 +1000960{
961 int i;
962 char *prefix;
963
964 for (i = 0; i < opts->num_mnt_opts; i++) {
David P. Quigley11689d42009-01-16 09:22:03 -0500965 char *has_comma;
966
967 if (opts->mnt_opts[i])
968 has_comma = strchr(opts->mnt_opts[i], ',');
969 else
970 has_comma = NULL;
Eric Paris2069f452008-07-04 09:47:13 +1000971
972 switch (opts->mnt_opts_flags[i]) {
973 case CONTEXT_MNT:
974 prefix = CONTEXT_STR;
975 break;
976 case FSCONTEXT_MNT:
977 prefix = FSCONTEXT_STR;
978 break;
979 case ROOTCONTEXT_MNT:
980 prefix = ROOTCONTEXT_STR;
981 break;
982 case DEFCONTEXT_MNT:
983 prefix = DEFCONTEXT_STR;
984 break;
David P. Quigley11689d42009-01-16 09:22:03 -0500985 case SE_SBLABELSUPP:
986 seq_putc(m, ',');
987 seq_puts(m, LABELSUPP_STR);
988 continue;
Eric Paris2069f452008-07-04 09:47:13 +1000989 default:
990 BUG();
Eric Parisa35c6c832011-04-20 10:21:28 -0400991 return;
Eric Paris2069f452008-07-04 09:47:13 +1000992 };
993 /* we need a comma before each option */
994 seq_putc(m, ',');
995 seq_puts(m, prefix);
996 if (has_comma)
997 seq_putc(m, '\"');
998 seq_puts(m, opts->mnt_opts[i]);
999 if (has_comma)
1000 seq_putc(m, '\"');
1001 }
1002}
1003
1004static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
1005{
1006 struct security_mnt_opts opts;
1007 int rc;
1008
1009 rc = selinux_get_mnt_opts(sb, &opts);
Eric Paris383795c2008-07-29 17:07:26 -04001010 if (rc) {
1011 /* before policy load we may get EINVAL, don't show anything */
1012 if (rc == -EINVAL)
1013 rc = 0;
Eric Paris2069f452008-07-04 09:47:13 +10001014 return rc;
Eric Paris383795c2008-07-29 17:07:26 -04001015 }
Eric Paris2069f452008-07-04 09:47:13 +10001016
1017 selinux_write_opts(m, &opts);
1018
1019 security_free_mnt_opts(&opts);
1020
1021 return rc;
1022}
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024static inline u16 inode_mode_to_security_class(umode_t mode)
1025{
1026 switch (mode & S_IFMT) {
1027 case S_IFSOCK:
1028 return SECCLASS_SOCK_FILE;
1029 case S_IFLNK:
1030 return SECCLASS_LNK_FILE;
1031 case S_IFREG:
1032 return SECCLASS_FILE;
1033 case S_IFBLK:
1034 return SECCLASS_BLK_FILE;
1035 case S_IFDIR:
1036 return SECCLASS_DIR;
1037 case S_IFCHR:
1038 return SECCLASS_CHR_FILE;
1039 case S_IFIFO:
1040 return SECCLASS_FIFO_FILE;
1041
1042 }
1043
1044 return SECCLASS_FILE;
1045}
1046
James Morris13402582005-09-30 14:24:34 -04001047static inline int default_protocol_stream(int protocol)
1048{
1049 return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
1050}
1051
1052static inline int default_protocol_dgram(int protocol)
1053{
1054 return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
1055}
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057static inline u16 socket_type_to_security_class(int family, int type, int protocol)
1058{
1059 switch (family) {
1060 case PF_UNIX:
1061 switch (type) {
1062 case SOCK_STREAM:
1063 case SOCK_SEQPACKET:
1064 return SECCLASS_UNIX_STREAM_SOCKET;
1065 case SOCK_DGRAM:
1066 return SECCLASS_UNIX_DGRAM_SOCKET;
1067 }
1068 break;
1069 case PF_INET:
1070 case PF_INET6:
1071 switch (type) {
1072 case SOCK_STREAM:
James Morris13402582005-09-30 14:24:34 -04001073 if (default_protocol_stream(protocol))
1074 return SECCLASS_TCP_SOCKET;
1075 else
1076 return SECCLASS_RAWIP_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 case SOCK_DGRAM:
James Morris13402582005-09-30 14:24:34 -04001078 if (default_protocol_dgram(protocol))
1079 return SECCLASS_UDP_SOCKET;
1080 else
1081 return SECCLASS_RAWIP_SOCKET;
James Morris2ee92d42006-11-13 16:09:01 -08001082 case SOCK_DCCP:
1083 return SECCLASS_DCCP_SOCKET;
James Morris13402582005-09-30 14:24:34 -04001084 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 return SECCLASS_RAWIP_SOCKET;
1086 }
1087 break;
1088 case PF_NETLINK:
1089 switch (protocol) {
1090 case NETLINK_ROUTE:
1091 return SECCLASS_NETLINK_ROUTE_SOCKET;
1092 case NETLINK_FIREWALL:
1093 return SECCLASS_NETLINK_FIREWALL_SOCKET;
Pavel Emelyanov7f1fb602011-12-06 07:56:43 +00001094 case NETLINK_SOCK_DIAG:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return SECCLASS_NETLINK_TCPDIAG_SOCKET;
1096 case NETLINK_NFLOG:
1097 return SECCLASS_NETLINK_NFLOG_SOCKET;
1098 case NETLINK_XFRM:
1099 return SECCLASS_NETLINK_XFRM_SOCKET;
1100 case NETLINK_SELINUX:
1101 return SECCLASS_NETLINK_SELINUX_SOCKET;
1102 case NETLINK_AUDIT:
1103 return SECCLASS_NETLINK_AUDIT_SOCKET;
1104 case NETLINK_IP6_FW:
1105 return SECCLASS_NETLINK_IP6FW_SOCKET;
1106 case NETLINK_DNRTMSG:
1107 return SECCLASS_NETLINK_DNRT_SOCKET;
James Morris0c9b7942005-04-16 15:24:13 -07001108 case NETLINK_KOBJECT_UEVENT:
1109 return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 default:
1111 return SECCLASS_NETLINK_SOCKET;
1112 }
1113 case PF_PACKET:
1114 return SECCLASS_PACKET_SOCKET;
1115 case PF_KEY:
1116 return SECCLASS_KEY_SOCKET;
Christopher J. PeBenito3e3ff152006-06-09 00:25:03 -07001117 case PF_APPLETALK:
1118 return SECCLASS_APPLETALK_SOCKET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
1120
1121 return SECCLASS_SOCKET;
1122}
1123
1124#ifdef CONFIG_PROC_FS
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001125static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 u16 tclass,
1127 u32 *sid)
1128{
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001129 int rc;
1130 char *buffer, *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Eric Paris828dfe12008-04-17 13:17:49 -04001132 buffer = (char *)__get_free_page(GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (!buffer)
1134 return -ENOMEM;
1135
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001136 path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
1137 if (IS_ERR(path))
1138 rc = PTR_ERR(path);
1139 else {
1140 /* each process gets a /proc/PID/ entry. Strip off the
1141 * PID part to get a valid selinux labeling.
1142 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
1143 while (path[1] >= '0' && path[1] <= '9') {
1144 path[1] = '/';
1145 path++;
1146 }
1147 rc = security_genfs_sid("proc", path, tclass, sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 free_page((unsigned long)buffer);
1150 return rc;
1151}
1152#else
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001153static int selinux_proc_get_sid(struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 u16 tclass,
1155 u32 *sid)
1156{
1157 return -EINVAL;
1158}
1159#endif
1160
1161/* The inode's security attributes must be initialized before first use. */
1162static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
1163{
1164 struct superblock_security_struct *sbsec = NULL;
1165 struct inode_security_struct *isec = inode->i_security;
1166 u32 sid;
1167 struct dentry *dentry;
1168#define INITCONTEXTLEN 255
1169 char *context = NULL;
1170 unsigned len = 0;
1171 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173 if (isec->initialized)
1174 goto out;
1175
Eric Paris23970742006-09-25 23:32:01 -07001176 mutex_lock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (isec->initialized)
Eric Paris23970742006-09-25 23:32:01 -07001178 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
1180 sbsec = inode->i_sb->s_security;
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001181 if (!(sbsec->flags & SE_SBINITIALIZED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 /* Defer initialization until selinux_complete_init,
1183 after the initial policy is loaded and the security
1184 server is ready to handle calls. */
1185 spin_lock(&sbsec->isec_lock);
1186 if (list_empty(&isec->list))
1187 list_add(&isec->list, &sbsec->isec_head);
1188 spin_unlock(&sbsec->isec_lock);
Eric Paris23970742006-09-25 23:32:01 -07001189 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 }
1191
1192 switch (sbsec->behavior) {
1193 case SECURITY_FS_USE_XATTR:
1194 if (!inode->i_op->getxattr) {
1195 isec->sid = sbsec->def_sid;
1196 break;
1197 }
1198
1199 /* Need a dentry, since the xattr API requires one.
1200 Life would be simpler if we could just pass the inode. */
1201 if (opt_dentry) {
1202 /* Called from d_instantiate or d_splice_alias. */
1203 dentry = dget(opt_dentry);
1204 } else {
1205 /* Called from selinux_complete_init, try to find a dentry. */
1206 dentry = d_find_alias(inode);
1207 }
1208 if (!dentry) {
Eric Parisdf7f54c2009-03-09 14:35:58 -04001209 /*
1210 * this is can be hit on boot when a file is accessed
1211 * before the policy is loaded. When we load policy we
1212 * may find inodes that have no dentry on the
1213 * sbsec->isec_head list. No reason to complain as these
1214 * will get fixed up the next time we go through
1215 * inode_doinit with a dentry, before these inodes could
1216 * be used again by userspace.
1217 */
Eric Paris23970742006-09-25 23:32:01 -07001218 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
1220
1221 len = INITCONTEXTLEN;
Eric Paris4cb912f2009-02-12 14:50:05 -05001222 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 if (!context) {
1224 rc = -ENOMEM;
1225 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001226 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001228 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1230 context, len);
1231 if (rc == -ERANGE) {
James Morris314dabb2009-08-10 22:00:13 +10001232 kfree(context);
1233
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 /* Need a larger buffer. Query for the right size. */
1235 rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
1236 NULL, 0);
1237 if (rc < 0) {
1238 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001239 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 len = rc;
Eric Paris4cb912f2009-02-12 14:50:05 -05001242 context = kmalloc(len+1, GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (!context) {
1244 rc = -ENOMEM;
1245 dput(dentry);
Eric Paris23970742006-09-25 23:32:01 -07001246 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 }
Eric Paris4cb912f2009-02-12 14:50:05 -05001248 context[len] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 rc = inode->i_op->getxattr(dentry,
1250 XATTR_NAME_SELINUX,
1251 context, len);
1252 }
1253 dput(dentry);
1254 if (rc < 0) {
1255 if (rc != -ENODATA) {
Eric Paris744ba352008-04-17 11:52:44 -04001256 printk(KERN_WARNING "SELinux: %s: getxattr returned "
Harvey Harrisondd6f9532008-03-06 10:03:59 +11001257 "%d for dev=%s ino=%ld\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 -rc, inode->i_sb->s_id, inode->i_ino);
1259 kfree(context);
Eric Paris23970742006-09-25 23:32:01 -07001260 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 }
1262 /* Map ENODATA to the default file SID */
1263 sid = sbsec->def_sid;
1264 rc = 0;
1265 } else {
James Morrisf5c1d5b2005-07-28 01:07:37 -07001266 rc = security_context_to_sid_default(context, rc, &sid,
Stephen Smalley869ab512008-04-04 08:46:05 -04001267 sbsec->def_sid,
1268 GFP_NOFS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if (rc) {
Eric Paris4ba0a8a2009-02-12 15:01:10 -05001270 char *dev = inode->i_sb->s_id;
1271 unsigned long ino = inode->i_ino;
1272
1273 if (rc == -EINVAL) {
1274 if (printk_ratelimit())
1275 printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
1276 "context=%s. This indicates you may need to relabel the inode or the "
1277 "filesystem in question.\n", ino, dev, context);
1278 } else {
1279 printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
1280 "returned %d for dev=%s ino=%ld\n",
1281 __func__, context, -rc, dev, ino);
1282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 kfree(context);
1284 /* Leave with the unlabeled SID */
1285 rc = 0;
1286 break;
1287 }
1288 }
1289 kfree(context);
1290 isec->sid = sid;
1291 break;
1292 case SECURITY_FS_USE_TASK:
1293 isec->sid = isec->task_sid;
1294 break;
1295 case SECURITY_FS_USE_TRANS:
1296 /* Default to the fs SID. */
1297 isec->sid = sbsec->sid;
1298
1299 /* Try to obtain a transition SID. */
1300 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Eric Paris652bb9b2011-02-01 11:05:40 -05001301 rc = security_transition_sid(isec->task_sid, sbsec->sid,
1302 isec->sclass, NULL, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001304 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 isec->sid = sid;
1306 break;
Eric Parisc312feb2006-07-10 04:43:53 -07001307 case SECURITY_FS_USE_MNTPOINT:
1308 isec->sid = sbsec->mntpoint_sid;
1309 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 default:
Eric Parisc312feb2006-07-10 04:43:53 -07001311 /* Default to the fs superblock SID. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 isec->sid = sbsec->sid;
1313
David P. Quigley0d90a7e2009-01-16 09:22:02 -05001314 if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001315 if (opt_dentry) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Lucian Adrian Grijincu8e6c9692011-02-01 18:42:22 +02001317 rc = selinux_proc_get_sid(opt_dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 isec->sclass,
1319 &sid);
1320 if (rc)
Eric Paris23970742006-09-25 23:32:01 -07001321 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 isec->sid = sid;
1323 }
1324 }
1325 break;
1326 }
1327
1328 isec->initialized = 1;
1329
Eric Paris23970742006-09-25 23:32:01 -07001330out_unlock:
1331 mutex_unlock(&isec->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332out:
1333 if (isec->sclass == SECCLASS_FILE)
1334 isec->sclass = inode_mode_to_security_class(inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return rc;
1336}
1337
1338/* Convert a Linux signal to an access vector. */
1339static inline u32 signal_to_av(int sig)
1340{
1341 u32 perm = 0;
1342
1343 switch (sig) {
1344 case SIGCHLD:
1345 /* Commonly granted from child to parent. */
1346 perm = PROCESS__SIGCHLD;
1347 break;
1348 case SIGKILL:
1349 /* Cannot be caught or ignored */
1350 perm = PROCESS__SIGKILL;
1351 break;
1352 case SIGSTOP:
1353 /* Cannot be caught or ignored */
1354 perm = PROCESS__SIGSTOP;
1355 break;
1356 default:
1357 /* All other signals. */
1358 perm = PROCESS__SIGNAL;
1359 break;
1360 }
1361
1362 return perm;
1363}
1364
David Howells275bb412008-11-14 10:39:19 +11001365/*
David Howellsd84f4f92008-11-14 10:39:23 +11001366 * Check permission between a pair of credentials
1367 * fork check, ptrace check, etc.
1368 */
1369static int cred_has_perm(const struct cred *actor,
1370 const struct cred *target,
1371 u32 perms)
1372{
1373 u32 asid = cred_sid(actor), tsid = cred_sid(target);
1374
1375 return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
1376}
1377
1378/*
David Howells88e67f32008-11-14 10:39:21 +11001379 * Check permission between a pair of tasks, e.g. signal checks,
David Howells275bb412008-11-14 10:39:19 +11001380 * fork check, ptrace check, etc.
1381 * tsk1 is the actor and tsk2 is the target
David Howells3b11a1d2008-11-14 10:39:26 +11001382 * - this uses the default subjective creds of tsk1
David Howells275bb412008-11-14 10:39:19 +11001383 */
1384static int task_has_perm(const struct task_struct *tsk1,
1385 const struct task_struct *tsk2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 u32 perms)
1387{
David Howells275bb412008-11-14 10:39:19 +11001388 const struct task_security_struct *__tsec1, *__tsec2;
1389 u32 sid1, sid2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
David Howells275bb412008-11-14 10:39:19 +11001391 rcu_read_lock();
1392 __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
1393 __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
1394 rcu_read_unlock();
1395 return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396}
1397
David Howells3b11a1d2008-11-14 10:39:26 +11001398/*
1399 * Check permission between current and another task, e.g. signal checks,
1400 * fork check, ptrace check, etc.
1401 * current is the actor and tsk2 is the target
1402 * - this uses current's subjective creds
1403 */
1404static int current_has_perm(const struct task_struct *tsk,
1405 u32 perms)
1406{
1407 u32 sid, tsid;
1408
1409 sid = current_sid();
1410 tsid = task_sid(tsk);
1411 return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
1412}
1413
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001414#if CAP_LAST_CAP > 63
1415#error Fix SELinux to handle capabilities > 63.
1416#endif
1417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418/* Check whether a task is allowed to use a capability. */
Eric Paris6a9de492012-01-03 12:25:14 -05001419static int cred_has_capability(const struct cred *cred,
Eric Paris06112162008-11-11 22:02:50 +11001420 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421{
Thomas Liu2bf49692009-07-14 12:14:09 -04001422 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001423 struct selinux_audit_data sad = {0,};
Eric Paris06112162008-11-11 22:02:50 +11001424 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001425 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001426 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001427 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001428 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
Thomas Liu2bf49692009-07-14 12:14:09 -04001430 COMMON_AUDIT_DATA_INIT(&ad, CAP);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001431 ad.selinux_audit_data = &sad;
Eric Paris6a9de492012-01-03 12:25:14 -05001432 ad.tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 ad.u.cap = cap;
1434
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001435 switch (CAP_TO_INDEX(cap)) {
1436 case 0:
1437 sclass = SECCLASS_CAPABILITY;
1438 break;
1439 case 1:
1440 sclass = SECCLASS_CAPABILITY2;
1441 break;
1442 default:
1443 printk(KERN_ERR
1444 "SELinux: out of range capability %d\n", cap);
1445 BUG();
Eric Parisa35c6c832011-04-20 10:21:28 -04001446 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001447 }
Eric Paris06112162008-11-11 22:02:50 +11001448
David Howells275bb412008-11-14 10:39:19 +11001449 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001450 if (audit == SECURITY_CAP_AUDIT) {
1451 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1452 if (rc2)
1453 return rc2;
1454 }
Eric Paris06112162008-11-11 22:02:50 +11001455 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456}
1457
1458/* Check whether a task is allowed to use a system operation. */
1459static int task_has_system(struct task_struct *tsk,
1460 u32 perms)
1461{
David Howells275bb412008-11-14 10:39:19 +11001462 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
David Howells275bb412008-11-14 10:39:19 +11001464 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 SECCLASS_SYSTEM, perms, NULL);
1466}
1467
1468/* Check whether a task has a particular permission to an inode.
1469 The 'adp' parameter is optional and allows other audit
1470 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001471static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 struct inode *inode,
1473 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001474 struct common_audit_data *adp,
1475 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001478 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
David Howellse0e81732009-09-02 09:13:40 +01001480 validate_creds(cred);
1481
Eric Paris828dfe12008-04-17 13:17:49 -04001482 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001483 return 0;
1484
David Howells88e67f32008-11-14 10:39:21 +11001485 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 isec = inode->i_security;
1487
Eric Paris9ade0cf2011-04-25 16:26:29 -04001488 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489}
1490
1491/* Same as inode_has_perm, but pass explicit audit data containing
1492 the dentry to help the auditing code to more easily generate the
1493 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001494static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 struct dentry *dentry,
1496 u32 av)
1497{
1498 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001499 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001500 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001501
Eric Paris2875fa02011-04-28 16:04:24 -04001502 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1503 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001504 ad.selinux_audit_data = &sad;
Eric Paris2875fa02011-04-28 16:04:24 -04001505 return inode_has_perm(cred, inode, av, &ad, 0);
1506}
1507
1508/* Same as inode_has_perm, but pass explicit audit data containing
1509 the path to help the auditing code to more easily generate the
1510 pathname if needed. */
1511static inline int path_has_perm(const struct cred *cred,
1512 struct path *path,
1513 u32 av)
1514{
1515 struct inode *inode = path->dentry->d_inode;
1516 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001517 struct selinux_audit_data sad = {0,};
Eric Paris2875fa02011-04-28 16:04:24 -04001518
Eric Parisf48b7392011-04-25 12:54:27 -04001519 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris2875fa02011-04-28 16:04:24 -04001520 ad.u.path = *path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001521 ad.selinux_audit_data = &sad;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001522 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523}
1524
1525/* Check whether a task can use an open file descriptor to
1526 access an inode in a given way. Check access to the
1527 descriptor itself, and then use dentry_has_perm to
1528 check a particular permission to the file.
1529 Access to the descriptor is implicitly granted if it
1530 has the same SID as the process. If av is zero, then
1531 access to the file is not checked, e.g. for cases
1532 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001533static int file_has_perm(const struct cred *cred,
1534 struct file *file,
1535 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001538 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001539 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001540 struct selinux_audit_data sad = {0,};
David Howells88e67f32008-11-14 10:39:21 +11001541 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 int rc;
1543
Eric Parisf48b7392011-04-25 12:54:27 -04001544 COMMON_AUDIT_DATA_INIT(&ad, PATH);
1545 ad.u.path = file->f_path;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001546 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
David Howells275bb412008-11-14 10:39:19 +11001548 if (sid != fsec->sid) {
1549 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 SECCLASS_FD,
1551 FD__USE,
1552 &ad);
1553 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001554 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 }
1556
1557 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001558 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001560 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
David Howells88e67f32008-11-14 10:39:21 +11001562out:
1563 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564}
1565
1566/* Check whether a task can create a file. */
1567static int may_create(struct inode *dir,
1568 struct dentry *dentry,
1569 u16 tclass)
1570{
Paul Moore5fb49872010-04-22 14:46:19 -04001571 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 struct inode_security_struct *dsec;
1573 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001574 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001575 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001576 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 int rc;
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 dsec = dir->i_security;
1580 sbsec = dir->i_sb->s_security;
1581
David Howells275bb412008-11-14 10:39:19 +11001582 sid = tsec->sid;
1583 newsid = tsec->create_sid;
1584
Eric Parisa2694342011-04-25 13:10:27 -04001585 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1586 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001587 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
David Howells275bb412008-11-14 10:39:19 +11001589 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 DIR__ADD_NAME | DIR__SEARCH,
1591 &ad);
1592 if (rc)
1593 return rc;
1594
David P. Quigleycd895962009-01-16 09:22:04 -05001595 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001596 rc = security_transition_sid(sid, dsec->sid, tclass,
1597 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 if (rc)
1599 return rc;
1600 }
1601
David Howells275bb412008-11-14 10:39:19 +11001602 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (rc)
1604 return rc;
1605
1606 return avc_has_perm(newsid, sbsec->sid,
1607 SECCLASS_FILESYSTEM,
1608 FILESYSTEM__ASSOCIATE, &ad);
1609}
1610
Michael LeMay4eb582c2006-06-26 00:24:57 -07001611/* Check whether a task can create a key. */
1612static int may_create_key(u32 ksid,
1613 struct task_struct *ctx)
1614{
David Howells275bb412008-11-14 10:39:19 +11001615 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001616
David Howells275bb412008-11-14 10:39:19 +11001617 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001618}
1619
Eric Paris828dfe12008-04-17 13:17:49 -04001620#define MAY_LINK 0
1621#define MAY_UNLINK 1
1622#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
1624/* Check whether a task can link, unlink, or rmdir a file/directory. */
1625static int may_link(struct inode *dir,
1626 struct dentry *dentry,
1627 int kind)
1628
1629{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001631 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001632 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001633 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 u32 av;
1635 int rc;
1636
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 dsec = dir->i_security;
1638 isec = dentry->d_inode->i_security;
1639
Eric Parisa2694342011-04-25 13:10:27 -04001640 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
1641 ad.u.dentry = dentry;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001642 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644 av = DIR__SEARCH;
1645 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001646 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if (rc)
1648 return rc;
1649
1650 switch (kind) {
1651 case MAY_LINK:
1652 av = FILE__LINK;
1653 break;
1654 case MAY_UNLINK:
1655 av = FILE__UNLINK;
1656 break;
1657 case MAY_RMDIR:
1658 av = DIR__RMDIR;
1659 break;
1660 default:
Eric Paris744ba352008-04-17 11:52:44 -04001661 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1662 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 return 0;
1664 }
1665
David Howells275bb412008-11-14 10:39:19 +11001666 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 return rc;
1668}
1669
1670static inline int may_rename(struct inode *old_dir,
1671 struct dentry *old_dentry,
1672 struct inode *new_dir,
1673 struct dentry *new_dentry)
1674{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001676 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001677 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11001678 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 u32 av;
1680 int old_is_dir, new_is_dir;
1681 int rc;
1682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 old_dsec = old_dir->i_security;
1684 old_isec = old_dentry->d_inode->i_security;
1685 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1686 new_dsec = new_dir->i_security;
1687
Eric Parisa2694342011-04-25 13:10:27 -04001688 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07001689 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Eric Parisa2694342011-04-25 13:10:27 -04001691 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001692 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1694 if (rc)
1695 return rc;
David Howells275bb412008-11-14 10:39:19 +11001696 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 old_isec->sclass, FILE__RENAME, &ad);
1698 if (rc)
1699 return rc;
1700 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001701 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 old_isec->sclass, DIR__REPARENT, &ad);
1703 if (rc)
1704 return rc;
1705 }
1706
Eric Parisa2694342011-04-25 13:10:27 -04001707 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 av = DIR__ADD_NAME | DIR__SEARCH;
1709 if (new_dentry->d_inode)
1710 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001711 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 if (rc)
1713 return rc;
1714 if (new_dentry->d_inode) {
1715 new_isec = new_dentry->d_inode->i_security;
1716 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001717 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 new_isec->sclass,
1719 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1720 if (rc)
1721 return rc;
1722 }
1723
1724 return 0;
1725}
1726
1727/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001728static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 struct super_block *sb,
1730 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001731 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001734 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001737 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738}
1739
1740/* Convert a Linux mode and permission mask to an access vector. */
1741static inline u32 file_mask_to_av(int mode, int mask)
1742{
1743 u32 av = 0;
1744
Al Virodba19c62011-07-25 20:49:29 -04001745 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 if (mask & MAY_EXEC)
1747 av |= FILE__EXECUTE;
1748 if (mask & MAY_READ)
1749 av |= FILE__READ;
1750
1751 if (mask & MAY_APPEND)
1752 av |= FILE__APPEND;
1753 else if (mask & MAY_WRITE)
1754 av |= FILE__WRITE;
1755
1756 } else {
1757 if (mask & MAY_EXEC)
1758 av |= DIR__SEARCH;
1759 if (mask & MAY_WRITE)
1760 av |= DIR__WRITE;
1761 if (mask & MAY_READ)
1762 av |= DIR__READ;
1763 }
1764
1765 return av;
1766}
1767
1768/* Convert a Linux file to an access vector. */
1769static inline u32 file_to_av(struct file *file)
1770{
1771 u32 av = 0;
1772
1773 if (file->f_mode & FMODE_READ)
1774 av |= FILE__READ;
1775 if (file->f_mode & FMODE_WRITE) {
1776 if (file->f_flags & O_APPEND)
1777 av |= FILE__APPEND;
1778 else
1779 av |= FILE__WRITE;
1780 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001781 if (!av) {
1782 /*
1783 * Special file opened with flags 3 for ioctl-only use.
1784 */
1785 av = FILE__IOCTL;
1786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 return av;
1789}
1790
Eric Paris8b6a5a32008-10-29 17:06:46 -04001791/*
1792 * Convert a file to an access vector and include the correct open
1793 * open permission.
1794 */
1795static inline u32 open_file_to_av(struct file *file)
1796{
1797 u32 av = file_to_av(file);
1798
Eric Paris49b7b8d2010-07-23 11:44:09 -04001799 if (selinux_policycap_openperm)
1800 av |= FILE__OPEN;
1801
Eric Paris8b6a5a32008-10-29 17:06:46 -04001802 return av;
1803}
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805/* Hook functions begin here. */
1806
Ingo Molnar9e488582009-05-07 19:26:19 +10001807static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001808 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 int rc;
1811
Ingo Molnar9e488582009-05-07 19:26:19 +10001812 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 if (rc)
1814 return rc;
1815
Eric Paris69f594a2012-01-03 12:25:15 -05001816 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001817 u32 sid = current_sid();
1818 u32 csid = task_sid(child);
1819 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001820 }
1821
David Howells3b11a1d2008-11-14 10:39:26 +11001822 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001823}
1824
1825static int selinux_ptrace_traceme(struct task_struct *parent)
1826{
1827 int rc;
1828
Eric Paris200ac532009-02-12 15:01:04 -05001829 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001830 if (rc)
1831 return rc;
1832
1833 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834}
1835
1836static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001837 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838{
1839 int error;
1840
David Howells3b11a1d2008-11-14 10:39:26 +11001841 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if (error)
1843 return error;
1844
Eric Paris200ac532009-02-12 15:01:04 -05001845 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846}
1847
David Howellsd84f4f92008-11-14 10:39:23 +11001848static int selinux_capset(struct cred *new, const struct cred *old,
1849 const kernel_cap_t *effective,
1850 const kernel_cap_t *inheritable,
1851 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852{
1853 int error;
1854
Eric Paris200ac532009-02-12 15:01:04 -05001855 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001856 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 if (error)
1858 return error;
1859
David Howellsd84f4f92008-11-14 10:39:23 +11001860 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861}
1862
James Morris5626d3e2009-01-30 10:05:06 +11001863/*
1864 * (This comment used to live with the selinux_task_setuid hook,
1865 * which was removed).
1866 *
1867 * Since setuid only affects the current process, and since the SELinux
1868 * controls are not based on the Linux identity attributes, SELinux does not
1869 * need to control this operation. However, SELinux does control the use of
1870 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1871 */
1872
Eric Paris6a9de492012-01-03 12:25:14 -05001873static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1874 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
1876 int rc;
1877
Eric Paris6a9de492012-01-03 12:25:14 -05001878 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 if (rc)
1880 return rc;
1881
Eric Paris6a9de492012-01-03 12:25:14 -05001882 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883}
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1886{
David Howells88e67f32008-11-14 10:39:21 +11001887 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 int rc = 0;
1889
1890 if (!sb)
1891 return 0;
1892
1893 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001894 case Q_SYNC:
1895 case Q_QUOTAON:
1896 case Q_QUOTAOFF:
1897 case Q_SETINFO:
1898 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001899 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001900 break;
1901 case Q_GETFMT:
1902 case Q_GETINFO:
1903 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001904 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001905 break;
1906 default:
1907 rc = 0; /* let the kernel handle invalid cmds */
1908 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 }
1910 return rc;
1911}
1912
1913static int selinux_quota_on(struct dentry *dentry)
1914{
David Howells88e67f32008-11-14 10:39:21 +11001915 const struct cred *cred = current_cred();
1916
Eric Paris2875fa02011-04-28 16:04:24 -04001917 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918}
1919
Eric Paris12b30522010-11-15 18:36:29 -05001920static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921{
1922 int rc;
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08001925 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
1926 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001927 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1928 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001929 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
1930 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
1931 /* Set level of messages printed to console */
1932 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04001933 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1934 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001935 case SYSLOG_ACTION_CLOSE: /* Close log */
1936 case SYSLOG_ACTION_OPEN: /* Open log */
1937 case SYSLOG_ACTION_READ: /* Read from log */
1938 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
1939 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001940 default:
1941 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1942 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
1944 return rc;
1945}
1946
1947/*
1948 * Check that a process has enough memory to allocate a new virtual
1949 * mapping. 0 means there is enough memory for the allocation to
1950 * succeed and -ENOMEM implies there is not.
1951 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 * Do not audit the selinux permission check, as this is applied to all
1953 * processes that allocate mappings.
1954 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001955static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956{
1957 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Eric Paris6a9de492012-01-03 12:25:14 -05001959 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00001960 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (rc == 0)
1962 cap_sys_admin = 1;
1963
Alan Cox34b4e4a2007-08-22 14:01:28 -07001964 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965}
1966
1967/* binprm security operations */
1968
David Howellsa6f76f22008-11-14 10:39:24 +11001969static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
David Howellsa6f76f22008-11-14 10:39:24 +11001971 const struct task_security_struct *old_tsec;
1972 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001974 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07001975 struct selinux_audit_data sad = {0,};
David Howellsa6f76f22008-11-14 10:39:24 +11001976 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 int rc;
1978
Eric Paris200ac532009-02-12 15:01:04 -05001979 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 if (rc)
1981 return rc;
1982
David Howellsa6f76f22008-11-14 10:39:24 +11001983 /* SELinux context only depends on initial program or script and not
1984 * the script interpreter */
1985 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 return 0;
1987
David Howellsa6f76f22008-11-14 10:39:24 +11001988 old_tsec = current_security();
1989 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 isec = inode->i_security;
1991
1992 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11001993 new_tsec->sid = old_tsec->sid;
1994 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Michael LeMay28eba5b2006-06-27 02:53:42 -07001996 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11001997 new_tsec->create_sid = 0;
1998 new_tsec->keycreate_sid = 0;
1999 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
David Howellsa6f76f22008-11-14 10:39:24 +11002001 if (old_tsec->exec_sid) {
2002 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11002004 new_tsec->exec_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 } else {
2006 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11002007 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05002008 SECCLASS_PROCESS, NULL,
2009 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (rc)
2011 return rc;
2012 }
2013
Eric Parisf48b7392011-04-25 12:54:27 -04002014 COMMON_AUDIT_DATA_INIT(&ad, PATH);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002015 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002016 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Josef Sipek3d5ff522006-12-08 02:37:38 -08002018 if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
David Howellsa6f76f22008-11-14 10:39:24 +11002019 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
David Howellsa6f76f22008-11-14 10:39:24 +11002021 if (new_tsec->sid == old_tsec->sid) {
2022 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2024 if (rc)
2025 return rc;
2026 } else {
2027 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002028 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2030 if (rc)
2031 return rc;
2032
David Howellsa6f76f22008-11-14 10:39:24 +11002033 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2035 if (rc)
2036 return rc;
2037
David Howellsa6f76f22008-11-14 10:39:24 +11002038 /* Check for shared state */
2039 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2040 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2041 SECCLASS_PROCESS, PROCESS__SHARE,
2042 NULL);
2043 if (rc)
2044 return -EPERM;
2045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
David Howellsa6f76f22008-11-14 10:39:24 +11002047 /* Make sure that anyone attempting to ptrace over a task that
2048 * changes its SID has the appropriate permit */
2049 if (bprm->unsafe &
2050 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2051 struct task_struct *tracer;
2052 struct task_security_struct *sec;
2053 u32 ptsid = 0;
2054
2055 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002056 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002057 if (likely(tracer != NULL)) {
2058 sec = __task_cred(tracer)->security;
2059 ptsid = sec->sid;
2060 }
2061 rcu_read_unlock();
2062
2063 if (ptsid != 0) {
2064 rc = avc_has_perm(ptsid, new_tsec->sid,
2065 SECCLASS_PROCESS,
2066 PROCESS__PTRACE, NULL);
2067 if (rc)
2068 return -EPERM;
2069 }
2070 }
2071
2072 /* Clear any possibly unsafe personality bits on exec: */
2073 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 }
2075
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 return 0;
2077}
2078
Eric Paris828dfe12008-04-17 13:17:49 -04002079static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080{
Paul Moore5fb49872010-04-22 14:46:19 -04002081 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002082 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 int atsecure = 0;
2084
David Howells275bb412008-11-14 10:39:19 +11002085 sid = tsec->sid;
2086 osid = tsec->osid;
2087
2088 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 /* Enable secure mode for SIDs transitions unless
2090 the noatsecure permission is granted between
2091 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002092 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002093 SECCLASS_PROCESS,
2094 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 }
2096
Eric Paris200ac532009-02-12 15:01:04 -05002097 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098}
2099
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002101static inline void flush_unauthorized_files(const struct cred *cred,
2102 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103{
Thomas Liu2bf49692009-07-14 12:14:09 -04002104 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002105 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002107 struct tty_struct *tty;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002108 struct fdtable *fdt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 long j = -1;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002110 int drop_tty = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002112 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002114 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002115 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002116 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 /* Revalidate access to controlling tty.
Eric Paris602a8dd2012-04-04 15:01:42 -04002119 Use path_has_perm on the tty path directly rather
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 than using file_has_perm, as this particular open
2121 file may belong to another process and we are only
2122 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002123 file_priv = list_first_entry(&tty->tty_files,
2124 struct tty_file_private, list);
2125 file = file_priv->file;
Eric Paris602a8dd2012-04-04 15:01:42 -04002126 if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002127 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002129 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002130 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002132 /* Reset controlling tty. */
2133 if (drop_tty)
2134 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 /* Revalidate access to inherited open files. */
2137
Eric Parisf48b7392011-04-25 12:54:27 -04002138 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002139 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
2141 spin_lock(&files->file_lock);
2142 for (;;) {
2143 unsigned long set, i;
2144 int fd;
2145
2146 j++;
2147 i = j * __NFDBITS;
Dipankar Sarmabadf1662005-09-09 13:04:10 -07002148 fdt = files_fdtable(files);
Vadim Lobanovbbea9f62006-12-10 02:21:12 -08002149 if (i >= fdt->max_fds)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 break;
David Howells1fd36ad2012-02-16 17:49:54 +00002151 set = fdt->open_fds[j];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 if (!set)
2153 continue;
2154 spin_unlock(&files->file_lock);
Eric Paris828dfe12008-04-17 13:17:49 -04002155 for ( ; set ; i++, set >>= 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 if (set & 1) {
2157 file = fget(i);
2158 if (!file)
2159 continue;
David Howells88e67f32008-11-14 10:39:21 +11002160 if (file_has_perm(cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 file,
2162 file_to_av(file))) {
2163 sys_close(i);
2164 fd = get_unused_fd();
2165 if (fd != i) {
2166 if (fd >= 0)
2167 put_unused_fd(fd);
2168 fput(file);
2169 continue;
2170 }
2171 if (devnull) {
Nick Piggin095975d2006-01-08 01:02:19 -08002172 get_file(devnull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 } else {
David Howells745ca242008-11-14 10:39:22 +11002174 devnull = dentry_open(
2175 dget(selinux_null),
2176 mntget(selinuxfs_mount),
2177 O_RDWR, cred);
Akinobu Mitafc5d81e2006-11-27 15:16:48 +09002178 if (IS_ERR(devnull)) {
2179 devnull = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 put_unused_fd(fd);
2181 fput(file);
2182 continue;
2183 }
2184 }
2185 fd_install(fd, devnull);
2186 }
2187 fput(file);
2188 }
2189 }
2190 spin_lock(&files->file_lock);
2191
2192 }
2193 spin_unlock(&files->file_lock);
2194}
2195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196/*
David Howellsa6f76f22008-11-14 10:39:24 +11002197 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 */
David Howellsa6f76f22008-11-14 10:39:24 +11002199static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200{
David Howellsa6f76f22008-11-14 10:39:24 +11002201 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 int rc, i;
2204
David Howellsa6f76f22008-11-14 10:39:24 +11002205 new_tsec = bprm->cred->security;
2206 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 return;
2208
2209 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002210 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
David Howellsa6f76f22008-11-14 10:39:24 +11002212 /* Always clear parent death signal on SID transitions. */
2213 current->pdeath_signal = 0;
2214
2215 /* Check whether the new SID can inherit resource limits from the old
2216 * SID. If not, reset all soft limits to the lower of the current
2217 * task's hard limit and the init task's soft limit.
2218 *
2219 * Note that the setting of hard limits (even to lower them) can be
2220 * controlled by the setrlimit check. The inclusion of the init task's
2221 * soft limit into the computation is to avoid resetting soft limits
2222 * higher than the default soft limit for cases where the default is
2223 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2224 */
2225 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2226 PROCESS__RLIMITINH, NULL);
2227 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002228 /* protect against do_prlimit() */
2229 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002230 for (i = 0; i < RLIM_NLIMITS; i++) {
2231 rlim = current->signal->rlim + i;
2232 initrlim = init_task.signal->rlim + i;
2233 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2234 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002235 task_unlock(current);
2236 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002237 }
2238}
2239
2240/*
2241 * Clean up the process immediately after the installation of new credentials
2242 * due to exec
2243 */
2244static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2245{
2246 const struct task_security_struct *tsec = current_security();
2247 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002248 u32 osid, sid;
2249 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002250
David Howellsa6f76f22008-11-14 10:39:24 +11002251 osid = tsec->osid;
2252 sid = tsec->sid;
2253
2254 if (sid == osid)
2255 return;
2256
2257 /* Check whether the new SID can inherit signal state from the old SID.
2258 * If not, clear itimers to avoid subsequent signal generation and
2259 * flush and unblock signals.
2260 *
2261 * This must occur _after_ the task SID has been updated so that any
2262 * kill done after the flush will be checked against the new SID.
2263 */
2264 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 if (rc) {
2266 memset(&itimer, 0, sizeof itimer);
2267 for (i = 0; i < 3; i++)
2268 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002270 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2271 __flush_signals(current);
2272 flush_signal_handlers(current, 1);
2273 sigemptyset(&current->blocked);
2274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 spin_unlock_irq(&current->sighand->siglock);
2276 }
2277
David Howellsa6f76f22008-11-14 10:39:24 +11002278 /* Wake up the parent if it is waiting so that it can recheck
2279 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002280 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002281 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002282 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283}
2284
2285/* superblock security operations */
2286
2287static int selinux_sb_alloc_security(struct super_block *sb)
2288{
2289 return superblock_alloc_security(sb);
2290}
2291
2292static void selinux_sb_free_security(struct super_block *sb)
2293{
2294 superblock_free_security(sb);
2295}
2296
2297static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2298{
2299 if (plen > olen)
2300 return 0;
2301
2302 return !memcmp(prefix, option, plen);
2303}
2304
2305static inline int selinux_option(char *option, int len)
2306{
Eric Paris832cbd92008-04-01 13:24:09 -04002307 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2308 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2309 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002310 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2311 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312}
2313
2314static inline void take_option(char **to, char *from, int *first, int len)
2315{
2316 if (!*first) {
2317 **to = ',';
2318 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002319 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 *first = 0;
2321 memcpy(*to, from, len);
2322 *to += len;
2323}
2324
Eric Paris828dfe12008-04-17 13:17:49 -04002325static inline void take_selinux_option(char **to, char *from, int *first,
2326 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002327{
2328 int current_size = 0;
2329
2330 if (!*first) {
2331 **to = '|';
2332 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002333 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002334 *first = 0;
2335
2336 while (current_size < len) {
2337 if (*from != '"') {
2338 **to = *from;
2339 *to += 1;
2340 }
2341 from += 1;
2342 current_size += 1;
2343 }
2344}
2345
Eric Parise0007522008-03-05 10:31:54 -05002346static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347{
2348 int fnosec, fsec, rc = 0;
2349 char *in_save, *in_curr, *in_end;
2350 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002351 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352
2353 in_curr = orig;
2354 sec_curr = copy;
2355
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2357 if (!nosec) {
2358 rc = -ENOMEM;
2359 goto out;
2360 }
2361
2362 nosec_save = nosec;
2363 fnosec = fsec = 1;
2364 in_save = in_end = orig;
2365
2366 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002367 if (*in_end == '"')
2368 open_quote = !open_quote;
2369 if ((*in_end == ',' && open_quote == 0) ||
2370 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 int len = in_end - in_curr;
2372
2373 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002374 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 else
2376 take_option(&nosec, in_curr, &fnosec, len);
2377
2378 in_curr = in_end + 1;
2379 }
2380 } while (*in_end++);
2381
Eric Paris6931dfc2005-06-30 02:58:51 -07002382 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002383 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384out:
2385 return rc;
2386}
2387
Eric Paris026eb162011-03-03 16:09:14 -05002388static int selinux_sb_remount(struct super_block *sb, void *data)
2389{
2390 int rc, i, *flags;
2391 struct security_mnt_opts opts;
2392 char *secdata, **mount_options;
2393 struct superblock_security_struct *sbsec = sb->s_security;
2394
2395 if (!(sbsec->flags & SE_SBINITIALIZED))
2396 return 0;
2397
2398 if (!data)
2399 return 0;
2400
2401 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2402 return 0;
2403
2404 security_init_mnt_opts(&opts);
2405 secdata = alloc_secdata();
2406 if (!secdata)
2407 return -ENOMEM;
2408 rc = selinux_sb_copy_data(data, secdata);
2409 if (rc)
2410 goto out_free_secdata;
2411
2412 rc = selinux_parse_opts_str(secdata, &opts);
2413 if (rc)
2414 goto out_free_secdata;
2415
2416 mount_options = opts.mnt_opts;
2417 flags = opts.mnt_opts_flags;
2418
2419 for (i = 0; i < opts.num_mnt_opts; i++) {
2420 u32 sid;
2421 size_t len;
2422
2423 if (flags[i] == SE_SBLABELSUPP)
2424 continue;
2425 len = strlen(mount_options[i]);
2426 rc = security_context_to_sid(mount_options[i], len, &sid);
2427 if (rc) {
2428 printk(KERN_WARNING "SELinux: security_context_to_sid"
2429 "(%s) failed for (dev %s, type %s) errno=%d\n",
2430 mount_options[i], sb->s_id, sb->s_type->name, rc);
2431 goto out_free_opts;
2432 }
2433 rc = -EINVAL;
2434 switch (flags[i]) {
2435 case FSCONTEXT_MNT:
2436 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2437 goto out_bad_option;
2438 break;
2439 case CONTEXT_MNT:
2440 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2441 goto out_bad_option;
2442 break;
2443 case ROOTCONTEXT_MNT: {
2444 struct inode_security_struct *root_isec;
2445 root_isec = sb->s_root->d_inode->i_security;
2446
2447 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2448 goto out_bad_option;
2449 break;
2450 }
2451 case DEFCONTEXT_MNT:
2452 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2453 goto out_bad_option;
2454 break;
2455 default:
2456 goto out_free_opts;
2457 }
2458 }
2459
2460 rc = 0;
2461out_free_opts:
2462 security_free_mnt_opts(&opts);
2463out_free_secdata:
2464 free_secdata(secdata);
2465 return rc;
2466out_bad_option:
2467 printk(KERN_WARNING "SELinux: unable to change security options "
2468 "during remount (dev %s, type=%s)\n", sb->s_id,
2469 sb->s_type->name);
2470 goto out_free_opts;
2471}
2472
James Morris12204e22008-12-19 10:44:42 +11002473static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474{
David Howells88e67f32008-11-14 10:39:21 +11002475 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002476 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002477 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 int rc;
2479
2480 rc = superblock_doinit(sb, data);
2481 if (rc)
2482 return rc;
2483
James Morris74192242008-12-19 11:41:10 +11002484 /* Allow all mounts performed by the kernel */
2485 if (flags & MS_KERNMOUNT)
2486 return 0;
2487
Eric Parisa2694342011-04-25 13:10:27 -04002488 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002489 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002490 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002491 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492}
2493
David Howells726c3342006-06-23 02:02:58 -07002494static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495{
David Howells88e67f32008-11-14 10:39:21 +11002496 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002497 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002498 struct selinux_audit_data sad = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Eric Parisa2694342011-04-25 13:10:27 -04002500 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002501 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002502 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002503 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504}
2505
Eric Paris828dfe12008-04-17 13:17:49 -04002506static int selinux_mount(char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002507 struct path *path,
Eric Paris828dfe12008-04-17 13:17:49 -04002508 char *type,
2509 unsigned long flags,
2510 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511{
David Howells88e67f32008-11-14 10:39:21 +11002512 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
2514 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002515 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002516 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 else
Eric Paris2875fa02011-04-28 16:04:24 -04002518 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519}
2520
2521static int selinux_umount(struct vfsmount *mnt, int flags)
2522{
David Howells88e67f32008-11-14 10:39:21 +11002523 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524
David Howells88e67f32008-11-14 10:39:21 +11002525 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002526 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527}
2528
2529/* inode security operations */
2530
2531static int selinux_inode_alloc_security(struct inode *inode)
2532{
2533 return inode_alloc_security(inode);
2534}
2535
2536static void selinux_inode_free_security(struct inode *inode)
2537{
2538 inode_free_security(inode);
2539}
2540
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002541static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002542 const struct qstr *qstr, char **name,
2543 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002544{
Paul Moore5fb49872010-04-22 14:46:19 -04002545 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002546 struct inode_security_struct *dsec;
2547 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002548 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002549 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002550 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002551
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002552 dsec = dir->i_security;
2553 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002554
David Howells275bb412008-11-14 10:39:19 +11002555 sid = tsec->sid;
2556 newsid = tsec->create_sid;
2557
Eric Paris415103f2010-12-02 16:13:40 -05002558 if ((sbsec->flags & SE_SBINITIALIZED) &&
2559 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2560 newsid = sbsec->mntpoint_sid;
2561 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002562 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002563 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002564 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002565 if (rc) {
2566 printk(KERN_WARNING "%s: "
2567 "security_transition_sid failed, rc=%d (dev=%s "
2568 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002569 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002570 -rc, inode->i_sb->s_id, inode->i_ino);
2571 return rc;
2572 }
2573 }
2574
Eric Paris296fddf2006-09-25 23:32:00 -07002575 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002576 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002577 struct inode_security_struct *isec = inode->i_security;
2578 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2579 isec->sid = newsid;
2580 isec->initialized = 1;
2581 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002582
David P. Quigleycd895962009-01-16 09:22:04 -05002583 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002584 return -EOPNOTSUPP;
2585
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002586 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002587 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002588 if (!namep)
2589 return -ENOMEM;
2590 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002591 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002592
2593 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002594 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002595 if (rc) {
2596 kfree(namep);
2597 return rc;
2598 }
2599 *value = context;
2600 *len = clen;
2601 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002602
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002603 return 0;
2604}
2605
Al Viro4acdaf22011-07-26 01:42:34 -04002606static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607{
2608 return may_create(dir, dentry, SECCLASS_FILE);
2609}
2610
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2612{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 return may_link(dir, old_dentry, MAY_LINK);
2614}
2615
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2617{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 return may_link(dir, dentry, MAY_UNLINK);
2619}
2620
2621static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2622{
2623 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2624}
2625
Al Viro18bb1db2011-07-26 01:41:39 -04002626static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627{
2628 return may_create(dir, dentry, SECCLASS_DIR);
2629}
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2632{
2633 return may_link(dir, dentry, MAY_RMDIR);
2634}
2635
Al Viro1a67aaf2011-07-26 01:52:52 -04002636static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2639}
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002642 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
2644 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2645}
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647static int selinux_inode_readlink(struct dentry *dentry)
2648{
David Howells88e67f32008-11-14 10:39:21 +11002649 const struct cred *cred = current_cred();
2650
Eric Paris2875fa02011-04-28 16:04:24 -04002651 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652}
2653
2654static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2655{
David Howells88e67f32008-11-14 10:39:21 +11002656 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Eric Paris2875fa02011-04-28 16:04:24 -04002658 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659}
2660
Al Viroe74f71e2011-06-20 19:38:15 -04002661static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
David Howells88e67f32008-11-14 10:39:21 +11002663 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002664 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002665 struct selinux_audit_data sad = {0,};
Eric Parisb782e0a2010-07-23 11:44:03 -04002666 u32 perms;
2667 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002668 unsigned flags = mask & MAY_NOT_BLOCK;
Eric Paris2e334052012-04-04 15:01:42 -04002669 struct inode_security_struct *isec;
2670 u32 sid;
2671 struct av_decision avd;
2672 int rc, rc2;
2673 u32 audited, denied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
Eric Parisb782e0a2010-07-23 11:44:03 -04002675 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002676 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2677
Eric Parisb782e0a2010-07-23 11:44:03 -04002678 /* No permission to check. Existence test. */
2679 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
Eric Paris2e334052012-04-04 15:01:42 -04002682 validate_creds(cred);
2683
2684 if (unlikely(IS_PRIVATE(inode)))
2685 return 0;
2686
2687 perms = file_mask_to_av(inode->i_mode, mask);
2688
2689 sid = cred_sid(cred);
2690 isec = inode->i_security;
2691
2692 rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
2693 audited = avc_audit_required(perms, &avd, rc,
2694 from_access ? FILE__AUDIT_ACCESS : 0,
2695 &denied);
2696 if (likely(!audited))
2697 return rc;
2698
Eric Parisf48b7392011-04-25 12:54:27 -04002699 COMMON_AUDIT_DATA_INIT(&ad, INODE);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002700 ad.selinux_audit_data = &sad;
Eric Parisf48b7392011-04-25 12:54:27 -04002701 ad.u.inode = inode;
Eric Parisb782e0a2010-07-23 11:44:03 -04002702
2703 if (from_access)
Eric Paris3b3b0e42012-04-03 09:37:02 -07002704 ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
Eric Parisb782e0a2010-07-23 11:44:03 -04002705
Eric Paris2e334052012-04-04 15:01:42 -04002706 rc2 = slow_avc_audit(sid, isec->sid, isec->sclass, perms,
2707 audited, denied, &ad, flags);
2708 if (rc2)
2709 return rc2;
2710 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711}
2712
2713static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2714{
David Howells88e67f32008-11-14 10:39:21 +11002715 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002716 unsigned int ia_valid = iattr->ia_valid;
Eric Paris95dbf732012-04-04 13:45:34 -04002717 __u32 av = FILE__WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002719 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2720 if (ia_valid & ATTR_FORCE) {
2721 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2722 ATTR_FORCE);
2723 if (!ia_valid)
2724 return 0;
2725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002727 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2728 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002729 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
Eric Paris95dbf732012-04-04 13:45:34 -04002731 if (ia_valid & ATTR_SIZE)
2732 av |= FILE__OPEN;
2733
2734 return dentry_has_perm(cred, dentry, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735}
2736
2737static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2738{
David Howells88e67f32008-11-14 10:39:21 +11002739 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002740 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002741
Eric Paris2875fa02011-04-28 16:04:24 -04002742 path.dentry = dentry;
2743 path.mnt = mnt;
2744
2745 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746}
2747
David Howells8f0cfa52008-04-29 00:59:41 -07002748static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002749{
David Howells88e67f32008-11-14 10:39:21 +11002750 const struct cred *cred = current_cred();
2751
Serge E. Hallynb5376772007-10-16 23:31:36 -07002752 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2753 sizeof XATTR_SECURITY_PREFIX - 1)) {
2754 if (!strcmp(name, XATTR_NAME_CAPS)) {
2755 if (!capable(CAP_SETFCAP))
2756 return -EPERM;
2757 } else if (!capable(CAP_SYS_ADMIN)) {
2758 /* A different attribute in the security namespace.
2759 Restrict to administrator. */
2760 return -EPERM;
2761 }
2762 }
2763
2764 /* Not an attribute we recognize, so just check the
2765 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002766 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002767}
2768
David Howells8f0cfa52008-04-29 00:59:41 -07002769static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2770 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 struct inode *inode = dentry->d_inode;
2773 struct inode_security_struct *isec = inode->i_security;
2774 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002775 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07002776 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11002777 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 int rc = 0;
2779
Serge E. Hallynb5376772007-10-16 23:31:36 -07002780 if (strcmp(name, XATTR_NAME_SELINUX))
2781 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
2783 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002784 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return -EOPNOTSUPP;
2786
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002787 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 return -EPERM;
2789
Eric Parisa2694342011-04-25 13:10:27 -04002790 COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
Eric Paris3b3b0e42012-04-03 09:37:02 -07002791 ad.selinux_audit_data = &sad;
Eric Parisa2694342011-04-25 13:10:27 -04002792 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
David Howells275bb412008-11-14 10:39:19 +11002794 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 FILE__RELABELFROM, &ad);
2796 if (rc)
2797 return rc;
2798
2799 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002800 if (rc == -EINVAL) {
Eric Parisd6ea83e2012-04-04 13:45:49 -04002801 if (!capable(CAP_MAC_ADMIN)) {
2802 struct audit_buffer *ab;
2803 size_t audit_size;
2804 const char *str;
2805
2806 /* We strip a nul only if it is at the end, otherwise the
2807 * context contains a nul and we should audit that */
2808 str = value;
2809 if (str[size - 1] == '\0')
2810 audit_size = size - 1;
2811 else
2812 audit_size = size;
2813 ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
2814 audit_log_format(ab, "op=setxattr invalid_context=");
2815 audit_log_n_untrustedstring(ab, value, audit_size);
2816 audit_log_end(ab);
2817
Stephen Smalley12b29f32008-05-07 13:03:20 -04002818 return rc;
Eric Parisd6ea83e2012-04-04 13:45:49 -04002819 }
Stephen Smalley12b29f32008-05-07 13:03:20 -04002820 rc = security_context_to_sid_force(value, size, &newsid);
2821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 if (rc)
2823 return rc;
2824
David Howells275bb412008-11-14 10:39:19 +11002825 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 FILE__RELABELTO, &ad);
2827 if (rc)
2828 return rc;
2829
David Howells275bb412008-11-14 10:39:19 +11002830 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002831 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (rc)
2833 return rc;
2834
2835 return avc_has_perm(newsid,
2836 sbsec->sid,
2837 SECCLASS_FILESYSTEM,
2838 FILESYSTEM__ASSOCIATE,
2839 &ad);
2840}
2841
David Howells8f0cfa52008-04-29 00:59:41 -07002842static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002843 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002844 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845{
2846 struct inode *inode = dentry->d_inode;
2847 struct inode_security_struct *isec = inode->i_security;
2848 u32 newsid;
2849 int rc;
2850
2851 if (strcmp(name, XATTR_NAME_SELINUX)) {
2852 /* Not an attribute we recognize, so nothing to do. */
2853 return;
2854 }
2855
Stephen Smalley12b29f32008-05-07 13:03:20 -04002856 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002858 printk(KERN_ERR "SELinux: unable to map context to SID"
2859 "for (%s, %lu), rc=%d\n",
2860 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 return;
2862 }
2863
2864 isec->sid = newsid;
2865 return;
2866}
2867
David Howells8f0cfa52008-04-29 00:59:41 -07002868static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869{
David Howells88e67f32008-11-14 10:39:21 +11002870 const struct cred *cred = current_cred();
2871
Eric Paris2875fa02011-04-28 16:04:24 -04002872 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873}
2874
Eric Paris828dfe12008-04-17 13:17:49 -04002875static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876{
David Howells88e67f32008-11-14 10:39:21 +11002877 const struct cred *cred = current_cred();
2878
Eric Paris2875fa02011-04-28 16:04:24 -04002879 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880}
2881
David Howells8f0cfa52008-04-29 00:59:41 -07002882static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002884 if (strcmp(name, XATTR_NAME_SELINUX))
2885 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 /* No one is allowed to remove a SELinux security label.
2888 You can change the label, but all data must be labeled. */
2889 return -EACCES;
2890}
2891
James Morrisd381d8a2005-10-30 14:59:22 -08002892/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002893 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002894 *
2895 * Permission check is handled by selinux_inode_getxattr hook.
2896 */
David P. Quigley42492592008-02-04 22:29:39 -08002897static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898{
David P. Quigley42492592008-02-04 22:29:39 -08002899 u32 size;
2900 int error;
2901 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002904 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2905 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002907 /*
2908 * If the caller has CAP_MAC_ADMIN, then get the raw context
2909 * value even if it is not defined by current policy; otherwise,
2910 * use the in-core value under current policy.
2911 * Use the non-auditing forms of the permission checks since
2912 * getxattr may be called by unprivileged processes commonly
2913 * and lack of permission just means that we fall back to the
2914 * in-core context value, not a denial.
2915 */
Eric Paris6a9de492012-01-03 12:25:14 -05002916 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002917 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002918 if (!error)
2919 error = security_sid_to_context_force(isec->sid, &context,
2920 &size);
2921 else
2922 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002923 if (error)
2924 return error;
2925 error = size;
2926 if (alloc) {
2927 *buffer = context;
2928 goto out_nofree;
2929 }
2930 kfree(context);
2931out_nofree:
2932 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933}
2934
2935static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002936 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937{
2938 struct inode_security_struct *isec = inode->i_security;
2939 u32 newsid;
2940 int rc;
2941
2942 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2943 return -EOPNOTSUPP;
2944
2945 if (!value || !size)
2946 return -EACCES;
2947
Eric Paris828dfe12008-04-17 13:17:49 -04002948 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 if (rc)
2950 return rc;
2951
2952 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002953 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 return 0;
2955}
2956
2957static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2958{
2959 const int len = sizeof(XATTR_NAME_SELINUX);
2960 if (buffer && len <= buffer_size)
2961 memcpy(buffer, XATTR_NAME_SELINUX, len);
2962 return len;
2963}
2964
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02002965static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2966{
2967 struct inode_security_struct *isec = inode->i_security;
2968 *secid = isec->sid;
2969}
2970
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971/* file security operations */
2972
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002973static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974{
David Howells88e67f32008-11-14 10:39:21 +11002975 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002976 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2979 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2980 mask |= MAY_APPEND;
2981
Paul Moore389fb8002009-03-27 17:10:34 -04002982 return file_has_perm(cred, file,
2983 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984}
2985
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002986static int selinux_file_permission(struct file *file, int mask)
2987{
Stephen Smalley20dda182009-06-22 14:54:53 -04002988 struct inode *inode = file->f_path.dentry->d_inode;
2989 struct file_security_struct *fsec = file->f_security;
2990 struct inode_security_struct *isec = inode->i_security;
2991 u32 sid = current_sid();
2992
Paul Moore389fb8002009-03-27 17:10:34 -04002993 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002994 /* No permission to check. Existence test. */
2995 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002996
Stephen Smalley20dda182009-06-22 14:54:53 -04002997 if (sid == fsec->sid && fsec->isid == isec->sid &&
2998 fsec->pseqno == avc_policy_seqno())
Eric Paris83d49852012-04-04 13:45:40 -04002999 /* No change since file_open check. */
Stephen Smalley20dda182009-06-22 14:54:53 -04003000 return 0;
3001
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003002 return selinux_revalidate_file_permission(file, mask);
3003}
3004
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005static int selinux_file_alloc_security(struct file *file)
3006{
3007 return file_alloc_security(file);
3008}
3009
3010static void selinux_file_free_security(struct file *file)
3011{
3012 file_free_security(file);
3013}
3014
3015static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3016 unsigned long arg)
3017{
David Howells88e67f32008-11-14 10:39:21 +11003018 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05003019 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Eric Paris0b24dcb2011-02-25 15:39:20 -05003021 switch (cmd) {
3022 case FIONREAD:
3023 /* fall through */
3024 case FIBMAP:
3025 /* fall through */
3026 case FIGETBSZ:
3027 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003028 case FS_IOC_GETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003029 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003030 case FS_IOC_GETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003031 error = file_has_perm(cred, file, FILE__GETATTR);
3032 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
Al Viro2f99c362012-03-23 16:04:05 -04003034 case FS_IOC_SETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003035 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04003036 case FS_IOC_SETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05003037 error = file_has_perm(cred, file, FILE__SETATTR);
3038 break;
3039
3040 /* sys_ioctl() checks */
3041 case FIONBIO:
3042 /* fall through */
3043 case FIOASYNC:
3044 error = file_has_perm(cred, file, 0);
3045 break;
3046
3047 case KDSKBENT:
3048 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05003049 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3050 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003051 break;
3052
3053 /* default case assumes that the command will go
3054 * to the file's ioctl() function.
3055 */
3056 default:
3057 error = file_has_perm(cred, file, FILE__IOCTL);
3058 }
3059 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060}
3061
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003062static int default_noexec;
3063
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3065{
David Howells88e67f32008-11-14 10:39:21 +11003066 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003067 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003068
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003069 if (default_noexec &&
3070 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 /*
3072 * We are making executable an anonymous mapping or a
3073 * private file mapping that will also be writable.
3074 * This has an additional check.
3075 */
David Howellsd84f4f92008-11-14 10:39:23 +11003076 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003078 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
3081 if (file) {
3082 /* read access is always possible with a mapping */
3083 u32 av = FILE__READ;
3084
3085 /* write access only matters if the mapping is shared */
3086 if (shared && (prot & PROT_WRITE))
3087 av |= FILE__WRITE;
3088
3089 if (prot & PROT_EXEC)
3090 av |= FILE__EXECUTE;
3091
David Howells88e67f32008-11-14 10:39:21 +11003092 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 }
David Howellsd84f4f92008-11-14 10:39:23 +11003094
3095error:
3096 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097}
3098
3099static int selinux_file_mmap(struct file *file, unsigned long reqprot,
Eric Parised032182007-06-28 15:55:21 -04003100 unsigned long prot, unsigned long flags,
3101 unsigned long addr, unsigned long addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102{
Eric Parised032182007-06-28 15:55:21 -04003103 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003104 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Eric Paris84336d1a2009-07-31 12:54:05 -04003106 /*
3107 * notice that we are intentionally putting the SELinux check before
3108 * the secondary cap_file_mmap check. This is such a likely attempt
3109 * at bad behaviour/exploit that we always want to get the AVC, even
3110 * if DAC would have also denied the operation.
3111 */
Eric Parisa2551df2009-07-31 12:54:11 -04003112 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003113 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3114 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003115 if (rc)
3116 return rc;
3117 }
3118
3119 /* do DAC check on address space usage */
3120 rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
Eric Parised032182007-06-28 15:55:21 -04003121 if (rc || addr_only)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 return rc;
3123
3124 if (selinux_checkreqprot)
3125 prot = reqprot;
3126
3127 return file_map_prot_check(file, prot,
3128 (flags & MAP_TYPE) == MAP_SHARED);
3129}
3130
3131static int selinux_file_mprotect(struct vm_area_struct *vma,
3132 unsigned long reqprot,
3133 unsigned long prot)
3134{
David Howells88e67f32008-11-14 10:39:21 +11003135 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136
3137 if (selinux_checkreqprot)
3138 prot = reqprot;
3139
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003140 if (default_noexec &&
3141 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003142 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003143 if (vma->vm_start >= vma->vm_mm->start_brk &&
3144 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003145 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003146 } else if (!vma->vm_file &&
3147 vma->vm_start <= vma->vm_mm->start_stack &&
3148 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003149 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003150 } else if (vma->vm_file && vma->anon_vma) {
3151 /*
3152 * We are making executable a file mapping that has
3153 * had some COW done. Since pages might have been
3154 * written, check ability to execute the possibly
3155 * modified content. This typically should only
3156 * occur for text relocations.
3157 */
David Howellsd84f4f92008-11-14 10:39:23 +11003158 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003159 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003160 if (rc)
3161 return rc;
3162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
3164 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3165}
3166
3167static int selinux_file_lock(struct file *file, unsigned int cmd)
3168{
David Howells88e67f32008-11-14 10:39:21 +11003169 const struct cred *cred = current_cred();
3170
3171 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172}
3173
3174static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3175 unsigned long arg)
3176{
David Howells88e67f32008-11-14 10:39:21 +11003177 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 int err = 0;
3179
3180 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003181 case F_SETFL:
3182 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3183 err = -EINVAL;
3184 break;
3185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Eric Paris828dfe12008-04-17 13:17:49 -04003187 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003188 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003190 }
3191 /* fall through */
3192 case F_SETOWN:
3193 case F_SETSIG:
3194 case F_GETFL:
3195 case F_GETOWN:
3196 case F_GETSIG:
3197 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003198 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003199 break;
3200 case F_GETLK:
3201 case F_SETLK:
3202 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003204 case F_GETLK64:
3205 case F_SETLK64:
3206 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003208 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3209 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003211 }
David Howells88e67f32008-11-14 10:39:21 +11003212 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003213 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 }
3215
3216 return err;
3217}
3218
3219static int selinux_file_set_fowner(struct file *file)
3220{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 struct file_security_struct *fsec;
3222
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003224 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225
3226 return 0;
3227}
3228
3229static int selinux_file_send_sigiotask(struct task_struct *tsk,
3230 struct fown_struct *fown, int signum)
3231{
Eric Paris828dfe12008-04-17 13:17:49 -04003232 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003233 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 struct file_security_struct *fsec;
3236
3237 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003238 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 fsec = file->f_security;
3241
3242 if (!signum)
3243 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3244 else
3245 perm = signal_to_av(signum);
3246
David Howells275bb412008-11-14 10:39:19 +11003247 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 SECCLASS_PROCESS, perm, NULL);
3249}
3250
3251static int selinux_file_receive(struct file *file)
3252{
David Howells88e67f32008-11-14 10:39:21 +11003253 const struct cred *cred = current_cred();
3254
3255 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256}
3257
Eric Paris83d49852012-04-04 13:45:40 -04003258static int selinux_file_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003259{
3260 struct file_security_struct *fsec;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003261 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003262
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003263 fsec = file->f_security;
Eric Paris602a8dd2012-04-04 15:01:42 -04003264 isec = file->f_path.dentry->d_inode->i_security;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003265 /*
3266 * Save inode label and policy sequence number
3267 * at open-time so that selinux_file_permission
3268 * can determine whether revalidation is necessary.
3269 * Task label is already saved in the file security
3270 * struct as its SID.
3271 */
3272 fsec->isid = isec->sid;
3273 fsec->pseqno = avc_policy_seqno();
3274 /*
3275 * Since the inode label or policy seqno may have changed
3276 * between the selinux_inode_permission check and the saving
3277 * of state above, recheck that access is still permitted.
3278 * Otherwise, access might never be revalidated against the
3279 * new inode label or new policy.
3280 * This check is not redundant - do not remove.
3281 */
Eric Paris602a8dd2012-04-04 15:01:42 -04003282 return path_has_perm(cred, &file->f_path, open_file_to_av(file));
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003283}
3284
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285/* task security operations */
3286
3287static int selinux_task_create(unsigned long clone_flags)
3288{
David Howells3b11a1d2008-11-14 10:39:26 +11003289 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290}
3291
David Howellsf1752ee2008-11-14 10:39:17 +11003292/*
David Howellsee18d642009-09-02 09:14:21 +01003293 * allocate the SELinux part of blank credentials
3294 */
3295static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3296{
3297 struct task_security_struct *tsec;
3298
3299 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3300 if (!tsec)
3301 return -ENOMEM;
3302
3303 cred->security = tsec;
3304 return 0;
3305}
3306
3307/*
David Howellsf1752ee2008-11-14 10:39:17 +11003308 * detach and free the LSM part of a set of credentials
3309 */
3310static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311{
David Howellsf1752ee2008-11-14 10:39:17 +11003312 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003313
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003314 /*
3315 * cred->security == NULL if security_cred_alloc_blank() or
3316 * security_prepare_creds() returned an error.
3317 */
3318 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003319 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003320 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321}
3322
David Howellsd84f4f92008-11-14 10:39:23 +11003323/*
3324 * prepare a new set of credentials for modification
3325 */
3326static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3327 gfp_t gfp)
3328{
3329 const struct task_security_struct *old_tsec;
3330 struct task_security_struct *tsec;
3331
3332 old_tsec = old->security;
3333
3334 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3335 if (!tsec)
3336 return -ENOMEM;
3337
3338 new->security = tsec;
3339 return 0;
3340}
3341
3342/*
David Howellsee18d642009-09-02 09:14:21 +01003343 * transfer the SELinux data to a blank set of creds
3344 */
3345static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3346{
3347 const struct task_security_struct *old_tsec = old->security;
3348 struct task_security_struct *tsec = new->security;
3349
3350 *tsec = *old_tsec;
3351}
3352
3353/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003354 * set the security data for a kernel service
3355 * - all the creation contexts are set to unlabelled
3356 */
3357static int selinux_kernel_act_as(struct cred *new, u32 secid)
3358{
3359 struct task_security_struct *tsec = new->security;
3360 u32 sid = current_sid();
3361 int ret;
3362
3363 ret = avc_has_perm(sid, secid,
3364 SECCLASS_KERNEL_SERVICE,
3365 KERNEL_SERVICE__USE_AS_OVERRIDE,
3366 NULL);
3367 if (ret == 0) {
3368 tsec->sid = secid;
3369 tsec->create_sid = 0;
3370 tsec->keycreate_sid = 0;
3371 tsec->sockcreate_sid = 0;
3372 }
3373 return ret;
3374}
3375
3376/*
3377 * set the file creation context in a security record to the same as the
3378 * objective context of the specified inode
3379 */
3380static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3381{
3382 struct inode_security_struct *isec = inode->i_security;
3383 struct task_security_struct *tsec = new->security;
3384 u32 sid = current_sid();
3385 int ret;
3386
3387 ret = avc_has_perm(sid, isec->sid,
3388 SECCLASS_KERNEL_SERVICE,
3389 KERNEL_SERVICE__CREATE_FILES_AS,
3390 NULL);
3391
3392 if (ret == 0)
3393 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003394 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003395}
3396
Eric Parisdd8dbf22009-11-03 16:35:32 +11003397static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003398{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003399 u32 sid;
3400 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003401 struct selinux_audit_data sad = {0,};
Eric Parisdd8dbf22009-11-03 16:35:32 +11003402
3403 sid = task_sid(current);
3404
3405 COMMON_AUDIT_DATA_INIT(&ad, KMOD);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003406 ad.selinux_audit_data = &sad;
Eric Parisdd8dbf22009-11-03 16:35:32 +11003407 ad.u.kmod_name = kmod_name;
3408
3409 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3410 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003411}
3412
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3414{
David Howells3b11a1d2008-11-14 10:39:26 +11003415 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416}
3417
3418static int selinux_task_getpgid(struct task_struct *p)
3419{
David Howells3b11a1d2008-11-14 10:39:26 +11003420 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421}
3422
3423static int selinux_task_getsid(struct task_struct *p)
3424{
David Howells3b11a1d2008-11-14 10:39:26 +11003425 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426}
3427
David Quigleyf9008e42006-06-30 01:55:46 -07003428static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3429{
David Howells275bb412008-11-14 10:39:19 +11003430 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003431}
3432
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433static int selinux_task_setnice(struct task_struct *p, int nice)
3434{
3435 int rc;
3436
Eric Paris200ac532009-02-12 15:01:04 -05003437 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 if (rc)
3439 return rc;
3440
David Howells3b11a1d2008-11-14 10:39:26 +11003441 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442}
3443
James Morris03e68062006-06-23 02:03:58 -07003444static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3445{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003446 int rc;
3447
Eric Paris200ac532009-02-12 15:01:04 -05003448 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003449 if (rc)
3450 return rc;
3451
David Howells3b11a1d2008-11-14 10:39:26 +11003452 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003453}
3454
David Quigleya1836a42006-06-30 01:55:49 -07003455static int selinux_task_getioprio(struct task_struct *p)
3456{
David Howells3b11a1d2008-11-14 10:39:26 +11003457 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003458}
3459
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003460static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3461 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003463 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
3465 /* Control the ability to change the hard limit (whether
3466 lowering or raising it), so that the hard limit can
3467 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003468 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003470 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
3472 return 0;
3473}
3474
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003475static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003477 int rc;
3478
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003479 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003480 if (rc)
3481 return rc;
3482
David Howells3b11a1d2008-11-14 10:39:26 +11003483 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484}
3485
3486static int selinux_task_getscheduler(struct task_struct *p)
3487{
David Howells3b11a1d2008-11-14 10:39:26 +11003488 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489}
3490
David Quigley35601542006-06-23 02:04:01 -07003491static int selinux_task_movememory(struct task_struct *p)
3492{
David Howells3b11a1d2008-11-14 10:39:26 +11003493 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003494}
3495
David Quigleyf9008e42006-06-30 01:55:46 -07003496static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3497 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498{
3499 u32 perm;
3500 int rc;
3501
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 if (!sig)
3503 perm = PROCESS__SIGNULL; /* null signal; existence test */
3504 else
3505 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003506 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003507 rc = avc_has_perm(secid, task_sid(p),
3508 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003509 else
David Howells3b11a1d2008-11-14 10:39:26 +11003510 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003511 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512}
3513
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514static int selinux_task_wait(struct task_struct *p)
3515{
Eric Paris8a535142007-10-22 16:10:31 -04003516 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517}
3518
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519static void selinux_task_to_inode(struct task_struct *p,
3520 struct inode *inode)
3521{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003523 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
David Howells275bb412008-11-14 10:39:19 +11003525 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527}
3528
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003530static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003531 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532{
3533 int offset, ihlen, ret = -EINVAL;
3534 struct iphdr _iph, *ih;
3535
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003536 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3538 if (ih == NULL)
3539 goto out;
3540
3541 ihlen = ih->ihl * 4;
3542 if (ihlen < sizeof(_iph))
3543 goto out;
3544
Eric Paris48c62af2012-04-02 13:15:44 -04003545 ad->u.net->v4info.saddr = ih->saddr;
3546 ad->u.net->v4info.daddr = ih->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 ret = 0;
3548
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003549 if (proto)
3550 *proto = ih->protocol;
3551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003553 case IPPROTO_TCP: {
3554 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
Eric Paris828dfe12008-04-17 13:17:49 -04003556 if (ntohs(ih->frag_off) & IP_OFFSET)
3557 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559 offset += ihlen;
3560 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3561 if (th == NULL)
3562 break;
3563
Eric Paris48c62af2012-04-02 13:15:44 -04003564 ad->u.net->sport = th->source;
3565 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
Eric Paris828dfe12008-04-17 13:17:49 -04003569 case IPPROTO_UDP: {
3570 struct udphdr _udph, *uh;
3571
3572 if (ntohs(ih->frag_off) & IP_OFFSET)
3573 break;
3574
3575 offset += ihlen;
3576 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3577 if (uh == NULL)
3578 break;
3579
Eric Paris48c62af2012-04-02 13:15:44 -04003580 ad->u.net->sport = uh->source;
3581 ad->u.net->dport = uh->dest;
Eric Paris828dfe12008-04-17 13:17:49 -04003582 break;
3583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
James Morris2ee92d42006-11-13 16:09:01 -08003585 case IPPROTO_DCCP: {
3586 struct dccp_hdr _dccph, *dh;
3587
3588 if (ntohs(ih->frag_off) & IP_OFFSET)
3589 break;
3590
3591 offset += ihlen;
3592 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3593 if (dh == NULL)
3594 break;
3595
Eric Paris48c62af2012-04-02 13:15:44 -04003596 ad->u.net->sport = dh->dccph_sport;
3597 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003598 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003599 }
James Morris2ee92d42006-11-13 16:09:01 -08003600
Eric Paris828dfe12008-04-17 13:17:49 -04003601 default:
3602 break;
3603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604out:
3605 return ret;
3606}
3607
3608#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3609
3610/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003611static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003612 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613{
3614 u8 nexthdr;
3615 int ret = -EINVAL, offset;
3616 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003617 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003619 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3621 if (ip6 == NULL)
3622 goto out;
3623
Eric Paris48c62af2012-04-02 13:15:44 -04003624 ad->u.net->v6info.saddr = ip6->saddr;
3625 ad->u.net->v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 ret = 0;
3627
3628 nexthdr = ip6->nexthdr;
3629 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003630 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 if (offset < 0)
3632 goto out;
3633
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003634 if (proto)
3635 *proto = nexthdr;
3636
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 switch (nexthdr) {
3638 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003639 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640
3641 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3642 if (th == NULL)
3643 break;
3644
Eric Paris48c62af2012-04-02 13:15:44 -04003645 ad->u.net->sport = th->source;
3646 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 break;
3648 }
3649
3650 case IPPROTO_UDP: {
3651 struct udphdr _udph, *uh;
3652
3653 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3654 if (uh == NULL)
3655 break;
3656
Eric Paris48c62af2012-04-02 13:15:44 -04003657 ad->u.net->sport = uh->source;
3658 ad->u.net->dport = uh->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 break;
3660 }
3661
James Morris2ee92d42006-11-13 16:09:01 -08003662 case IPPROTO_DCCP: {
3663 struct dccp_hdr _dccph, *dh;
3664
3665 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3666 if (dh == NULL)
3667 break;
3668
Eric Paris48c62af2012-04-02 13:15:44 -04003669 ad->u.net->sport = dh->dccph_sport;
3670 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003671 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003672 }
James Morris2ee92d42006-11-13 16:09:01 -08003673
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 /* includes fragments */
3675 default:
3676 break;
3677 }
3678out:
3679 return ret;
3680}
3681
3682#endif /* IPV6 */
3683
Thomas Liu2bf49692009-07-14 12:14:09 -04003684static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003685 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686{
David Howellscf9481e2008-07-27 21:31:07 +10003687 char *addrp;
3688 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689
Eric Paris48c62af2012-04-02 13:15:44 -04003690 switch (ad->u.net->family) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003692 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003693 if (ret)
3694 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003695 addrp = (char *)(src ? &ad->u.net->v4info.saddr :
3696 &ad->u.net->v4info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003697 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698
3699#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3700 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003701 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003702 if (ret)
3703 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003704 addrp = (char *)(src ? &ad->u.net->v6info.saddr :
3705 &ad->u.net->v6info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003706 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707#endif /* IPV6 */
3708 default:
David Howellscf9481e2008-07-27 21:31:07 +10003709 addrp = NULL;
3710 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 }
3712
David Howellscf9481e2008-07-27 21:31:07 +10003713parse_error:
3714 printk(KERN_WARNING
3715 "SELinux: failure in selinux_parse_skb(),"
3716 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003718
3719okay:
3720 if (_addrp)
3721 *_addrp = addrp;
3722 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723}
3724
Paul Moore4f6a9932007-03-01 14:35:22 -05003725/**
Paul Moore220deb92008-01-29 08:38:23 -05003726 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003727 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003728 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003729 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003730 *
3731 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003732 * Check the various different forms of network peer labeling and determine
3733 * the peer label/SID for the packet; most of the magic actually occurs in
3734 * the security server function security_net_peersid_cmp(). The function
3735 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3736 * or -EACCES if @sid is invalid due to inconsistencies with the different
3737 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003738 *
3739 */
Paul Moore220deb92008-01-29 08:38:23 -05003740static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003741{
Paul Moore71f1cb02008-01-29 08:51:16 -05003742 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003743 u32 xfrm_sid;
3744 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003745 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003746
3747 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003748 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003749
Paul Moore71f1cb02008-01-29 08:51:16 -05003750 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3751 if (unlikely(err)) {
3752 printk(KERN_WARNING
3753 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3754 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003755 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003756 }
Paul Moore220deb92008-01-29 08:38:23 -05003757
3758 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003759}
3760
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003762
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003763static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3764 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003765{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003766 if (tsec->sockcreate_sid > SECSID_NULL) {
3767 *socksid = tsec->sockcreate_sid;
3768 return 0;
3769 }
3770
3771 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3772 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003773}
3774
Paul Moore253bfae2010-04-22 14:46:19 -04003775static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776{
Paul Moore253bfae2010-04-22 14:46:19 -04003777 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003778 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003779 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003780 struct lsm_network_audit net = {0,};
Paul Moore253bfae2010-04-22 14:46:19 -04003781 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Paul Moore253bfae2010-04-22 14:46:19 -04003783 if (sksec->sid == SECINITSID_KERNEL)
3784 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
Thomas Liu2bf49692009-07-14 12:14:09 -04003786 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003787 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003788 ad.u.net = &net;
3789 ad.u.net->sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
Paul Moore253bfae2010-04-22 14:46:19 -04003791 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792}
3793
3794static int selinux_socket_create(int family, int type,
3795 int protocol, int kern)
3796{
Paul Moore5fb49872010-04-22 14:46:19 -04003797 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003798 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003799 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003800 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801
3802 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003803 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
David Howells275bb412008-11-14 10:39:19 +11003805 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003806 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3807 if (rc)
3808 return rc;
3809
Paul Moored4f2d972010-04-22 14:46:18 -04003810 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811}
3812
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003813static int selinux_socket_post_create(struct socket *sock, int family,
3814 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815{
Paul Moore5fb49872010-04-22 14:46:19 -04003816 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003817 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003818 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003819 int err = 0;
3820
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003821 isec->sclass = socket_type_to_security_class(family, type, protocol);
3822
David Howells275bb412008-11-14 10:39:19 +11003823 if (kern)
3824 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003825 else {
3826 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3827 if (err)
3828 return err;
3829 }
David Howells275bb412008-11-14 10:39:19 +11003830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 isec->initialized = 1;
3832
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003833 if (sock->sk) {
3834 sksec = sock->sk->sk_security;
3835 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003836 sksec->sclass = isec->sclass;
Paul Moore389fb8002009-03-27 17:10:34 -04003837 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003838 }
3839
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003840 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841}
3842
3843/* Range of port numbers used to automatically bind.
3844 Need to determine whether we should perform a name_bind
3845 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
3847static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3848{
Paul Moore253bfae2010-04-22 14:46:19 -04003849 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 u16 family;
3851 int err;
3852
Paul Moore253bfae2010-04-22 14:46:19 -04003853 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 if (err)
3855 goto out;
3856
3857 /*
3858 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003859 * Multiple address binding for SCTP is not supported yet: we just
3860 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 */
Paul Moore253bfae2010-04-22 14:46:19 -04003862 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 if (family == PF_INET || family == PF_INET6) {
3864 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003865 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003866 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003867 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003868 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 struct sockaddr_in *addr4 = NULL;
3870 struct sockaddr_in6 *addr6 = NULL;
3871 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003872 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 if (family == PF_INET) {
3875 addr4 = (struct sockaddr_in *)address;
3876 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 addrp = (char *)&addr4->sin_addr.s_addr;
3878 } else {
3879 addr6 = (struct sockaddr_in6 *)address;
3880 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 addrp = (char *)&addr6->sin6_addr.s6_addr;
3882 }
3883
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003884 if (snum) {
3885 int low, high;
3886
3887 inet_get_local_port_range(&low, &high);
3888
3889 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003890 err = sel_netport_sid(sk->sk_protocol,
3891 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003892 if (err)
3893 goto out;
Thomas Liu2bf49692009-07-14 12:14:09 -04003894 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003895 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003896 ad.u.net = &net;
3897 ad.u.net->sport = htons(snum);
3898 ad.u.net->family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003899 err = avc_has_perm(sksec->sid, sid,
3900 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003901 SOCKET__NAME_BIND, &ad);
3902 if (err)
3903 goto out;
3904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 }
Eric Paris828dfe12008-04-17 13:17:49 -04003906
Paul Moore253bfae2010-04-22 14:46:19 -04003907 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003908 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 node_perm = TCP_SOCKET__NODE_BIND;
3910 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003911
James Morris13402582005-09-30 14:24:34 -04003912 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 node_perm = UDP_SOCKET__NODE_BIND;
3914 break;
James Morris2ee92d42006-11-13 16:09:01 -08003915
3916 case SECCLASS_DCCP_SOCKET:
3917 node_perm = DCCP_SOCKET__NODE_BIND;
3918 break;
3919
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 default:
3921 node_perm = RAWIP_SOCKET__NODE_BIND;
3922 break;
3923 }
Eric Paris828dfe12008-04-17 13:17:49 -04003924
Paul Moore224dfbd2008-01-29 08:38:13 -05003925 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 if (err)
3927 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003928
Thomas Liu2bf49692009-07-14 12:14:09 -04003929 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003930 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003931 ad.u.net = &net;
3932 ad.u.net->sport = htons(snum);
3933 ad.u.net->family = family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
3935 if (family == PF_INET)
Eric Paris48c62af2012-04-02 13:15:44 -04003936 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 else
Eric Paris48c62af2012-04-02 13:15:44 -04003938 ad.u.net->v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939
Paul Moore253bfae2010-04-22 14:46:19 -04003940 err = avc_has_perm(sksec->sid, sid,
3941 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 if (err)
3943 goto out;
3944 }
3945out:
3946 return err;
3947}
3948
3949static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3950{
Paul Moore014ab192008-10-10 10:16:33 -04003951 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003952 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 int err;
3954
Paul Moore253bfae2010-04-22 14:46:19 -04003955 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 if (err)
3957 return err;
3958
3959 /*
James Morris2ee92d42006-11-13 16:09:01 -08003960 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 */
Paul Moore253bfae2010-04-22 14:46:19 -04003962 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
3963 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003964 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07003965 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04003966 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 struct sockaddr_in *addr4 = NULL;
3968 struct sockaddr_in6 *addr6 = NULL;
3969 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003970 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971
3972 if (sk->sk_family == PF_INET) {
3973 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003974 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 return -EINVAL;
3976 snum = ntohs(addr4->sin_port);
3977 } else {
3978 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003979 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 return -EINVAL;
3981 snum = ntohs(addr6->sin6_port);
3982 }
3983
Paul Moore3e112172008-04-10 10:48:14 -04003984 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 if (err)
3986 goto out;
3987
Paul Moore253bfae2010-04-22 14:46:19 -04003988 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08003989 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3990
Thomas Liu2bf49692009-07-14 12:14:09 -04003991 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07003992 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04003993 ad.u.net = &net;
3994 ad.u.net->dport = htons(snum);
3995 ad.u.net->family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04003996 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 if (err)
3998 goto out;
3999 }
4000
Paul Moore014ab192008-10-10 10:16:33 -04004001 err = selinux_netlbl_socket_connect(sk, address);
4002
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003out:
4004 return err;
4005}
4006
4007static int selinux_socket_listen(struct socket *sock, int backlog)
4008{
Paul Moore253bfae2010-04-22 14:46:19 -04004009 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010}
4011
4012static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
4013{
4014 int err;
4015 struct inode_security_struct *isec;
4016 struct inode_security_struct *newisec;
4017
Paul Moore253bfae2010-04-22 14:46:19 -04004018 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 if (err)
4020 return err;
4021
4022 newisec = SOCK_INODE(newsock)->i_security;
4023
4024 isec = SOCK_INODE(sock)->i_security;
4025 newisec->sclass = isec->sclass;
4026 newisec->sid = isec->sid;
4027 newisec->initialized = 1;
4028
4029 return 0;
4030}
4031
4032static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04004033 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034{
Paul Moore253bfae2010-04-22 14:46:19 -04004035 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036}
4037
4038static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
4039 int size, int flags)
4040{
Paul Moore253bfae2010-04-22 14:46:19 -04004041 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042}
4043
4044static int selinux_socket_getsockname(struct socket *sock)
4045{
Paul Moore253bfae2010-04-22 14:46:19 -04004046 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047}
4048
4049static int selinux_socket_getpeername(struct socket *sock)
4050{
Paul Moore253bfae2010-04-22 14:46:19 -04004051 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052}
4053
Eric Paris828dfe12008-04-17 13:17:49 -04004054static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055{
Paul Mooref8687af2006-10-30 15:22:15 -08004056 int err;
4057
Paul Moore253bfae2010-04-22 14:46:19 -04004058 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08004059 if (err)
4060 return err;
4061
4062 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063}
4064
4065static int selinux_socket_getsockopt(struct socket *sock, int level,
4066 int optname)
4067{
Paul Moore253bfae2010-04-22 14:46:19 -04004068 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069}
4070
4071static int selinux_socket_shutdown(struct socket *sock, int how)
4072{
Paul Moore253bfae2010-04-22 14:46:19 -04004073 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074}
4075
David S. Miller3610cda2011-01-05 15:38:53 -08004076static int selinux_socket_unix_stream_connect(struct sock *sock,
4077 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 struct sock *newsk)
4079{
David S. Miller3610cda2011-01-05 15:38:53 -08004080 struct sk_security_struct *sksec_sock = sock->sk_security;
4081 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004082 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004083 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004084 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004085 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 int err;
4087
Thomas Liu2bf49692009-07-14 12:14:09 -04004088 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004089 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004090 ad.u.net = &net;
4091 ad.u.net->sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
Paul Moore4d1e2452010-04-22 14:46:18 -04004093 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4094 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4096 if (err)
4097 return err;
4098
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004100 sksec_new->peer_sid = sksec_sock->sid;
4101 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4102 &sksec_new->sid);
4103 if (err)
4104 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004105
Paul Moore4d1e2452010-04-22 14:46:18 -04004106 /* connecting socket */
4107 sksec_sock->peer_sid = sksec_new->sid;
4108
4109 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110}
4111
4112static int selinux_socket_unix_may_send(struct socket *sock,
4113 struct socket *other)
4114{
Paul Moore253bfae2010-04-22 14:46:19 -04004115 struct sk_security_struct *ssec = sock->sk->sk_security;
4116 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004117 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004118 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004119 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
Thomas Liu2bf49692009-07-14 12:14:09 -04004121 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004122 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004123 ad.u.net = &net;
4124 ad.u.net->sk = other->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
Paul Moore253bfae2010-04-22 14:46:19 -04004126 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4127 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128}
4129
Paul Mooreeffad8d2008-01-29 08:49:27 -05004130static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4131 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004132 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004133{
4134 int err;
4135 u32 if_sid;
4136 u32 node_sid;
4137
4138 err = sel_netif_sid(ifindex, &if_sid);
4139 if (err)
4140 return err;
4141 err = avc_has_perm(peer_sid, if_sid,
4142 SECCLASS_NETIF, NETIF__INGRESS, ad);
4143 if (err)
4144 return err;
4145
4146 err = sel_netnode_sid(addrp, family, &node_sid);
4147 if (err)
4148 return err;
4149 return avc_has_perm(peer_sid, node_sid,
4150 SECCLASS_NODE, NODE__RECVFROM, ad);
4151}
4152
Paul Moore220deb92008-01-29 08:38:23 -05004153static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004154 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004155{
Paul Moore277d3422008-12-31 12:54:11 -05004156 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004157 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004158 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004159 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004160 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004161 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004162 char *addrp;
4163
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->netif = skb->skb_iif;
4168 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004169 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4170 if (err)
4171 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004172
Paul Moore58bfbb52009-03-27 17:10:41 -04004173 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004174 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004175 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004176 if (err)
4177 return err;
4178 }
Paul Moore220deb92008-01-29 08:38:23 -05004179
Steffen Klassertb9679a72011-02-23 12:55:21 +01004180 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4181 if (err)
4182 return err;
4183 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004184
James Morris4e5ab4c2006-06-09 00:33:33 -07004185 return err;
4186}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004187
James Morris4e5ab4c2006-06-09 00:33:33 -07004188static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4189{
Paul Moore220deb92008-01-29 08:38:23 -05004190 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004191 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004192 u16 family = sk->sk_family;
4193 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004194 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004195 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004196 struct lsm_network_audit net = {0,};
Paul Moore220deb92008-01-29 08:38:23 -05004197 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004198 u8 secmark_active;
4199 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004200
James Morris4e5ab4c2006-06-09 00:33:33 -07004201 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004202 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004203
4204 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004205 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004206 family = PF_INET;
4207
Paul Moored8395c82008-10-10 10:16:30 -04004208 /* If any sort of compatibility mode is enabled then handoff processing
4209 * to the selinux_sock_rcv_skb_compat() function to deal with the
4210 * special handling. We do this in an attempt to keep this function
4211 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004212 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004213 return selinux_sock_rcv_skb_compat(sk, skb, family);
4214
4215 secmark_active = selinux_secmark_enabled();
4216 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4217 if (!secmark_active && !peerlbl_active)
4218 return 0;
4219
Thomas Liu2bf49692009-07-14 12:14:09 -04004220 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004221 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004222 ad.u.net = &net;
4223 ad.u.net->netif = skb->skb_iif;
4224 ad.u.net->family = family;
Paul Moore224dfbd2008-01-29 08:38:13 -05004225 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004226 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004227 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004228
Paul Moored8395c82008-10-10 10:16:30 -04004229 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004230 u32 peer_sid;
4231
4232 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4233 if (err)
4234 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004235 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004236 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004237 if (err) {
4238 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004239 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004240 }
Paul Moored621d352008-01-29 08:43:36 -05004241 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4242 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004243 if (err)
4244 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004245 }
4246
Paul Moored8395c82008-10-10 10:16:30 -04004247 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004248 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4249 PACKET__RECV, &ad);
4250 if (err)
4251 return err;
4252 }
4253
Paul Moored621d352008-01-29 08:43:36 -05004254 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255}
4256
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004257static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4258 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259{
4260 int err = 0;
4261 char *scontext;
4262 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004263 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004264 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
Paul Moore253bfae2010-04-22 14:46:19 -04004266 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4267 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004268 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004269 if (peer_sid == SECSID_NULL)
4270 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004272 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004274 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275
4276 if (scontext_len > len) {
4277 err = -ERANGE;
4278 goto out_len;
4279 }
4280
4281 if (copy_to_user(optval, scontext, scontext_len))
4282 err = -EFAULT;
4283
4284out_len:
4285 if (put_user(scontext_len, optlen))
4286 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 return err;
4289}
4290
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004291static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004292{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004293 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004294 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004295
Paul Mooreaa862902008-10-10 10:16:29 -04004296 if (skb && skb->protocol == htons(ETH_P_IP))
4297 family = PF_INET;
4298 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4299 family = PF_INET6;
4300 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004301 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004302 else
4303 goto out;
4304
4305 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02004306 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004307 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004308 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004309
Paul Moore75e22912008-01-29 08:38:04 -05004310out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004311 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004312 if (peer_secid == SECSID_NULL)
4313 return -EINVAL;
4314 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004315}
4316
Al Viro7d877f32005-10-21 03:20:43 -04004317static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318{
Paul Moore84914b72010-04-22 14:46:18 -04004319 struct sk_security_struct *sksec;
4320
4321 sksec = kzalloc(sizeof(*sksec), priority);
4322 if (!sksec)
4323 return -ENOMEM;
4324
4325 sksec->peer_sid = SECINITSID_UNLABELED;
4326 sksec->sid = SECINITSID_UNLABELED;
4327 selinux_netlbl_sk_security_reset(sksec);
4328 sk->sk_security = sksec;
4329
4330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331}
4332
4333static void selinux_sk_free_security(struct sock *sk)
4334{
Paul Moore84914b72010-04-22 14:46:18 -04004335 struct sk_security_struct *sksec = sk->sk_security;
4336
4337 sk->sk_security = NULL;
4338 selinux_netlbl_sk_security_free(sksec);
4339 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340}
4341
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004342static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4343{
Eric Parisdd3e7832010-04-07 15:08:46 -04004344 struct sk_security_struct *sksec = sk->sk_security;
4345 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004346
Eric Parisdd3e7832010-04-07 15:08:46 -04004347 newsksec->sid = sksec->sid;
4348 newsksec->peer_sid = sksec->peer_sid;
4349 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004350
Eric Parisdd3e7832010-04-07 15:08:46 -04004351 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004352}
4353
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004354static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004355{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004356 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004357 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004358 else {
4359 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004360
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004361 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004362 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004363}
4364
Eric Paris828dfe12008-04-17 13:17:49 -04004365static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004366{
4367 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4368 struct sk_security_struct *sksec = sk->sk_security;
4369
David Woodhouse2148ccc2006-09-29 15:50:25 -07004370 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4371 sk->sk_family == PF_UNIX)
4372 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004373 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004374}
4375
Adrian Bunk9a673e52006-08-15 00:03:53 -07004376static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4377 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004378{
4379 struct sk_security_struct *sksec = sk->sk_security;
4380 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004381 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004382 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004383 u32 peersid;
4384
Paul Mooreaa862902008-10-10 10:16:29 -04004385 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4386 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4387 family = PF_INET;
4388
4389 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004390 if (err)
4391 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004392 if (peersid == SECSID_NULL) {
4393 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004394 req->peer_secid = SECSID_NULL;
Paul Moore389fb8002009-03-27 17:10:34 -04004395 } else {
4396 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4397 if (err)
4398 return err;
4399 req->secid = newsid;
4400 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004401 }
4402
Paul Moore389fb8002009-03-27 17:10:34 -04004403 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004404}
4405
Adrian Bunk9a673e52006-08-15 00:03:53 -07004406static void selinux_inet_csk_clone(struct sock *newsk,
4407 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004408{
4409 struct sk_security_struct *newsksec = newsk->sk_security;
4410
4411 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004412 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004413 /* NOTE: Ideally, we should also get the isec->sid for the
4414 new socket in sync, but we don't have the isec available yet.
4415 So we will wait until sock_graft to do it, by which
4416 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004417
Paul Moore9f2ad662006-11-17 17:38:53 -05004418 /* We don't need to take any sort of lock here as we are the only
4419 * thread with access to newsksec */
Paul Moore389fb8002009-03-27 17:10:34 -04004420 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004421}
4422
Paul Moore014ab192008-10-10 10:16:33 -04004423static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004424{
Paul Mooreaa862902008-10-10 10:16:29 -04004425 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004426 struct sk_security_struct *sksec = sk->sk_security;
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 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004433}
4434
Eric Paris2606fd12010-10-13 16:24:41 -04004435static int selinux_secmark_relabel_packet(u32 sid)
4436{
4437 const struct task_security_struct *__tsec;
4438 u32 tsid;
4439
4440 __tsec = current_security();
4441 tsid = __tsec->sid;
4442
4443 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4444}
4445
4446static void selinux_secmark_refcount_inc(void)
4447{
4448 atomic_inc(&selinux_secmark_refcount);
4449}
4450
4451static void selinux_secmark_refcount_dec(void)
4452{
4453 atomic_dec(&selinux_secmark_refcount);
4454}
4455
Adrian Bunk9a673e52006-08-15 00:03:53 -07004456static void selinux_req_classify_flow(const struct request_sock *req,
4457 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004458{
David S. Miller1d28f422011-03-12 00:29:39 -05004459 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004460}
4461
Paul Mooreed6d76e2009-08-28 18:12:49 -04004462static int selinux_tun_dev_create(void)
4463{
4464 u32 sid = current_sid();
4465
4466 /* we aren't taking into account the "sockcreate" SID since the socket
4467 * that is being created here is not a socket in the traditional sense,
4468 * instead it is a private sock, accessible only to the kernel, and
4469 * representing a wide range of network traffic spanning multiple
4470 * connections unlike traditional sockets - check the TUN driver to
4471 * get a better understanding of why this socket is special */
4472
4473 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4474 NULL);
4475}
4476
4477static void selinux_tun_dev_post_create(struct sock *sk)
4478{
4479 struct sk_security_struct *sksec = sk->sk_security;
4480
4481 /* we don't currently perform any NetLabel based labeling here and it
4482 * isn't clear that we would want to do so anyway; while we could apply
4483 * labeling without the support of the TUN user the resulting labeled
4484 * traffic from the other end of the connection would almost certainly
4485 * cause confusion to the TUN user that had no idea network labeling
4486 * protocols were being used */
4487
4488 /* see the comments in selinux_tun_dev_create() about why we don't use
4489 * the sockcreate SID here */
4490
4491 sksec->sid = current_sid();
4492 sksec->sclass = SECCLASS_TUN_SOCKET;
4493}
4494
4495static int selinux_tun_dev_attach(struct sock *sk)
4496{
4497 struct sk_security_struct *sksec = sk->sk_security;
4498 u32 sid = current_sid();
4499 int err;
4500
4501 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4502 TUN_SOCKET__RELABELFROM, NULL);
4503 if (err)
4504 return err;
4505 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4506 TUN_SOCKET__RELABELTO, NULL);
4507 if (err)
4508 return err;
4509
4510 sksec->sid = sid;
4511
4512 return 0;
4513}
4514
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4516{
4517 int err = 0;
4518 u32 perm;
4519 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004520 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004521
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 if (skb->len < NLMSG_SPACE(0)) {
4523 err = -EINVAL;
4524 goto out;
4525 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004526 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004527
Paul Moore253bfae2010-04-22 14:46:19 -04004528 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 if (err) {
4530 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004531 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 "SELinux: unrecognized netlink message"
4533 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004534 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004535 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 err = 0;
4537 }
4538
4539 /* Ignore */
4540 if (err == -ENOENT)
4541 err = 0;
4542 goto out;
4543 }
4544
Paul Moore253bfae2010-04-22 14:46:19 -04004545 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546out:
4547 return err;
4548}
4549
4550#ifdef CONFIG_NETFILTER
4551
Paul Mooreeffad8d2008-01-29 08:49:27 -05004552static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4553 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554{
Paul Mooredfaebe92008-10-10 10:16:31 -04004555 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004556 char *addrp;
4557 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004558 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004559 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004560 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004561 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004562 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004563 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004564
Paul Mooreeffad8d2008-01-29 08:49:27 -05004565 if (!selinux_policycap_netpeer)
4566 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004567
Paul Mooreeffad8d2008-01-29 08:49:27 -05004568 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004569 netlbl_active = netlbl_enabled();
4570 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004571 if (!secmark_active && !peerlbl_active)
4572 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004573
Paul Moored8395c82008-10-10 10:16:30 -04004574 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4575 return NF_DROP;
4576
Thomas Liu2bf49692009-07-14 12:14:09 -04004577 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004578 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004579 ad.u.net = &net;
4580 ad.u.net->netif = ifindex;
4581 ad.u.net->family = family;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004582 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4583 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584
Paul Mooredfaebe92008-10-10 10:16:31 -04004585 if (peerlbl_active) {
4586 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4587 peer_sid, &ad);
4588 if (err) {
4589 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004590 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004591 }
4592 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004593
4594 if (secmark_active)
4595 if (avc_has_perm(peer_sid, skb->secmark,
4596 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4597 return NF_DROP;
4598
Paul Moore948bf852008-10-10 10:16:32 -04004599 if (netlbl_active)
4600 /* we do this in the FORWARD path and not the POST_ROUTING
4601 * path because we want to make sure we apply the necessary
4602 * labeling before IPsec is applied so we can leverage AH
4603 * protection */
4604 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4605 return NF_DROP;
4606
Paul Mooreeffad8d2008-01-29 08:49:27 -05004607 return NF_ACCEPT;
4608}
4609
4610static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4611 struct sk_buff *skb,
4612 const struct net_device *in,
4613 const struct net_device *out,
4614 int (*okfn)(struct sk_buff *))
4615{
4616 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4617}
4618
4619#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4620static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4621 struct sk_buff *skb,
4622 const struct net_device *in,
4623 const struct net_device *out,
4624 int (*okfn)(struct sk_buff *))
4625{
4626 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4627}
4628#endif /* IPV6 */
4629
Paul Moore948bf852008-10-10 10:16:32 -04004630static unsigned int selinux_ip_output(struct sk_buff *skb,
4631 u16 family)
4632{
4633 u32 sid;
4634
4635 if (!netlbl_enabled())
4636 return NF_ACCEPT;
4637
4638 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4639 * because we want to make sure we apply the necessary labeling
4640 * before IPsec is applied so we can leverage AH protection */
4641 if (skb->sk) {
4642 struct sk_security_struct *sksec = skb->sk->sk_security;
4643 sid = sksec->sid;
4644 } else
4645 sid = SECINITSID_KERNEL;
4646 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4647 return NF_DROP;
4648
4649 return NF_ACCEPT;
4650}
4651
4652static unsigned int selinux_ipv4_output(unsigned int hooknum,
4653 struct sk_buff *skb,
4654 const struct net_device *in,
4655 const struct net_device *out,
4656 int (*okfn)(struct sk_buff *))
4657{
4658 return selinux_ip_output(skb, PF_INET);
4659}
4660
Paul Mooreeffad8d2008-01-29 08:49:27 -05004661static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4662 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004663 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004664{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004665 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004666 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004667 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004668 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004669 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004670 char *addrp;
4671 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004672
Paul Mooreeffad8d2008-01-29 08:49:27 -05004673 if (sk == NULL)
4674 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004675 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004676
Thomas Liu2bf49692009-07-14 12:14:09 -04004677 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004678 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004679 ad.u.net = &net;
4680 ad.u.net->netif = ifindex;
4681 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004682 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4683 return NF_DROP;
4684
Paul Moore58bfbb52009-03-27 17:10:41 -04004685 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004686 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004687 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004688 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004689
Steffen Klassertb9679a72011-02-23 12:55:21 +01004690 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4691 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004692
Paul Mooreeffad8d2008-01-29 08:49:27 -05004693 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694}
4695
Paul Mooreeffad8d2008-01-29 08:49:27 -05004696static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4697 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004699 u32 secmark_perm;
4700 u32 peer_sid;
4701 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004702 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004703 struct selinux_audit_data sad = {0,};
Eric Paris48c62af2012-04-02 13:15:44 -04004704 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004705 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004706 u8 secmark_active;
4707 u8 peerlbl_active;
4708
Paul Mooreeffad8d2008-01-29 08:49:27 -05004709 /* If any sort of compatibility mode is enabled then handoff processing
4710 * to the selinux_ip_postroute_compat() function to deal with the
4711 * special handling. We do this in an attempt to keep this function
4712 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004713 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004714 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004715#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4717 * packet transformation so allow the packet to pass without any checks
4718 * since we'll have another chance to perform access control checks
4719 * when the packet is on it's final way out.
4720 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4721 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004722 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004723 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004724#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004725 secmark_active = selinux_secmark_enabled();
4726 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4727 if (!secmark_active && !peerlbl_active)
4728 return NF_ACCEPT;
4729
Paul Moored8395c82008-10-10 10:16:30 -04004730 /* if the packet is being forwarded then get the peer label from the
4731 * packet itself; otherwise check to see if it is from a local
4732 * application or the kernel, if from an application get the peer label
4733 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004734 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004735 if (sk == NULL) {
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004736 if (skb->skb_iif) {
4737 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004738 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004739 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004740 } else {
4741 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004742 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004743 }
Paul Moored8395c82008-10-10 10:16:30 -04004744 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004745 struct sk_security_struct *sksec = sk->sk_security;
4746 peer_sid = sksec->sid;
4747 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004748 }
4749
Thomas Liu2bf49692009-07-14 12:14:09 -04004750 COMMON_AUDIT_DATA_INIT(&ad, NET);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004751 ad.selinux_audit_data = &sad;
Eric Paris48c62af2012-04-02 13:15:44 -04004752 ad.u.net = &net;
4753 ad.u.net->netif = ifindex;
4754 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004755 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004756 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004757
Paul Mooreeffad8d2008-01-29 08:49:27 -05004758 if (secmark_active)
4759 if (avc_has_perm(peer_sid, skb->secmark,
4760 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004761 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004762
4763 if (peerlbl_active) {
4764 u32 if_sid;
4765 u32 node_sid;
4766
4767 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004768 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004769 if (avc_has_perm(peer_sid, if_sid,
4770 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004771 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004772
4773 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004774 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004775 if (avc_has_perm(peer_sid, node_sid,
4776 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004777 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004778 }
4779
4780 return NF_ACCEPT;
4781}
4782
4783static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4784 struct sk_buff *skb,
4785 const struct net_device *in,
4786 const struct net_device *out,
4787 int (*okfn)(struct sk_buff *))
4788{
4789 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790}
4791
4792#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004793static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4794 struct sk_buff *skb,
4795 const struct net_device *in,
4796 const struct net_device *out,
4797 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004799 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801#endif /* IPV6 */
4802
4803#endif /* CONFIG_NETFILTER */
4804
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4806{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 int err;
4808
Eric Paris200ac532009-02-12 15:01:04 -05004809 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 if (err)
4811 return err;
4812
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004813 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814}
4815
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816static int ipc_alloc_security(struct task_struct *task,
4817 struct kern_ipc_perm *perm,
4818 u16 sclass)
4819{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004821 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822
James Morris89d155e2005-10-30 14:59:21 -08004823 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 if (!isec)
4825 return -ENOMEM;
4826
David Howells275bb412008-11-14 10:39:19 +11004827 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004829 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 perm->security = isec;
4831
4832 return 0;
4833}
4834
4835static void ipc_free_security(struct kern_ipc_perm *perm)
4836{
4837 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 perm->security = NULL;
4839 kfree(isec);
4840}
4841
4842static int msg_msg_alloc_security(struct msg_msg *msg)
4843{
4844 struct msg_security_struct *msec;
4845
James Morris89d155e2005-10-30 14:59:21 -08004846 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 if (!msec)
4848 return -ENOMEM;
4849
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 msec->sid = SECINITSID_UNLABELED;
4851 msg->security = msec;
4852
4853 return 0;
4854}
4855
4856static void msg_msg_free_security(struct msg_msg *msg)
4857{
4858 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859
4860 msg->security = NULL;
4861 kfree(msec);
4862}
4863
4864static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004865 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004868 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004869 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004870 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 isec = ipc_perms->security;
4873
Thomas Liu2bf49692009-07-14 12:14:09 -04004874 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004875 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 ad.u.ipc_id = ipc_perms->key;
4877
David Howells275bb412008-11-14 10:39:19 +11004878 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879}
4880
4881static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4882{
4883 return msg_msg_alloc_security(msg);
4884}
4885
4886static void selinux_msg_msg_free_security(struct msg_msg *msg)
4887{
4888 msg_msg_free_security(msg);
4889}
4890
4891/* message queue security operations */
4892static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4893{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004895 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004896 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004897 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 int rc;
4899
4900 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4901 if (rc)
4902 return rc;
4903
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 isec = msq->q_perm.security;
4905
Thomas Liu2bf49692009-07-14 12:14:09 -04004906 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004907 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04004908 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909
David Howells275bb412008-11-14 10:39:19 +11004910 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 MSGQ__CREATE, &ad);
4912 if (rc) {
4913 ipc_free_security(&msq->q_perm);
4914 return rc;
4915 }
4916 return 0;
4917}
4918
4919static void selinux_msg_queue_free_security(struct msg_queue *msq)
4920{
4921 ipc_free_security(&msq->q_perm);
4922}
4923
4924static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4925{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004927 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004928 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004929 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 isec = msq->q_perm.security;
4932
Thomas Liu2bf49692009-07-14 12:14:09 -04004933 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004934 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 ad.u.ipc_id = msq->q_perm.key;
4936
David Howells275bb412008-11-14 10:39:19 +11004937 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 MSGQ__ASSOCIATE, &ad);
4939}
4940
4941static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4942{
4943 int err;
4944 int perms;
4945
Eric Paris828dfe12008-04-17 13:17:49 -04004946 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 case IPC_INFO:
4948 case MSG_INFO:
4949 /* No specific object, just general system-wide information. */
4950 return task_has_system(current, SYSTEM__IPC_INFO);
4951 case IPC_STAT:
4952 case MSG_STAT:
4953 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4954 break;
4955 case IPC_SET:
4956 perms = MSGQ__SETATTR;
4957 break;
4958 case IPC_RMID:
4959 perms = MSGQ__DESTROY;
4960 break;
4961 default:
4962 return 0;
4963 }
4964
Stephen Smalley6af963f2005-05-01 08:58:39 -07004965 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966 return err;
4967}
4968
4969static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4970{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 struct ipc_security_struct *isec;
4972 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004973 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07004974 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11004975 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 int rc;
4977
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 isec = msq->q_perm.security;
4979 msec = msg->security;
4980
4981 /*
4982 * First time through, need to assign label to the message
4983 */
4984 if (msec->sid == SECINITSID_UNLABELED) {
4985 /*
4986 * Compute new sid based on current process and
4987 * message queue this message will be stored in
4988 */
David Howells275bb412008-11-14 10:39:19 +11004989 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05004990 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 if (rc)
4992 return rc;
4993 }
4994
Thomas Liu2bf49692009-07-14 12:14:09 -04004995 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07004996 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 ad.u.ipc_id = msq->q_perm.key;
4998
4999 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11005000 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 MSGQ__WRITE, &ad);
5002 if (!rc)
5003 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11005004 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
5005 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 if (!rc)
5007 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11005008 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
5009 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010
5011 return rc;
5012}
5013
5014static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
5015 struct task_struct *target,
5016 long type, int mode)
5017{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 struct ipc_security_struct *isec;
5019 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005020 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005021 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005022 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023 int rc;
5024
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 isec = msq->q_perm.security;
5026 msec = msg->security;
5027
Thomas Liu2bf49692009-07-14 12:14:09 -04005028 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005029 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005030 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031
David Howells275bb412008-11-14 10:39:19 +11005032 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 SECCLASS_MSGQ, MSGQ__READ, &ad);
5034 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11005035 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 SECCLASS_MSG, MSG__RECEIVE, &ad);
5037 return rc;
5038}
5039
5040/* Shared Memory security operations */
5041static int selinux_shm_alloc_security(struct shmid_kernel *shp)
5042{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005044 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005045 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005046 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 int rc;
5048
5049 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
5050 if (rc)
5051 return rc;
5052
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 isec = shp->shm_perm.security;
5054
Thomas Liu2bf49692009-07-14 12:14:09 -04005055 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005056 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005057 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058
David Howells275bb412008-11-14 10:39:19 +11005059 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 SHM__CREATE, &ad);
5061 if (rc) {
5062 ipc_free_security(&shp->shm_perm);
5063 return rc;
5064 }
5065 return 0;
5066}
5067
5068static void selinux_shm_free_security(struct shmid_kernel *shp)
5069{
5070 ipc_free_security(&shp->shm_perm);
5071}
5072
5073static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5074{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005076 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005077 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005078 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 isec = shp->shm_perm.security;
5081
Thomas Liu2bf49692009-07-14 12:14:09 -04005082 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005083 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 ad.u.ipc_id = shp->shm_perm.key;
5085
David Howells275bb412008-11-14 10:39:19 +11005086 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 SHM__ASSOCIATE, &ad);
5088}
5089
5090/* Note, at this point, shp is locked down */
5091static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5092{
5093 int perms;
5094 int err;
5095
Eric Paris828dfe12008-04-17 13:17:49 -04005096 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 case IPC_INFO:
5098 case SHM_INFO:
5099 /* No specific object, just general system-wide information. */
5100 return task_has_system(current, SYSTEM__IPC_INFO);
5101 case IPC_STAT:
5102 case SHM_STAT:
5103 perms = SHM__GETATTR | SHM__ASSOCIATE;
5104 break;
5105 case IPC_SET:
5106 perms = SHM__SETATTR;
5107 break;
5108 case SHM_LOCK:
5109 case SHM_UNLOCK:
5110 perms = SHM__LOCK;
5111 break;
5112 case IPC_RMID:
5113 perms = SHM__DESTROY;
5114 break;
5115 default:
5116 return 0;
5117 }
5118
Stephen Smalley6af963f2005-05-01 08:58:39 -07005119 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 return err;
5121}
5122
5123static int selinux_shm_shmat(struct shmid_kernel *shp,
5124 char __user *shmaddr, int shmflg)
5125{
5126 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127
5128 if (shmflg & SHM_RDONLY)
5129 perms = SHM__READ;
5130 else
5131 perms = SHM__READ | SHM__WRITE;
5132
Stephen Smalley6af963f2005-05-01 08:58:39 -07005133 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134}
5135
5136/* Semaphore security operations */
5137static int selinux_sem_alloc_security(struct sem_array *sma)
5138{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005140 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005141 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005142 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 int rc;
5144
5145 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5146 if (rc)
5147 return rc;
5148
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 isec = sma->sem_perm.security;
5150
Thomas Liu2bf49692009-07-14 12:14:09 -04005151 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005152 ad.selinux_audit_data = &sad;
Eric Paris828dfe12008-04-17 13:17:49 -04005153 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154
David Howells275bb412008-11-14 10:39:19 +11005155 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 SEM__CREATE, &ad);
5157 if (rc) {
5158 ipc_free_security(&sma->sem_perm);
5159 return rc;
5160 }
5161 return 0;
5162}
5163
5164static void selinux_sem_free_security(struct sem_array *sma)
5165{
5166 ipc_free_security(&sma->sem_perm);
5167}
5168
5169static int selinux_sem_associate(struct sem_array *sma, int semflg)
5170{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005172 struct common_audit_data ad;
Eric Paris3b3b0e42012-04-03 09:37:02 -07005173 struct selinux_audit_data sad = {0,};
David Howells275bb412008-11-14 10:39:19 +11005174 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 isec = sma->sem_perm.security;
5177
Thomas Liu2bf49692009-07-14 12:14:09 -04005178 COMMON_AUDIT_DATA_INIT(&ad, IPC);
Eric Paris3b3b0e42012-04-03 09:37:02 -07005179 ad.selinux_audit_data = &sad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 ad.u.ipc_id = sma->sem_perm.key;
5181
David Howells275bb412008-11-14 10:39:19 +11005182 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 SEM__ASSOCIATE, &ad);
5184}
5185
5186/* Note, at this point, sma is locked down */
5187static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5188{
5189 int err;
5190 u32 perms;
5191
Eric Paris828dfe12008-04-17 13:17:49 -04005192 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 case IPC_INFO:
5194 case SEM_INFO:
5195 /* No specific object, just general system-wide information. */
5196 return task_has_system(current, SYSTEM__IPC_INFO);
5197 case GETPID:
5198 case GETNCNT:
5199 case GETZCNT:
5200 perms = SEM__GETATTR;
5201 break;
5202 case GETVAL:
5203 case GETALL:
5204 perms = SEM__READ;
5205 break;
5206 case SETVAL:
5207 case SETALL:
5208 perms = SEM__WRITE;
5209 break;
5210 case IPC_RMID:
5211 perms = SEM__DESTROY;
5212 break;
5213 case IPC_SET:
5214 perms = SEM__SETATTR;
5215 break;
5216 case IPC_STAT:
5217 case SEM_STAT:
5218 perms = SEM__GETATTR | SEM__ASSOCIATE;
5219 break;
5220 default:
5221 return 0;
5222 }
5223
Stephen Smalley6af963f2005-05-01 08:58:39 -07005224 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 return err;
5226}
5227
5228static int selinux_sem_semop(struct sem_array *sma,
5229 struct sembuf *sops, unsigned nsops, int alter)
5230{
5231 u32 perms;
5232
5233 if (alter)
5234 perms = SEM__READ | SEM__WRITE;
5235 else
5236 perms = SEM__READ;
5237
Stephen Smalley6af963f2005-05-01 08:58:39 -07005238 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239}
5240
5241static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5242{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 u32 av = 0;
5244
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 av = 0;
5246 if (flag & S_IRUGO)
5247 av |= IPC__UNIX_READ;
5248 if (flag & S_IWUGO)
5249 av |= IPC__UNIX_WRITE;
5250
5251 if (av == 0)
5252 return 0;
5253
Stephen Smalley6af963f2005-05-01 08:58:39 -07005254 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255}
5256
Ahmed S. Darwish713a04ae2008-03-01 21:52:30 +02005257static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5258{
5259 struct ipc_security_struct *isec = ipcp->security;
5260 *secid = isec->sid;
5261}
5262
Eric Paris828dfe12008-04-17 13:17:49 -04005263static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264{
5265 if (inode)
5266 inode_doinit_with_dentry(inode, dentry);
5267}
5268
5269static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005270 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271{
David Howells275bb412008-11-14 10:39:19 +11005272 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005273 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005275 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276
5277 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005278 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 if (error)
5280 return error;
5281 }
5282
David Howells275bb412008-11-14 10:39:19 +11005283 rcu_read_lock();
5284 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285
5286 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005287 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005289 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005291 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005293 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005294 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005295 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005296 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005297 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 else
David Howells275bb412008-11-14 10:39:19 +11005299 goto invalid;
5300 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301
5302 if (!sid)
5303 return 0;
5304
Al Viro04ff9702007-03-12 16:17:58 +00005305 error = security_sid_to_context(sid, value, &len);
5306 if (error)
5307 return error;
5308 return len;
David Howells275bb412008-11-14 10:39:19 +11005309
5310invalid:
5311 rcu_read_unlock();
5312 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313}
5314
5315static int selinux_setprocattr(struct task_struct *p,
5316 char *name, void *value, size_t size)
5317{
5318 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005319 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005320 struct cred *new;
5321 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 int error;
5323 char *str = value;
5324
5325 if (current != p) {
5326 /* SELinux only allows a process to change its own
5327 security attributes. */
5328 return -EACCES;
5329 }
5330
5331 /*
5332 * Basic control over ability to set these attributes at all.
5333 * current == p, but we'll pass them separately in case the
5334 * above restriction is ever removed.
5335 */
5336 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005337 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005339 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005340 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005341 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005342 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005343 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005345 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 else
5347 error = -EINVAL;
5348 if (error)
5349 return error;
5350
5351 /* Obtain a SID for the context, if one was specified. */
5352 if (size && str[1] && str[1] != '\n') {
5353 if (str[size-1] == '\n') {
5354 str[size-1] = 0;
5355 size--;
5356 }
5357 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005358 if (error == -EINVAL && !strcmp(name, "fscreate")) {
Eric Parisd6ea83e2012-04-04 13:45:49 -04005359 if (!capable(CAP_MAC_ADMIN)) {
5360 struct audit_buffer *ab;
5361 size_t audit_size;
5362
5363 /* We strip a nul only if it is at the end, otherwise the
5364 * context contains a nul and we should audit that */
5365 if (str[size - 1] == '\0')
5366 audit_size = size - 1;
5367 else
5368 audit_size = size;
5369 ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
5370 audit_log_format(ab, "op=fscreate invalid_context=");
5371 audit_log_n_untrustedstring(ab, value, audit_size);
5372 audit_log_end(ab);
5373
Stephen Smalley12b29f32008-05-07 13:03:20 -04005374 return error;
Eric Parisd6ea83e2012-04-04 13:45:49 -04005375 }
Stephen Smalley12b29f32008-05-07 13:03:20 -04005376 error = security_context_to_sid_force(value, size,
5377 &sid);
5378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 if (error)
5380 return error;
5381 }
5382
David Howellsd84f4f92008-11-14 10:39:23 +11005383 new = prepare_creds();
5384 if (!new)
5385 return -ENOMEM;
5386
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 /* Permission checking based on the specified context is
5388 performed during the actual operation (execve,
5389 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005390 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 checks and may_create for the file creation checks. The
5392 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005393 tsec = new->security;
5394 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005396 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005398 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005399 error = may_create_key(sid, p);
5400 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005401 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005402 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005403 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005404 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005405 } else if (!strcmp(name, "current")) {
5406 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005408 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005409
David Howellsd84f4f92008-11-14 10:39:23 +11005410 /* Only allow single threaded processes to change context */
5411 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005412 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005413 error = security_bounded_transition(tsec->sid, sid);
5414 if (error)
5415 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417
5418 /* Check permissions for the transition. */
5419 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005420 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005422 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423
5424 /* Check for ptracing, and update the task SID if ok.
5425 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005426 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 task_lock(p);
Tejun Heo06d98472011-06-17 16:50:40 +02005428 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005429 if (tracer)
5430 ptsid = task_sid(tracer);
5431 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432
David Howellsd84f4f92008-11-14 10:39:23 +11005433 if (tracer) {
5434 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5435 PROCESS__PTRACE, NULL);
5436 if (error)
5437 goto abort_change;
5438 }
5439
5440 tsec->sid = sid;
5441 } else {
5442 error = -EINVAL;
5443 goto abort_change;
5444 }
5445
5446 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005448
5449abort_change:
5450 abort_creds(new);
5451 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452}
5453
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005454static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5455{
5456 return security_sid_to_context(secid, secdata, seclen);
5457}
5458
David Howells7bf570d2008-04-29 20:52:51 +01005459static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005460{
5461 return security_context_to_sid(secdata, seclen, secid);
5462}
5463
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005464static void selinux_release_secctx(char *secdata, u32 seclen)
5465{
Paul Moore088999e2007-08-01 11:12:58 -04005466 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005467}
5468
David P. Quigley1ee65e32009-09-03 14:25:57 -04005469/*
5470 * called with inode->i_mutex locked
5471 */
5472static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5473{
5474 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5475}
5476
5477/*
5478 * called with inode->i_mutex locked
5479 */
5480static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5481{
5482 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5483}
5484
5485static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5486{
5487 int len = 0;
5488 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5489 ctx, true);
5490 if (len < 0)
5491 return len;
5492 *ctxlen = len;
5493 return 0;
5494}
Michael LeMayd7200242006-06-22 14:47:17 -07005495#ifdef CONFIG_KEYS
5496
David Howellsd84f4f92008-11-14 10:39:23 +11005497static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005498 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005499{
David Howellsd84f4f92008-11-14 10:39:23 +11005500 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005501 struct key_security_struct *ksec;
5502
5503 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5504 if (!ksec)
5505 return -ENOMEM;
5506
David Howellsd84f4f92008-11-14 10:39:23 +11005507 tsec = cred->security;
5508 if (tsec->keycreate_sid)
5509 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005510 else
David Howellsd84f4f92008-11-14 10:39:23 +11005511 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005512
David Howells275bb412008-11-14 10:39:19 +11005513 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005514 return 0;
5515}
5516
5517static void selinux_key_free(struct key *k)
5518{
5519 struct key_security_struct *ksec = k->security;
5520
5521 k->security = NULL;
5522 kfree(ksec);
5523}
5524
5525static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005526 const struct cred *cred,
5527 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005528{
5529 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005530 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005531 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005532
5533 /* if no specific permissions are requested, we skip the
5534 permission check. No serious, additional covert channels
5535 appear to be created. */
5536 if (perm == 0)
5537 return 0;
5538
David Howellsd84f4f92008-11-14 10:39:23 +11005539 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005540
5541 key = key_ref_to_ptr(key_ref);
5542 ksec = key->security;
5543
5544 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005545}
5546
David Howells70a5bb72008-04-29 01:01:26 -07005547static int selinux_key_getsecurity(struct key *key, char **_buffer)
5548{
5549 struct key_security_struct *ksec = key->security;
5550 char *context = NULL;
5551 unsigned len;
5552 int rc;
5553
5554 rc = security_sid_to_context(ksec->sid, &context, &len);
5555 if (!rc)
5556 rc = len;
5557 *_buffer = context;
5558 return rc;
5559}
5560
Michael LeMayd7200242006-06-22 14:47:17 -07005561#endif
5562
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005564 .name = "selinux",
5565
Ingo Molnar9e488582009-05-07 19:26:19 +10005566 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005567 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005569 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 .capable = selinux_capable,
5571 .quotactl = selinux_quotactl,
5572 .quota_on = selinux_quota_on,
5573 .syslog = selinux_syslog,
5574 .vm_enough_memory = selinux_vm_enough_memory,
5575
5576 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
David Howellsa6f76f22008-11-14 10:39:24 +11005578 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005579 .bprm_committing_creds = selinux_bprm_committing_creds,
5580 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 .bprm_secureexec = selinux_bprm_secureexec,
5582
5583 .sb_alloc_security = selinux_sb_alloc_security,
5584 .sb_free_security = selinux_sb_free_security,
5585 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005586 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005587 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005588 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 .sb_statfs = selinux_sb_statfs,
5590 .sb_mount = selinux_mount,
5591 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005592 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005593 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005594 .sb_parse_opts_str = selinux_parse_opts_str,
5595
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596
5597 .inode_alloc_security = selinux_inode_alloc_security,
5598 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005599 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 .inode_unlink = selinux_inode_unlink,
5603 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 .inode_rmdir = selinux_inode_rmdir,
5606 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 .inode_readlink = selinux_inode_readlink,
5609 .inode_follow_link = selinux_inode_follow_link,
5610 .inode_permission = selinux_inode_permission,
5611 .inode_setattr = selinux_inode_setattr,
5612 .inode_getattr = selinux_inode_getattr,
5613 .inode_setxattr = selinux_inode_setxattr,
5614 .inode_post_setxattr = selinux_inode_post_setxattr,
5615 .inode_getxattr = selinux_inode_getxattr,
5616 .inode_listxattr = selinux_inode_listxattr,
5617 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005618 .inode_getsecurity = selinux_inode_getsecurity,
5619 .inode_setsecurity = selinux_inode_setsecurity,
5620 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005621 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622
5623 .file_permission = selinux_file_permission,
5624 .file_alloc_security = selinux_file_alloc_security,
5625 .file_free_security = selinux_file_free_security,
5626 .file_ioctl = selinux_file_ioctl,
5627 .file_mmap = selinux_file_mmap,
5628 .file_mprotect = selinux_file_mprotect,
5629 .file_lock = selinux_file_lock,
5630 .file_fcntl = selinux_file_fcntl,
5631 .file_set_fowner = selinux_file_set_fowner,
5632 .file_send_sigiotask = selinux_file_send_sigiotask,
5633 .file_receive = selinux_file_receive,
5634
Eric Paris83d49852012-04-04 13:45:40 -04005635 .file_open = selinux_file_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005636
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005638 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005639 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005640 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005641 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005642 .kernel_act_as = selinux_kernel_act_as,
5643 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005644 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 .task_setpgid = selinux_task_setpgid,
5646 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005647 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005648 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005650 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005651 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 .task_setrlimit = selinux_task_setrlimit,
5653 .task_setscheduler = selinux_task_setscheduler,
5654 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005655 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 .task_kill = selinux_task_kill,
5657 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005658 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659
5660 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005661 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
5663 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5664 .msg_msg_free_security = selinux_msg_msg_free_security,
5665
5666 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5667 .msg_queue_free_security = selinux_msg_queue_free_security,
5668 .msg_queue_associate = selinux_msg_queue_associate,
5669 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5670 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5671 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5672
5673 .shm_alloc_security = selinux_shm_alloc_security,
5674 .shm_free_security = selinux_shm_free_security,
5675 .shm_associate = selinux_shm_associate,
5676 .shm_shmctl = selinux_shm_shmctl,
5677 .shm_shmat = selinux_shm_shmat,
5678
Eric Paris828dfe12008-04-17 13:17:49 -04005679 .sem_alloc_security = selinux_sem_alloc_security,
5680 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 .sem_associate = selinux_sem_associate,
5682 .sem_semctl = selinux_sem_semctl,
5683 .sem_semop = selinux_sem_semop,
5684
Eric Paris828dfe12008-04-17 13:17:49 -04005685 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686
Eric Paris828dfe12008-04-17 13:17:49 -04005687 .getprocattr = selinux_getprocattr,
5688 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005690 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005691 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005692 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005693 .inode_notifysecctx = selinux_inode_notifysecctx,
5694 .inode_setsecctx = selinux_inode_setsecctx,
5695 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005696
Eric Paris828dfe12008-04-17 13:17:49 -04005697 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698 .unix_may_send = selinux_socket_unix_may_send,
5699
5700 .socket_create = selinux_socket_create,
5701 .socket_post_create = selinux_socket_post_create,
5702 .socket_bind = selinux_socket_bind,
5703 .socket_connect = selinux_socket_connect,
5704 .socket_listen = selinux_socket_listen,
5705 .socket_accept = selinux_socket_accept,
5706 .socket_sendmsg = selinux_socket_sendmsg,
5707 .socket_recvmsg = selinux_socket_recvmsg,
5708 .socket_getsockname = selinux_socket_getsockname,
5709 .socket_getpeername = selinux_socket_getpeername,
5710 .socket_getsockopt = selinux_socket_getsockopt,
5711 .socket_setsockopt = selinux_socket_setsockopt,
5712 .socket_shutdown = selinux_socket_shutdown,
5713 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005714 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5715 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 .sk_alloc_security = selinux_sk_alloc_security,
5717 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005718 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005719 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005720 .sock_graft = selinux_sock_graft,
5721 .inet_conn_request = selinux_inet_conn_request,
5722 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005723 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005724 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5725 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5726 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005727 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005728 .tun_dev_create = selinux_tun_dev_create,
5729 .tun_dev_post_create = selinux_tun_dev_post_create,
5730 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005731
5732#ifdef CONFIG_SECURITY_NETWORK_XFRM
5733 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5734 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5735 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005736 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005737 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5738 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005739 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005740 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005741 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005742 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005744
5745#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005746 .key_alloc = selinux_key_alloc,
5747 .key_free = selinux_key_free,
5748 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005749 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005750#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005751
5752#ifdef CONFIG_AUDIT
5753 .audit_rule_init = selinux_audit_rule_init,
5754 .audit_rule_known = selinux_audit_rule_known,
5755 .audit_rule_match = selinux_audit_rule_match,
5756 .audit_rule_free = selinux_audit_rule_free,
5757#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758};
5759
5760static __init int selinux_init(void)
5761{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005762 if (!security_module_enable(&selinux_ops)) {
5763 selinux_enabled = 0;
5764 return 0;
5765 }
5766
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 if (!selinux_enabled) {
5768 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5769 return 0;
5770 }
5771
5772 printk(KERN_INFO "SELinux: Initializing.\n");
5773
5774 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005775 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005777 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5778
James Morris7cae7e22006-03-22 00:09:22 -08005779 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5780 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005781 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 avc_init();
5783
Eric Paris828dfe12008-04-17 13:17:49 -04005784 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 panic("SELinux: Unable to register with kernel.\n");
5786
Eric Paris828dfe12008-04-17 13:17:49 -04005787 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005788 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005789 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005790 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005791
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 return 0;
5793}
5794
Al Viroe8c26252010-03-23 06:36:54 -04005795static void delayed_superblock_init(struct super_block *sb, void *unused)
5796{
5797 superblock_doinit(sb, NULL);
5798}
5799
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800void selinux_complete_init(void)
5801{
Eric Parisfadcdb42007-02-22 18:11:31 -05005802 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803
5804 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005805 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005806 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807}
5808
5809/* SELinux requires early initialization in order to label
5810 all processes and objects when they are created. */
5811security_initcall(selinux_init);
5812
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005813#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814
Paul Mooreeffad8d2008-01-29 08:49:27 -05005815static struct nf_hook_ops selinux_ipv4_ops[] = {
5816 {
5817 .hook = selinux_ipv4_postroute,
5818 .owner = THIS_MODULE,
5819 .pf = PF_INET,
5820 .hooknum = NF_INET_POST_ROUTING,
5821 .priority = NF_IP_PRI_SELINUX_LAST,
5822 },
5823 {
5824 .hook = selinux_ipv4_forward,
5825 .owner = THIS_MODULE,
5826 .pf = PF_INET,
5827 .hooknum = NF_INET_FORWARD,
5828 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005829 },
5830 {
5831 .hook = selinux_ipv4_output,
5832 .owner = THIS_MODULE,
5833 .pf = PF_INET,
5834 .hooknum = NF_INET_LOCAL_OUT,
5835 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837};
5838
5839#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5840
Paul Mooreeffad8d2008-01-29 08:49:27 -05005841static struct nf_hook_ops selinux_ipv6_ops[] = {
5842 {
5843 .hook = selinux_ipv6_postroute,
5844 .owner = THIS_MODULE,
5845 .pf = PF_INET6,
5846 .hooknum = NF_INET_POST_ROUTING,
5847 .priority = NF_IP6_PRI_SELINUX_LAST,
5848 },
5849 {
5850 .hook = selinux_ipv6_forward,
5851 .owner = THIS_MODULE,
5852 .pf = PF_INET6,
5853 .hooknum = NF_INET_FORWARD,
5854 .priority = NF_IP6_PRI_SELINUX_FIRST,
5855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856};
5857
5858#endif /* IPV6 */
5859
5860static int __init selinux_nf_ip_init(void)
5861{
5862 int err = 0;
5863
5864 if (!selinux_enabled)
5865 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005866
5867 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5868
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005869 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5870 if (err)
5871 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872
5873#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005874 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5875 if (err)
5876 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005878
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879out:
5880 return err;
5881}
5882
5883__initcall(selinux_nf_ip_init);
5884
5885#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5886static void selinux_nf_ip_exit(void)
5887{
Eric Parisfadcdb42007-02-22 18:11:31 -05005888 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005890 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005892 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893#endif /* IPV6 */
5894}
5895#endif
5896
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005897#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898
5899#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5900#define selinux_nf_ip_exit()
5901#endif
5902
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005903#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904
5905#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005906static int selinux_disabled;
5907
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908int selinux_disable(void)
5909{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 if (ss_initialized) {
5911 /* Not permitted after initial policy load. */
5912 return -EINVAL;
5913 }
5914
5915 if (selinux_disabled) {
5916 /* Only do this once. */
5917 return -EINVAL;
5918 }
5919
5920 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5921
5922 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005923 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08005925 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926
Eric Parisaf8ff042009-09-20 21:23:01 -04005927 /* Try to destroy the avc node cache */
5928 avc_disable();
5929
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 /* Unregister netfilter hooks. */
5931 selinux_nf_ip_exit();
5932
5933 /* Unregister selinuxfs. */
5934 exit_sel_fs();
5935
5936 return 0;
5937}
5938#endif