blob: 24ab4148547c2ba925042126ca9350a25a9969f8 [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. Hallyn3486740a2011-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 Parisa35c6c82011-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 Paris06112162008-11-11 22:02:50 +11001423 struct av_decision avd;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001424 u16 sclass;
David Howells3699c532009-01-06 22:27:01 +00001425 u32 sid = cred_sid(cred);
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001426 u32 av = CAP_TO_MASK(cap);
Eric Paris06112162008-11-11 22:02:50 +11001427 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Eric Paris50c205f2012-04-04 15:01:43 -04001429 ad.type = LSM_AUDIT_DATA_CAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 ad.u.cap = cap;
1431
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001432 switch (CAP_TO_INDEX(cap)) {
1433 case 0:
1434 sclass = SECCLASS_CAPABILITY;
1435 break;
1436 case 1:
1437 sclass = SECCLASS_CAPABILITY2;
1438 break;
1439 default:
1440 printk(KERN_ERR
1441 "SELinux: out of range capability %d\n", cap);
1442 BUG();
Eric Parisa35c6c82011-04-20 10:21:28 -04001443 return -EINVAL;
Stephen Smalleyb68e4182008-02-07 11:21:04 -05001444 }
Eric Paris06112162008-11-11 22:02:50 +11001445
David Howells275bb412008-11-14 10:39:19 +11001446 rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
Eric Paris9ade0cf2011-04-25 16:26:29 -04001447 if (audit == SECURITY_CAP_AUDIT) {
1448 int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
1449 if (rc2)
1450 return rc2;
1451 }
Eric Paris06112162008-11-11 22:02:50 +11001452 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453}
1454
1455/* Check whether a task is allowed to use a system operation. */
1456static int task_has_system(struct task_struct *tsk,
1457 u32 perms)
1458{
David Howells275bb412008-11-14 10:39:19 +11001459 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
David Howells275bb412008-11-14 10:39:19 +11001461 return avc_has_perm(sid, SECINITSID_KERNEL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 SECCLASS_SYSTEM, perms, NULL);
1463}
1464
1465/* Check whether a task has a particular permission to an inode.
1466 The 'adp' parameter is optional and allows other audit
1467 data to be passed (e.g. the dentry). */
David Howells88e67f32008-11-14 10:39:21 +11001468static int inode_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 struct inode *inode,
1470 u32 perms,
Eric Paris9ade0cf2011-04-25 16:26:29 -04001471 struct common_audit_data *adp,
1472 unsigned flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 struct inode_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11001475 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
David Howellse0e81732009-09-02 09:13:40 +01001477 validate_creds(cred);
1478
Eric Paris828dfe12008-04-17 13:17:49 -04001479 if (unlikely(IS_PRIVATE(inode)))
Stephen Smalleybbaca6c2007-02-14 00:34:16 -08001480 return 0;
1481
David Howells88e67f32008-11-14 10:39:21 +11001482 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 isec = inode->i_security;
1484
Eric Paris9ade0cf2011-04-25 16:26:29 -04001485 return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486}
1487
1488/* Same as inode_has_perm, but pass explicit audit data containing
1489 the dentry to help the auditing code to more easily generate the
1490 pathname if needed. */
David Howells88e67f32008-11-14 10:39:21 +11001491static inline int dentry_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 struct dentry *dentry,
1493 u32 av)
1494{
1495 struct inode *inode = dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001496 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001497
Eric Paris50c205f2012-04-04 15:01:43 -04001498 ad.type = LSM_AUDIT_DATA_DENTRY;
Eric Paris2875fa02011-04-28 16:04:24 -04001499 ad.u.dentry = dentry;
1500 return inode_has_perm(cred, inode, av, &ad, 0);
1501}
1502
1503/* Same as inode_has_perm, but pass explicit audit data containing
1504 the path to help the auditing code to more easily generate the
1505 pathname if needed. */
1506static inline int path_has_perm(const struct cred *cred,
1507 struct path *path,
1508 u32 av)
1509{
1510 struct inode *inode = path->dentry->d_inode;
1511 struct common_audit_data ad;
1512
Eric Paris50c205f2012-04-04 15:01:43 -04001513 ad.type = LSM_AUDIT_DATA_PATH;
Eric Paris2875fa02011-04-28 16:04:24 -04001514 ad.u.path = *path;
Eric Paris9ade0cf2011-04-25 16:26:29 -04001515 return inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516}
1517
1518/* Check whether a task can use an open file descriptor to
1519 access an inode in a given way. Check access to the
1520 descriptor itself, and then use dentry_has_perm to
1521 check a particular permission to the file.
1522 Access to the descriptor is implicitly granted if it
1523 has the same SID as the process. If av is zero, then
1524 access to the file is not checked, e.g. for cases
1525 where only the descriptor is affected like seek. */
David Howells88e67f32008-11-14 10:39:21 +11001526static int file_has_perm(const struct cred *cred,
1527 struct file *file,
1528 u32 av)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 struct file_security_struct *fsec = file->f_security;
Jan Blunck44707fd2008-02-14 19:38:33 -08001531 struct inode *inode = file->f_path.dentry->d_inode;
Thomas Liu2bf49692009-07-14 12:14:09 -04001532 struct common_audit_data ad;
David Howells88e67f32008-11-14 10:39:21 +11001533 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 int rc;
1535
Eric Paris50c205f2012-04-04 15:01:43 -04001536 ad.type = LSM_AUDIT_DATA_PATH;
Eric Parisf48b7392011-04-25 12:54:27 -04001537 ad.u.path = file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
David Howells275bb412008-11-14 10:39:19 +11001539 if (sid != fsec->sid) {
1540 rc = avc_has_perm(sid, fsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 SECCLASS_FD,
1542 FD__USE,
1543 &ad);
1544 if (rc)
David Howells88e67f32008-11-14 10:39:21 +11001545 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547
1548 /* av is zero if only checking access to the descriptor. */
David Howells88e67f32008-11-14 10:39:21 +11001549 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 if (av)
Eric Paris9ade0cf2011-04-25 16:26:29 -04001551 rc = inode_has_perm(cred, inode, av, &ad, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
David Howells88e67f32008-11-14 10:39:21 +11001553out:
1554 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555}
1556
1557/* Check whether a task can create a file. */
1558static int may_create(struct inode *dir,
1559 struct dentry *dentry,
1560 u16 tclass)
1561{
Paul Moore5fb49872010-04-22 14:46:19 -04001562 const struct task_security_struct *tsec = current_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 struct inode_security_struct *dsec;
1564 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11001565 u32 sid, newsid;
Thomas Liu2bf49692009-07-14 12:14:09 -04001566 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 int rc;
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 dsec = dir->i_security;
1570 sbsec = dir->i_sb->s_security;
1571
David Howells275bb412008-11-14 10:39:19 +11001572 sid = tsec->sid;
1573 newsid = tsec->create_sid;
1574
Eric Paris50c205f2012-04-04 15:01:43 -04001575 ad.type = LSM_AUDIT_DATA_DENTRY;
Eric Parisa2694342011-04-25 13:10:27 -04001576 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
David Howells275bb412008-11-14 10:39:19 +11001578 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 DIR__ADD_NAME | DIR__SEARCH,
1580 &ad);
1581 if (rc)
1582 return rc;
1583
David P. Quigleycd895962009-01-16 09:22:04 -05001584 if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
Eric Pariscb1e9222011-04-28 15:11:21 -04001585 rc = security_transition_sid(sid, dsec->sid, tclass,
1586 &dentry->d_name, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 if (rc)
1588 return rc;
1589 }
1590
David Howells275bb412008-11-14 10:39:19 +11001591 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (rc)
1593 return rc;
1594
1595 return avc_has_perm(newsid, sbsec->sid,
1596 SECCLASS_FILESYSTEM,
1597 FILESYSTEM__ASSOCIATE, &ad);
1598}
1599
Michael LeMay4eb582c2006-06-26 00:24:57 -07001600/* Check whether a task can create a key. */
1601static int may_create_key(u32 ksid,
1602 struct task_struct *ctx)
1603{
David Howells275bb412008-11-14 10:39:19 +11001604 u32 sid = task_sid(ctx);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001605
David Howells275bb412008-11-14 10:39:19 +11001606 return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
Michael LeMay4eb582c2006-06-26 00:24:57 -07001607}
1608
Eric Paris828dfe12008-04-17 13:17:49 -04001609#define MAY_LINK 0
1610#define MAY_UNLINK 1
1611#define MAY_RMDIR 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
1613/* Check whether a task can link, unlink, or rmdir a file/directory. */
1614static int may_link(struct inode *dir,
1615 struct dentry *dentry,
1616 int kind)
1617
1618{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 struct inode_security_struct *dsec, *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001620 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001621 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 u32 av;
1623 int rc;
1624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 dsec = dir->i_security;
1626 isec = dentry->d_inode->i_security;
1627
Eric Paris50c205f2012-04-04 15:01:43 -04001628 ad.type = LSM_AUDIT_DATA_DENTRY;
Eric Parisa2694342011-04-25 13:10:27 -04001629 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631 av = DIR__SEARCH;
1632 av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
David Howells275bb412008-11-14 10:39:19 +11001633 rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 if (rc)
1635 return rc;
1636
1637 switch (kind) {
1638 case MAY_LINK:
1639 av = FILE__LINK;
1640 break;
1641 case MAY_UNLINK:
1642 av = FILE__UNLINK;
1643 break;
1644 case MAY_RMDIR:
1645 av = DIR__RMDIR;
1646 break;
1647 default:
Eric Paris744ba352008-04-17 11:52:44 -04001648 printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n",
1649 __func__, kind);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 return 0;
1651 }
1652
David Howells275bb412008-11-14 10:39:19 +11001653 rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 return rc;
1655}
1656
1657static inline int may_rename(struct inode *old_dir,
1658 struct dentry *old_dentry,
1659 struct inode *new_dir,
1660 struct dentry *new_dentry)
1661{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001663 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11001664 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 u32 av;
1666 int old_is_dir, new_is_dir;
1667 int rc;
1668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 old_dsec = old_dir->i_security;
1670 old_isec = old_dentry->d_inode->i_security;
1671 old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
1672 new_dsec = new_dir->i_security;
1673
Eric Paris50c205f2012-04-04 15:01:43 -04001674 ad.type = LSM_AUDIT_DATA_DENTRY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
Eric Parisa2694342011-04-25 13:10:27 -04001676 ad.u.dentry = old_dentry;
David Howells275bb412008-11-14 10:39:19 +11001677 rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 DIR__REMOVE_NAME | DIR__SEARCH, &ad);
1679 if (rc)
1680 return rc;
David Howells275bb412008-11-14 10:39:19 +11001681 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 old_isec->sclass, FILE__RENAME, &ad);
1683 if (rc)
1684 return rc;
1685 if (old_is_dir && new_dir != old_dir) {
David Howells275bb412008-11-14 10:39:19 +11001686 rc = avc_has_perm(sid, old_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 old_isec->sclass, DIR__REPARENT, &ad);
1688 if (rc)
1689 return rc;
1690 }
1691
Eric Parisa2694342011-04-25 13:10:27 -04001692 ad.u.dentry = new_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 av = DIR__ADD_NAME | DIR__SEARCH;
1694 if (new_dentry->d_inode)
1695 av |= DIR__REMOVE_NAME;
David Howells275bb412008-11-14 10:39:19 +11001696 rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 if (rc)
1698 return rc;
1699 if (new_dentry->d_inode) {
1700 new_isec = new_dentry->d_inode->i_security;
1701 new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
David Howells275bb412008-11-14 10:39:19 +11001702 rc = avc_has_perm(sid, new_isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 new_isec->sclass,
1704 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
1705 if (rc)
1706 return rc;
1707 }
1708
1709 return 0;
1710}
1711
1712/* Check whether a task can perform a filesystem operation. */
David Howells88e67f32008-11-14 10:39:21 +11001713static int superblock_has_perm(const struct cred *cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 struct super_block *sb,
1715 u32 perms,
Thomas Liu2bf49692009-07-14 12:14:09 -04001716 struct common_audit_data *ad)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 struct superblock_security_struct *sbsec;
David Howells88e67f32008-11-14 10:39:21 +11001719 u32 sid = cred_sid(cred);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 sbsec = sb->s_security;
David Howells275bb412008-11-14 10:39:19 +11001722 return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723}
1724
1725/* Convert a Linux mode and permission mask to an access vector. */
1726static inline u32 file_mask_to_av(int mode, int mask)
1727{
1728 u32 av = 0;
1729
Al Virodba19c62011-07-25 20:49:29 -04001730 if (!S_ISDIR(mode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 if (mask & MAY_EXEC)
1732 av |= FILE__EXECUTE;
1733 if (mask & MAY_READ)
1734 av |= FILE__READ;
1735
1736 if (mask & MAY_APPEND)
1737 av |= FILE__APPEND;
1738 else if (mask & MAY_WRITE)
1739 av |= FILE__WRITE;
1740
1741 } else {
1742 if (mask & MAY_EXEC)
1743 av |= DIR__SEARCH;
1744 if (mask & MAY_WRITE)
1745 av |= DIR__WRITE;
1746 if (mask & MAY_READ)
1747 av |= DIR__READ;
1748 }
1749
1750 return av;
1751}
1752
1753/* Convert a Linux file to an access vector. */
1754static inline u32 file_to_av(struct file *file)
1755{
1756 u32 av = 0;
1757
1758 if (file->f_mode & FMODE_READ)
1759 av |= FILE__READ;
1760 if (file->f_mode & FMODE_WRITE) {
1761 if (file->f_flags & O_APPEND)
1762 av |= FILE__APPEND;
1763 else
1764 av |= FILE__WRITE;
1765 }
Stephen Smalley0794c662008-03-17 08:55:18 -04001766 if (!av) {
1767 /*
1768 * Special file opened with flags 3 for ioctl-only use.
1769 */
1770 av = FILE__IOCTL;
1771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
1773 return av;
1774}
1775
Eric Paris8b6a5a32008-10-29 17:06:46 -04001776/*
1777 * Convert a file to an access vector and include the correct open
1778 * open permission.
1779 */
1780static inline u32 open_file_to_av(struct file *file)
1781{
1782 u32 av = file_to_av(file);
1783
Eric Paris49b7b8d2010-07-23 11:44:09 -04001784 if (selinux_policycap_openperm)
1785 av |= FILE__OPEN;
1786
Eric Paris8b6a5a32008-10-29 17:06:46 -04001787 return av;
1788}
1789
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790/* Hook functions begin here. */
1791
Ingo Molnar9e488582009-05-07 19:26:19 +10001792static int selinux_ptrace_access_check(struct task_struct *child,
David Howells5cd9c582008-08-14 11:37:28 +01001793 unsigned int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 int rc;
1796
Ingo Molnar9e488582009-05-07 19:26:19 +10001797 rc = cap_ptrace_access_check(child, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 if (rc)
1799 return rc;
1800
Eric Paris69f594a2012-01-03 12:25:15 -05001801 if (mode & PTRACE_MODE_READ) {
David Howells275bb412008-11-14 10:39:19 +11001802 u32 sid = current_sid();
1803 u32 csid = task_sid(child);
1804 return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
Stephen Smalley006ebb42008-05-19 08:32:49 -04001805 }
1806
David Howells3b11a1d2008-11-14 10:39:26 +11001807 return current_has_perm(child, PROCESS__PTRACE);
David Howells5cd9c582008-08-14 11:37:28 +01001808}
1809
1810static int selinux_ptrace_traceme(struct task_struct *parent)
1811{
1812 int rc;
1813
Eric Paris200ac532009-02-12 15:01:04 -05001814 rc = cap_ptrace_traceme(parent);
David Howells5cd9c582008-08-14 11:37:28 +01001815 if (rc)
1816 return rc;
1817
1818 return task_has_perm(parent, current, PROCESS__PTRACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819}
1820
1821static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
Eric Paris828dfe12008-04-17 13:17:49 -04001822 kernel_cap_t *inheritable, kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823{
1824 int error;
1825
David Howells3b11a1d2008-11-14 10:39:26 +11001826 error = current_has_perm(target, PROCESS__GETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 if (error)
1828 return error;
1829
Eric Paris200ac532009-02-12 15:01:04 -05001830 return cap_capget(target, effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831}
1832
David Howellsd84f4f92008-11-14 10:39:23 +11001833static int selinux_capset(struct cred *new, const struct cred *old,
1834 const kernel_cap_t *effective,
1835 const kernel_cap_t *inheritable,
1836 const kernel_cap_t *permitted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837{
1838 int error;
1839
Eric Paris200ac532009-02-12 15:01:04 -05001840 error = cap_capset(new, old,
David Howellsd84f4f92008-11-14 10:39:23 +11001841 effective, inheritable, permitted);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if (error)
1843 return error;
1844
David Howellsd84f4f92008-11-14 10:39:23 +11001845 return cred_has_perm(old, new, PROCESS__SETCAP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846}
1847
James Morris5626d3e2009-01-30 10:05:06 +11001848/*
1849 * (This comment used to live with the selinux_task_setuid hook,
1850 * which was removed).
1851 *
1852 * Since setuid only affects the current process, and since the SELinux
1853 * controls are not based on the Linux identity attributes, SELinux does not
1854 * need to control this operation. However, SELinux does control the use of
1855 * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
1856 */
1857
Eric Paris6a9de492012-01-03 12:25:14 -05001858static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
1859 int cap, int audit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860{
1861 int rc;
1862
Eric Paris6a9de492012-01-03 12:25:14 -05001863 rc = cap_capable(cred, ns, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 if (rc)
1865 return rc;
1866
Eric Paris6a9de492012-01-03 12:25:14 -05001867 return cred_has_capability(cred, cap, audit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868}
1869
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
1871{
David Howells88e67f32008-11-14 10:39:21 +11001872 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 int rc = 0;
1874
1875 if (!sb)
1876 return 0;
1877
1878 switch (cmds) {
Eric Paris828dfe12008-04-17 13:17:49 -04001879 case Q_SYNC:
1880 case Q_QUOTAON:
1881 case Q_QUOTAOFF:
1882 case Q_SETINFO:
1883 case Q_SETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001884 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001885 break;
1886 case Q_GETFMT:
1887 case Q_GETINFO:
1888 case Q_GETQUOTA:
David Howells88e67f32008-11-14 10:39:21 +11001889 rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
Eric Paris828dfe12008-04-17 13:17:49 -04001890 break;
1891 default:
1892 rc = 0; /* let the kernel handle invalid cmds */
1893 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895 return rc;
1896}
1897
1898static int selinux_quota_on(struct dentry *dentry)
1899{
David Howells88e67f32008-11-14 10:39:21 +11001900 const struct cred *cred = current_cred();
1901
Eric Paris2875fa02011-04-28 16:04:24 -04001902 return dentry_has_perm(cred, dentry, FILE__QUOTAON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903}
1904
Eric Paris12b30522010-11-15 18:36:29 -05001905static int selinux_syslog(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906{
1907 int rc;
1908
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 switch (type) {
Kees Cookd78ca3c2010-02-03 15:37:13 -08001910 case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
1911 case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001912 rc = task_has_system(current, SYSTEM__SYSLOG_READ);
1913 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001914 case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
1915 case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
1916 /* Set level of messages printed to console */
1917 case SYSLOG_ACTION_CONSOLE_LEVEL:
Eric Paris828dfe12008-04-17 13:17:49 -04001918 rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
1919 break;
Kees Cookd78ca3c2010-02-03 15:37:13 -08001920 case SYSLOG_ACTION_CLOSE: /* Close log */
1921 case SYSLOG_ACTION_OPEN: /* Open log */
1922 case SYSLOG_ACTION_READ: /* Read from log */
1923 case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */
1924 case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */
Eric Paris828dfe12008-04-17 13:17:49 -04001925 default:
1926 rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
1927 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929 return rc;
1930}
1931
1932/*
1933 * Check that a process has enough memory to allocate a new virtual
1934 * mapping. 0 means there is enough memory for the allocation to
1935 * succeed and -ENOMEM implies there is not.
1936 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 * Do not audit the selinux permission check, as this is applied to all
1938 * processes that allocate mappings.
1939 */
Alan Cox34b4e4a2007-08-22 14:01:28 -07001940static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941{
1942 int rc, cap_sys_admin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
Eric Paris6a9de492012-01-03 12:25:14 -05001944 rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00001945 SECURITY_CAP_NOAUDIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 if (rc == 0)
1947 cap_sys_admin = 1;
1948
Alan Cox34b4e4a2007-08-22 14:01:28 -07001949 return __vm_enough_memory(mm, pages, cap_sys_admin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950}
1951
1952/* binprm security operations */
1953
David Howellsa6f76f22008-11-14 10:39:24 +11001954static int selinux_bprm_set_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
David Howellsa6f76f22008-11-14 10:39:24 +11001956 const struct task_security_struct *old_tsec;
1957 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 struct inode_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04001959 struct common_audit_data ad;
David Howellsa6f76f22008-11-14 10:39:24 +11001960 struct inode *inode = bprm->file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 int rc;
1962
Eric Paris200ac532009-02-12 15:01:04 -05001963 rc = cap_bprm_set_creds(bprm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 if (rc)
1965 return rc;
1966
David Howellsa6f76f22008-11-14 10:39:24 +11001967 /* SELinux context only depends on initial program or script and not
1968 * the script interpreter */
1969 if (bprm->cred_prepared)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 return 0;
1971
David Howellsa6f76f22008-11-14 10:39:24 +11001972 old_tsec = current_security();
1973 new_tsec = bprm->cred->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 isec = inode->i_security;
1975
1976 /* Default to the current task SID. */
David Howellsa6f76f22008-11-14 10:39:24 +11001977 new_tsec->sid = old_tsec->sid;
1978 new_tsec->osid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979
Michael LeMay28eba5b2006-06-27 02:53:42 -07001980 /* Reset fs, key, and sock SIDs on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11001981 new_tsec->create_sid = 0;
1982 new_tsec->keycreate_sid = 0;
1983 new_tsec->sockcreate_sid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
David Howellsa6f76f22008-11-14 10:39:24 +11001985 if (old_tsec->exec_sid) {
1986 new_tsec->sid = old_tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 /* Reset exec SID on execve. */
David Howellsa6f76f22008-11-14 10:39:24 +11001988 new_tsec->exec_sid = 0;
Andy Lutomirski259e5e62012-04-12 16:47:50 -05001989
1990 /*
1991 * Minimize confusion: if no_new_privs and a transition is
1992 * explicitly requested, then fail the exec.
1993 */
1994 if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
1995 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 } else {
1997 /* Check for a default transition on this program. */
David Howellsa6f76f22008-11-14 10:39:24 +11001998 rc = security_transition_sid(old_tsec->sid, isec->sid,
Eric Paris652bb9b2011-02-01 11:05:40 -05001999 SECCLASS_PROCESS, NULL,
2000 &new_tsec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 if (rc)
2002 return rc;
2003 }
2004
Eric Paris50c205f2012-04-04 15:01:43 -04002005 ad.type = LSM_AUDIT_DATA_PATH;
Eric Parisf48b7392011-04-25 12:54:27 -04002006 ad.u.path = bprm->file->f_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Andy Lutomirski259e5e62012-04-12 16:47:50 -05002008 if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
2009 (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
David Howellsa6f76f22008-11-14 10:39:24 +11002010 new_tsec->sid = old_tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
David Howellsa6f76f22008-11-14 10:39:24 +11002012 if (new_tsec->sid == old_tsec->sid) {
2013 rc = avc_has_perm(old_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
2015 if (rc)
2016 return rc;
2017 } else {
2018 /* Check permissions for the transition. */
David Howellsa6f76f22008-11-14 10:39:24 +11002019 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
2021 if (rc)
2022 return rc;
2023
David Howellsa6f76f22008-11-14 10:39:24 +11002024 rc = avc_has_perm(new_tsec->sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
2026 if (rc)
2027 return rc;
2028
David Howellsa6f76f22008-11-14 10:39:24 +11002029 /* Check for shared state */
2030 if (bprm->unsafe & LSM_UNSAFE_SHARE) {
2031 rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
2032 SECCLASS_PROCESS, PROCESS__SHARE,
2033 NULL);
2034 if (rc)
2035 return -EPERM;
2036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037
David Howellsa6f76f22008-11-14 10:39:24 +11002038 /* Make sure that anyone attempting to ptrace over a task that
2039 * changes its SID has the appropriate permit */
2040 if (bprm->unsafe &
2041 (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
2042 struct task_struct *tracer;
2043 struct task_security_struct *sec;
2044 u32 ptsid = 0;
2045
2046 rcu_read_lock();
Tejun Heo06d98472011-06-17 16:50:40 +02002047 tracer = ptrace_parent(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002048 if (likely(tracer != NULL)) {
2049 sec = __task_cred(tracer)->security;
2050 ptsid = sec->sid;
2051 }
2052 rcu_read_unlock();
2053
2054 if (ptsid != 0) {
2055 rc = avc_has_perm(ptsid, new_tsec->sid,
2056 SECCLASS_PROCESS,
2057 PROCESS__PTRACE, NULL);
2058 if (rc)
2059 return -EPERM;
2060 }
2061 }
2062
2063 /* Clear any possibly unsafe personality bits on exec: */
2064 bprm->per_clear |= PER_CLEAR_ON_SETID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 }
2066
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 return 0;
2068}
2069
Eric Paris828dfe12008-04-17 13:17:49 -04002070static int selinux_bprm_secureexec(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071{
Paul Moore5fb49872010-04-22 14:46:19 -04002072 const struct task_security_struct *tsec = current_security();
David Howells275bb412008-11-14 10:39:19 +11002073 u32 sid, osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 int atsecure = 0;
2075
David Howells275bb412008-11-14 10:39:19 +11002076 sid = tsec->sid;
2077 osid = tsec->osid;
2078
2079 if (osid != sid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 /* Enable secure mode for SIDs transitions unless
2081 the noatsecure permission is granted between
2082 the two SIDs, i.e. ahp returns 0. */
David Howells275bb412008-11-14 10:39:19 +11002083 atsecure = avc_has_perm(osid, sid,
David Howellsa6f76f22008-11-14 10:39:24 +11002084 SECCLASS_PROCESS,
2085 PROCESS__NOATSECURE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 }
2087
Eric Paris200ac532009-02-12 15:01:04 -05002088 return (atsecure || cap_bprm_secureexec(bprm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089}
2090
Al Viroc3c073f2012-08-21 22:32:06 -04002091static int match_file(const void *p, struct file *file, unsigned fd)
2092{
2093 return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0;
2094}
2095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096/* Derived from fs/exec.c:flush_old_files. */
David Howells745ca242008-11-14 10:39:22 +11002097static inline void flush_unauthorized_files(const struct cred *cred,
2098 struct files_struct *files)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 struct file *file, *devnull = NULL;
Stephen Smalleyb20c8122006-09-25 23:32:03 -07002101 struct tty_struct *tty;
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002102 int drop_tty = 0;
Al Viroc3c073f2012-08-21 22:32:06 -04002103 unsigned n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002105 tty = get_current_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 if (tty) {
Nick Pigginee2ffa02010-08-18 04:37:35 +10002107 spin_lock(&tty_files_lock);
Eric Paris37dd0bd2008-10-31 17:40:00 -04002108 if (!list_empty(&tty->tty_files)) {
Nick Piggind996b622010-08-18 04:37:36 +10002109 struct tty_file_private *file_priv;
Eric Paris37dd0bd2008-10-31 17:40:00 -04002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 /* Revalidate access to controlling tty.
Eric Paris602a8dd2012-04-04 15:01:42 -04002112 Use path_has_perm on the tty path directly rather
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 than using file_has_perm, as this particular open
2114 file may belong to another process and we are only
2115 interested in the inode-based check here. */
Nick Piggind996b622010-08-18 04:37:36 +10002116 file_priv = list_first_entry(&tty->tty_files,
2117 struct tty_file_private, list);
2118 file = file_priv->file;
Eric Paris602a8dd2012-04-04 15:01:42 -04002119 if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
Peter Zijlstra24ec8392006-12-08 02:36:04 -08002120 drop_tty = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 }
Nick Pigginee2ffa02010-08-18 04:37:35 +10002122 spin_unlock(&tty_files_lock);
Alan Cox452a00d2008-10-13 10:39:13 +01002123 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 }
Eric W. Biederman98a27ba2007-05-08 00:26:56 -07002125 /* Reset controlling tty. */
2126 if (drop_tty)
2127 no_tty();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
2129 /* Revalidate access to inherited open files. */
Al Viroc3c073f2012-08-21 22:32:06 -04002130 n = iterate_fd(files, 0, match_file, cred);
2131 if (!n) /* none found? */
2132 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Al Viroc3c073f2012-08-21 22:32:06 -04002134 devnull = dentry_open(&selinux_null, O_RDWR, cred);
2135 if (!IS_ERR(devnull)) {
2136 /* replace all the matching ones with this */
2137 do {
Al Virocb0942b2012-08-27 14:48:26 -04002138 replace_fd(n - 1, get_file(devnull), 0);
Al Viroc3c073f2012-08-21 22:32:06 -04002139 } while ((n = iterate_fd(files, n, match_file, cred)) != 0);
2140 fput(devnull);
2141 } else {
2142 /* just close all the matching ones */
2143 do {
2144 replace_fd(n - 1, NULL, 0);
2145 } while ((n = iterate_fd(files, n, match_file, cred)) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147}
2148
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149/*
David Howellsa6f76f22008-11-14 10:39:24 +11002150 * Prepare a process for imminent new credential changes due to exec
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 */
David Howellsa6f76f22008-11-14 10:39:24 +11002152static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{
David Howellsa6f76f22008-11-14 10:39:24 +11002154 struct task_security_struct *new_tsec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 struct rlimit *rlim, *initrlim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 int rc, i;
2157
David Howellsa6f76f22008-11-14 10:39:24 +11002158 new_tsec = bprm->cred->security;
2159 if (new_tsec->sid == new_tsec->osid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 return;
2161
2162 /* Close files for which the new task SID is not authorized. */
David Howellsa6f76f22008-11-14 10:39:24 +11002163 flush_unauthorized_files(bprm->cred, current->files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
David Howellsa6f76f22008-11-14 10:39:24 +11002165 /* Always clear parent death signal on SID transitions. */
2166 current->pdeath_signal = 0;
2167
2168 /* Check whether the new SID can inherit resource limits from the old
2169 * SID. If not, reset all soft limits to the lower of the current
2170 * task's hard limit and the init task's soft limit.
2171 *
2172 * Note that the setting of hard limits (even to lower them) can be
2173 * controlled by the setrlimit check. The inclusion of the init task's
2174 * soft limit into the computation is to avoid resetting soft limits
2175 * higher than the default soft limit for cases where the default is
2176 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2177 */
2178 rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2179 PROCESS__RLIMITINH, NULL);
2180 if (rc) {
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002181 /* protect against do_prlimit() */
2182 task_lock(current);
David Howellsa6f76f22008-11-14 10:39:24 +11002183 for (i = 0; i < RLIM_NLIMITS; i++) {
2184 rlim = current->signal->rlim + i;
2185 initrlim = init_task.signal->rlim + i;
2186 rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2187 }
Oleg Nesteroveb2d55a2010-06-23 22:43:32 +02002188 task_unlock(current);
2189 update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
David Howellsa6f76f22008-11-14 10:39:24 +11002190 }
2191}
2192
2193/*
2194 * Clean up the process immediately after the installation of new credentials
2195 * due to exec
2196 */
2197static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2198{
2199 const struct task_security_struct *tsec = current_security();
2200 struct itimerval itimer;
David Howellsa6f76f22008-11-14 10:39:24 +11002201 u32 osid, sid;
2202 int rc, i;
David Howellsa6f76f22008-11-14 10:39:24 +11002203
David Howellsa6f76f22008-11-14 10:39:24 +11002204 osid = tsec->osid;
2205 sid = tsec->sid;
2206
2207 if (sid == osid)
2208 return;
2209
2210 /* Check whether the new SID can inherit signal state from the old SID.
2211 * If not, clear itimers to avoid subsequent signal generation and
2212 * flush and unblock signals.
2213 *
2214 * This must occur _after_ the task SID has been updated so that any
2215 * kill done after the flush will be checked against the new SID.
2216 */
2217 rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 if (rc) {
2219 memset(&itimer, 0, sizeof itimer);
2220 for (i = 0; i < 3; i++)
2221 do_setitimer(i, &itimer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 spin_lock_irq(&current->sighand->siglock);
David Howells3bcac022009-04-29 13:45:05 +01002223 if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
2224 __flush_signals(current);
2225 flush_signal_handlers(current, 1);
2226 sigemptyset(&current->blocked);
2227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 spin_unlock_irq(&current->sighand->siglock);
2229 }
2230
David Howellsa6f76f22008-11-14 10:39:24 +11002231 /* Wake up the parent if it is waiting so that it can recheck
2232 * wait permission to the new task SID. */
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002233 read_lock(&tasklist_lock);
Oleg Nesterov0b7570e2009-09-23 15:56:46 -07002234 __wake_up_parent(current, current->real_parent);
Oleg Nesterovecd6de32009-04-29 16:02:24 +02002235 read_unlock(&tasklist_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236}
2237
2238/* superblock security operations */
2239
2240static int selinux_sb_alloc_security(struct super_block *sb)
2241{
2242 return superblock_alloc_security(sb);
2243}
2244
2245static void selinux_sb_free_security(struct super_block *sb)
2246{
2247 superblock_free_security(sb);
2248}
2249
2250static inline int match_prefix(char *prefix, int plen, char *option, int olen)
2251{
2252 if (plen > olen)
2253 return 0;
2254
2255 return !memcmp(prefix, option, plen);
2256}
2257
2258static inline int selinux_option(char *option, int len)
2259{
Eric Paris832cbd92008-04-01 13:24:09 -04002260 return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2261 match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2262 match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
David P. Quigley11689d42009-01-16 09:22:03 -05002263 match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
2264 match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265}
2266
2267static inline void take_option(char **to, char *from, int *first, int len)
2268{
2269 if (!*first) {
2270 **to = ',';
2271 *to += 1;
Cory Olmo3528a952006-09-29 01:58:44 -07002272 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 *first = 0;
2274 memcpy(*to, from, len);
2275 *to += len;
2276}
2277
Eric Paris828dfe12008-04-17 13:17:49 -04002278static inline void take_selinux_option(char **to, char *from, int *first,
2279 int len)
Cory Olmo3528a952006-09-29 01:58:44 -07002280{
2281 int current_size = 0;
2282
2283 if (!*first) {
2284 **to = '|';
2285 *to += 1;
Eric Paris828dfe12008-04-17 13:17:49 -04002286 } else
Cory Olmo3528a952006-09-29 01:58:44 -07002287 *first = 0;
2288
2289 while (current_size < len) {
2290 if (*from != '"') {
2291 **to = *from;
2292 *to += 1;
2293 }
2294 from += 1;
2295 current_size += 1;
2296 }
2297}
2298
Eric Parise0007522008-03-05 10:31:54 -05002299static int selinux_sb_copy_data(char *orig, char *copy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300{
2301 int fnosec, fsec, rc = 0;
2302 char *in_save, *in_curr, *in_end;
2303 char *sec_curr, *nosec_save, *nosec;
Cory Olmo3528a952006-09-29 01:58:44 -07002304 int open_quote = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
2306 in_curr = orig;
2307 sec_curr = copy;
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 nosec = (char *)get_zeroed_page(GFP_KERNEL);
2310 if (!nosec) {
2311 rc = -ENOMEM;
2312 goto out;
2313 }
2314
2315 nosec_save = nosec;
2316 fnosec = fsec = 1;
2317 in_save = in_end = orig;
2318
2319 do {
Cory Olmo3528a952006-09-29 01:58:44 -07002320 if (*in_end == '"')
2321 open_quote = !open_quote;
2322 if ((*in_end == ',' && open_quote == 0) ||
2323 *in_end == '\0') {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 int len = in_end - in_curr;
2325
2326 if (selinux_option(in_curr, len))
Cory Olmo3528a952006-09-29 01:58:44 -07002327 take_selinux_option(&sec_curr, in_curr, &fsec, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 else
2329 take_option(&nosec, in_curr, &fnosec, len);
2330
2331 in_curr = in_end + 1;
2332 }
2333 } while (*in_end++);
2334
Eric Paris6931dfc2005-06-30 02:58:51 -07002335 strcpy(in_save, nosec_save);
Gerald Schaeferda3caa22005-06-21 17:15:18 -07002336 free_page((unsigned long)nosec_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337out:
2338 return rc;
2339}
2340
Eric Paris026eb162011-03-03 16:09:14 -05002341static int selinux_sb_remount(struct super_block *sb, void *data)
2342{
2343 int rc, i, *flags;
2344 struct security_mnt_opts opts;
2345 char *secdata, **mount_options;
2346 struct superblock_security_struct *sbsec = sb->s_security;
2347
2348 if (!(sbsec->flags & SE_SBINITIALIZED))
2349 return 0;
2350
2351 if (!data)
2352 return 0;
2353
2354 if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
2355 return 0;
2356
2357 security_init_mnt_opts(&opts);
2358 secdata = alloc_secdata();
2359 if (!secdata)
2360 return -ENOMEM;
2361 rc = selinux_sb_copy_data(data, secdata);
2362 if (rc)
2363 goto out_free_secdata;
2364
2365 rc = selinux_parse_opts_str(secdata, &opts);
2366 if (rc)
2367 goto out_free_secdata;
2368
2369 mount_options = opts.mnt_opts;
2370 flags = opts.mnt_opts_flags;
2371
2372 for (i = 0; i < opts.num_mnt_opts; i++) {
2373 u32 sid;
2374 size_t len;
2375
2376 if (flags[i] == SE_SBLABELSUPP)
2377 continue;
2378 len = strlen(mount_options[i]);
2379 rc = security_context_to_sid(mount_options[i], len, &sid);
2380 if (rc) {
2381 printk(KERN_WARNING "SELinux: security_context_to_sid"
2382 "(%s) failed for (dev %s, type %s) errno=%d\n",
2383 mount_options[i], sb->s_id, sb->s_type->name, rc);
2384 goto out_free_opts;
2385 }
2386 rc = -EINVAL;
2387 switch (flags[i]) {
2388 case FSCONTEXT_MNT:
2389 if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2390 goto out_bad_option;
2391 break;
2392 case CONTEXT_MNT:
2393 if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2394 goto out_bad_option;
2395 break;
2396 case ROOTCONTEXT_MNT: {
2397 struct inode_security_struct *root_isec;
2398 root_isec = sb->s_root->d_inode->i_security;
2399
2400 if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2401 goto out_bad_option;
2402 break;
2403 }
2404 case DEFCONTEXT_MNT:
2405 if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2406 goto out_bad_option;
2407 break;
2408 default:
2409 goto out_free_opts;
2410 }
2411 }
2412
2413 rc = 0;
2414out_free_opts:
2415 security_free_mnt_opts(&opts);
2416out_free_secdata:
2417 free_secdata(secdata);
2418 return rc;
2419out_bad_option:
2420 printk(KERN_WARNING "SELinux: unable to change security options "
2421 "during remount (dev %s, type=%s)\n", sb->s_id,
2422 sb->s_type->name);
2423 goto out_free_opts;
2424}
2425
James Morris12204e22008-12-19 10:44:42 +11002426static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427{
David Howells88e67f32008-11-14 10:39:21 +11002428 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002429 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 int rc;
2431
2432 rc = superblock_doinit(sb, data);
2433 if (rc)
2434 return rc;
2435
James Morris74192242008-12-19 11:41:10 +11002436 /* Allow all mounts performed by the kernel */
2437 if (flags & MS_KERNMOUNT)
2438 return 0;
2439
Eric Paris50c205f2012-04-04 15:01:43 -04002440 ad.type = LSM_AUDIT_DATA_DENTRY;
Eric Parisa2694342011-04-25 13:10:27 -04002441 ad.u.dentry = sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002442 return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443}
2444
David Howells726c3342006-06-23 02:02:58 -07002445static int selinux_sb_statfs(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446{
David Howells88e67f32008-11-14 10:39:21 +11002447 const struct cred *cred = current_cred();
Thomas Liu2bf49692009-07-14 12:14:09 -04002448 struct common_audit_data ad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
Eric Paris50c205f2012-04-04 15:01:43 -04002450 ad.type = LSM_AUDIT_DATA_DENTRY;
Eric Parisa2694342011-04-25 13:10:27 -04002451 ad.u.dentry = dentry->d_sb->s_root;
David Howells88e67f32008-11-14 10:39:21 +11002452 return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453}
2454
Al Viro808d4e32012-10-11 11:42:01 -04002455static int selinux_mount(const char *dev_name,
Al Virob5266eb2008-03-22 17:48:24 -04002456 struct path *path,
Al Viro808d4e32012-10-11 11:42:01 -04002457 const char *type,
Eric Paris828dfe12008-04-17 13:17:49 -04002458 unsigned long flags,
2459 void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460{
David Howells88e67f32008-11-14 10:39:21 +11002461 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
2463 if (flags & MS_REMOUNT)
Al Virod8c95842011-12-07 18:16:57 -05002464 return superblock_has_perm(cred, path->dentry->d_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002465 FILESYSTEM__REMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 else
Eric Paris2875fa02011-04-28 16:04:24 -04002467 return path_has_perm(cred, path, FILE__MOUNTON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468}
2469
2470static int selinux_umount(struct vfsmount *mnt, int flags)
2471{
David Howells88e67f32008-11-14 10:39:21 +11002472 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473
David Howells88e67f32008-11-14 10:39:21 +11002474 return superblock_has_perm(cred, mnt->mnt_sb,
Eric Paris828dfe12008-04-17 13:17:49 -04002475 FILESYSTEM__UNMOUNT, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476}
2477
2478/* inode security operations */
2479
2480static int selinux_inode_alloc_security(struct inode *inode)
2481{
2482 return inode_alloc_security(inode);
2483}
2484
2485static void selinux_inode_free_security(struct inode *inode)
2486{
2487 inode_free_security(inode);
2488}
2489
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002490static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
Eric Paris2a7dba32011-02-01 11:05:39 -05002491 const struct qstr *qstr, char **name,
2492 void **value, size_t *len)
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002493{
Paul Moore5fb49872010-04-22 14:46:19 -04002494 const struct task_security_struct *tsec = current_security();
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002495 struct inode_security_struct *dsec;
2496 struct superblock_security_struct *sbsec;
David Howells275bb412008-11-14 10:39:19 +11002497 u32 sid, newsid, clen;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002498 int rc;
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002499 char *namep = NULL, *context;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002500
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002501 dsec = dir->i_security;
2502 sbsec = dir->i_sb->s_security;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002503
David Howells275bb412008-11-14 10:39:19 +11002504 sid = tsec->sid;
2505 newsid = tsec->create_sid;
2506
Eric Paris415103f2010-12-02 16:13:40 -05002507 if ((sbsec->flags & SE_SBINITIALIZED) &&
2508 (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
2509 newsid = sbsec->mntpoint_sid;
2510 else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
David Howells275bb412008-11-14 10:39:19 +11002511 rc = security_transition_sid(sid, dsec->sid,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002512 inode_mode_to_security_class(inode->i_mode),
Eric Paris652bb9b2011-02-01 11:05:40 -05002513 qstr, &newsid);
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002514 if (rc) {
2515 printk(KERN_WARNING "%s: "
2516 "security_transition_sid failed, rc=%d (dev=%s "
2517 "ino=%ld)\n",
Harvey Harrisondd6f9532008-03-06 10:03:59 +11002518 __func__,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002519 -rc, inode->i_sb->s_id, inode->i_ino);
2520 return rc;
2521 }
2522 }
2523
Eric Paris296fddf2006-09-25 23:32:00 -07002524 /* Possibly defer initialization to selinux_complete_init. */
David P. Quigley0d90a7e2009-01-16 09:22:02 -05002525 if (sbsec->flags & SE_SBINITIALIZED) {
Eric Paris296fddf2006-09-25 23:32:00 -07002526 struct inode_security_struct *isec = inode->i_security;
2527 isec->sclass = inode_mode_to_security_class(inode->i_mode);
2528 isec->sid = newsid;
2529 isec->initialized = 1;
2530 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002531
David P. Quigleycd895962009-01-16 09:22:04 -05002532 if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
Stephen Smalley25a74f32005-11-08 21:34:33 -08002533 return -EOPNOTSUPP;
2534
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002535 if (name) {
Josef Bacika02fe132008-04-04 09:35:05 +11002536 namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002537 if (!namep)
2538 return -ENOMEM;
2539 *name = namep;
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002540 }
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002541
2542 if (value && len) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002543 rc = security_sid_to_context_force(newsid, &context, &clen);
Stephen Smalley570bc1c2005-09-09 13:01:43 -07002544 if (rc) {
2545 kfree(namep);
2546 return rc;
2547 }
2548 *value = context;
2549 *len = clen;
2550 }
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002551
Stephen Smalley5e41ff92005-09-09 13:01:35 -07002552 return 0;
2553}
2554
Al Viro4acdaf22011-07-26 01:42:34 -04002555static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
2557 return may_create(dir, dentry, SECCLASS_FILE);
2558}
2559
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2561{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 return may_link(dir, old_dentry, MAY_LINK);
2563}
2564
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
2566{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 return may_link(dir, dentry, MAY_UNLINK);
2568}
2569
2570static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
2571{
2572 return may_create(dir, dentry, SECCLASS_LNK_FILE);
2573}
2574
Al Viro18bb1db2011-07-26 01:41:39 -04002575static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576{
2577 return may_create(dir, dentry, SECCLASS_DIR);
2578}
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
2581{
2582 return may_link(dir, dentry, MAY_RMDIR);
2583}
2584
Al Viro1a67aaf2011-07-26 01:52:52 -04002585static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 return may_create(dir, dentry, inode_mode_to_security_class(mode));
2588}
2589
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
Eric Paris828dfe12008-04-17 13:17:49 -04002591 struct inode *new_inode, struct dentry *new_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592{
2593 return may_rename(old_inode, old_dentry, new_inode, new_dentry);
2594}
2595
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596static int selinux_inode_readlink(struct dentry *dentry)
2597{
David Howells88e67f32008-11-14 10:39:21 +11002598 const struct cred *cred = current_cred();
2599
Eric Paris2875fa02011-04-28 16:04:24 -04002600 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601}
2602
2603static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
2604{
David Howells88e67f32008-11-14 10:39:21 +11002605 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Eric Paris2875fa02011-04-28 16:04:24 -04002607 return dentry_has_perm(cred, dentry, FILE__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608}
2609
Eric Parisd4cf970d2012-04-04 15:01:42 -04002610static noinline int audit_inode_permission(struct inode *inode,
2611 u32 perms, u32 audited, u32 denied,
2612 unsigned flags)
2613{
2614 struct common_audit_data ad;
Eric Parisd4cf970d2012-04-04 15:01:42 -04002615 struct inode_security_struct *isec = inode->i_security;
2616 int rc;
2617
Eric Paris50c205f2012-04-04 15:01:43 -04002618 ad.type = LSM_AUDIT_DATA_INODE;
Eric Parisd4cf970d2012-04-04 15:01:42 -04002619 ad.u.inode = inode;
2620
2621 rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
2622 audited, denied, &ad, flags);
2623 if (rc)
2624 return rc;
2625 return 0;
2626}
2627
Al Viroe74f71e2011-06-20 19:38:15 -04002628static int selinux_inode_permission(struct inode *inode, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629{
David Howells88e67f32008-11-14 10:39:21 +11002630 const struct cred *cred = current_cred();
Eric Parisb782e0a2010-07-23 11:44:03 -04002631 u32 perms;
2632 bool from_access;
Al Virocf1dd1d2011-06-20 19:44:08 -04002633 unsigned flags = mask & MAY_NOT_BLOCK;
Eric Paris2e334052012-04-04 15:01:42 -04002634 struct inode_security_struct *isec;
2635 u32 sid;
2636 struct av_decision avd;
2637 int rc, rc2;
2638 u32 audited, denied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
Eric Parisb782e0a2010-07-23 11:44:03 -04002640 from_access = mask & MAY_ACCESS;
Eric Parisd09ca732010-07-23 11:43:57 -04002641 mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
2642
Eric Parisb782e0a2010-07-23 11:44:03 -04002643 /* No permission to check. Existence test. */
2644 if (!mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
Eric Paris2e334052012-04-04 15:01:42 -04002647 validate_creds(cred);
Eric Parisb782e0a2010-07-23 11:44:03 -04002648
Eric Paris2e334052012-04-04 15:01:42 -04002649 if (unlikely(IS_PRIVATE(inode)))
2650 return 0;
Eric Parisb782e0a2010-07-23 11:44:03 -04002651
2652 perms = file_mask_to_av(inode->i_mode, mask);
2653
Eric Paris2e334052012-04-04 15:01:42 -04002654 sid = cred_sid(cred);
2655 isec = inode->i_security;
2656
2657 rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
2658 audited = avc_audit_required(perms, &avd, rc,
2659 from_access ? FILE__AUDIT_ACCESS : 0,
2660 &denied);
2661 if (likely(!audited))
2662 return rc;
2663
Eric Parisd4cf970d2012-04-04 15:01:42 -04002664 rc2 = audit_inode_permission(inode, perms, audited, denied, flags);
Eric Paris2e334052012-04-04 15:01:42 -04002665 if (rc2)
2666 return rc2;
2667 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668}
2669
2670static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
2671{
David Howells88e67f32008-11-14 10:39:21 +11002672 const struct cred *cred = current_cred();
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002673 unsigned int ia_valid = iattr->ia_valid;
Eric Paris95dbf732012-04-04 13:45:34 -04002674 __u32 av = FILE__WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002676 /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
2677 if (ia_valid & ATTR_FORCE) {
2678 ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
2679 ATTR_FORCE);
2680 if (!ia_valid)
2681 return 0;
2682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
Amerigo Wangbc6a6002009-08-20 19:29:02 -07002684 if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
2685 ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
Eric Paris2875fa02011-04-28 16:04:24 -04002686 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
Eric Paris3d2195c2012-07-06 14:13:30 -04002688 if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
Eric Paris95dbf732012-04-04 13:45:34 -04002689 av |= FILE__OPEN;
2690
2691 return dentry_has_perm(cred, dentry, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692}
2693
2694static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
2695{
David Howells88e67f32008-11-14 10:39:21 +11002696 const struct cred *cred = current_cred();
Eric Paris2875fa02011-04-28 16:04:24 -04002697 struct path path;
David Howells88e67f32008-11-14 10:39:21 +11002698
Eric Paris2875fa02011-04-28 16:04:24 -04002699 path.dentry = dentry;
2700 path.mnt = mnt;
2701
2702 return path_has_perm(cred, &path, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703}
2704
David Howells8f0cfa52008-04-29 00:59:41 -07002705static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
Serge E. Hallynb5376772007-10-16 23:31:36 -07002706{
David Howells88e67f32008-11-14 10:39:21 +11002707 const struct cred *cred = current_cred();
2708
Serge E. Hallynb5376772007-10-16 23:31:36 -07002709 if (!strncmp(name, XATTR_SECURITY_PREFIX,
2710 sizeof XATTR_SECURITY_PREFIX - 1)) {
2711 if (!strcmp(name, XATTR_NAME_CAPS)) {
2712 if (!capable(CAP_SETFCAP))
2713 return -EPERM;
2714 } else if (!capable(CAP_SYS_ADMIN)) {
2715 /* A different attribute in the security namespace.
2716 Restrict to administrator. */
2717 return -EPERM;
2718 }
2719 }
2720
2721 /* Not an attribute we recognize, so just check the
2722 ordinary setattr permission. */
Eric Paris2875fa02011-04-28 16:04:24 -04002723 return dentry_has_perm(cred, dentry, FILE__SETATTR);
Serge E. Hallynb5376772007-10-16 23:31:36 -07002724}
2725
David Howells8f0cfa52008-04-29 00:59:41 -07002726static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2727 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 struct inode *inode = dentry->d_inode;
2730 struct inode_security_struct *isec = inode->i_security;
2731 struct superblock_security_struct *sbsec;
Thomas Liu2bf49692009-07-14 12:14:09 -04002732 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11002733 u32 newsid, sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 int rc = 0;
2735
Serge E. Hallynb5376772007-10-16 23:31:36 -07002736 if (strcmp(name, XATTR_NAME_SELINUX))
2737 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
2739 sbsec = inode->i_sb->s_security;
David P. Quigleycd895962009-01-16 09:22:04 -05002740 if (!(sbsec->flags & SE_SBLABELSUPP))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 return -EOPNOTSUPP;
2742
Serge E. Hallyn2e149672011-03-23 16:43:26 -07002743 if (!inode_owner_or_capable(inode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 return -EPERM;
2745
Eric Paris50c205f2012-04-04 15:01:43 -04002746 ad.type = LSM_AUDIT_DATA_DENTRY;
Eric Parisa2694342011-04-25 13:10:27 -04002747 ad.u.dentry = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
David Howells275bb412008-11-14 10:39:19 +11002749 rc = avc_has_perm(sid, isec->sid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 FILE__RELABELFROM, &ad);
2751 if (rc)
2752 return rc;
2753
2754 rc = security_context_to_sid(value, size, &newsid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04002755 if (rc == -EINVAL) {
Eric Parisd6ea83e2012-04-04 13:45:49 -04002756 if (!capable(CAP_MAC_ADMIN)) {
2757 struct audit_buffer *ab;
2758 size_t audit_size;
2759 const char *str;
2760
2761 /* We strip a nul only if it is at the end, otherwise the
2762 * context contains a nul and we should audit that */
Al Viroe3fea3f2012-06-09 08:15:16 +01002763 if (value) {
2764 str = value;
2765 if (str[size - 1] == '\0')
2766 audit_size = size - 1;
2767 else
2768 audit_size = size;
2769 } else {
2770 str = "";
2771 audit_size = 0;
2772 }
Eric Parisd6ea83e2012-04-04 13:45:49 -04002773 ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
2774 audit_log_format(ab, "op=setxattr invalid_context=");
2775 audit_log_n_untrustedstring(ab, value, audit_size);
2776 audit_log_end(ab);
2777
Stephen Smalley12b29f32008-05-07 13:03:20 -04002778 return rc;
Eric Parisd6ea83e2012-04-04 13:45:49 -04002779 }
Stephen Smalley12b29f32008-05-07 13:03:20 -04002780 rc = security_context_to_sid_force(value, size, &newsid);
2781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 if (rc)
2783 return rc;
2784
David Howells275bb412008-11-14 10:39:19 +11002785 rc = avc_has_perm(sid, newsid, isec->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 FILE__RELABELTO, &ad);
2787 if (rc)
2788 return rc;
2789
David Howells275bb412008-11-14 10:39:19 +11002790 rc = security_validate_transition(isec->sid, newsid, sid,
Eric Paris828dfe12008-04-17 13:17:49 -04002791 isec->sclass);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 if (rc)
2793 return rc;
2794
2795 return avc_has_perm(newsid,
2796 sbsec->sid,
2797 SECCLASS_FILESYSTEM,
2798 FILESYSTEM__ASSOCIATE,
2799 &ad);
2800}
2801
David Howells8f0cfa52008-04-29 00:59:41 -07002802static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
Eric Parisf5269712008-05-14 11:27:45 -04002803 const void *value, size_t size,
David Howells8f0cfa52008-04-29 00:59:41 -07002804 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805{
2806 struct inode *inode = dentry->d_inode;
2807 struct inode_security_struct *isec = inode->i_security;
2808 u32 newsid;
2809 int rc;
2810
2811 if (strcmp(name, XATTR_NAME_SELINUX)) {
2812 /* Not an attribute we recognize, so nothing to do. */
2813 return;
2814 }
2815
Stephen Smalley12b29f32008-05-07 13:03:20 -04002816 rc = security_context_to_sid_force(value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 if (rc) {
Stephen Smalley12b29f32008-05-07 13:03:20 -04002818 printk(KERN_ERR "SELinux: unable to map context to SID"
2819 "for (%s, %lu), rc=%d\n",
2820 inode->i_sb->s_id, inode->i_ino, -rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 return;
2822 }
2823
2824 isec->sid = newsid;
2825 return;
2826}
2827
David Howells8f0cfa52008-04-29 00:59:41 -07002828static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
David Howells88e67f32008-11-14 10:39:21 +11002830 const struct cred *cred = current_cred();
2831
Eric Paris2875fa02011-04-28 16:04:24 -04002832 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833}
2834
Eric Paris828dfe12008-04-17 13:17:49 -04002835static int selinux_inode_listxattr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836{
David Howells88e67f32008-11-14 10:39:21 +11002837 const struct cred *cred = current_cred();
2838
Eric Paris2875fa02011-04-28 16:04:24 -04002839 return dentry_has_perm(cred, dentry, FILE__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840}
2841
David Howells8f0cfa52008-04-29 00:59:41 -07002842static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843{
Serge E. Hallynb5376772007-10-16 23:31:36 -07002844 if (strcmp(name, XATTR_NAME_SELINUX))
2845 return selinux_inode_setotherxattr(dentry, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846
2847 /* No one is allowed to remove a SELinux security label.
2848 You can change the label, but all data must be labeled. */
2849 return -EACCES;
2850}
2851
James Morrisd381d8a2005-10-30 14:59:22 -08002852/*
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002853 * Copy the inode security context value to the user.
James Morrisd381d8a2005-10-30 14:59:22 -08002854 *
2855 * Permission check is handled by selinux_inode_getxattr hook.
2856 */
David P. Quigley42492592008-02-04 22:29:39 -08002857static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858{
David P. Quigley42492592008-02-04 22:29:39 -08002859 u32 size;
2860 int error;
2861 char *context = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 struct inode_security_struct *isec = inode->i_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00002864 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2865 return -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002867 /*
2868 * If the caller has CAP_MAC_ADMIN, then get the raw context
2869 * value even if it is not defined by current policy; otherwise,
2870 * use the in-core value under current policy.
2871 * Use the non-auditing forms of the permission checks since
2872 * getxattr may be called by unprivileged processes commonly
2873 * and lack of permission just means that we fall back to the
2874 * in-core context value, not a denial.
2875 */
Eric Paris6a9de492012-01-03 12:25:14 -05002876 error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
David Howells3699c532009-01-06 22:27:01 +00002877 SECURITY_CAP_NOAUDIT);
Stephen Smalleyabc69bb2008-05-21 14:16:12 -04002878 if (!error)
2879 error = security_sid_to_context_force(isec->sid, &context,
2880 &size);
2881 else
2882 error = security_sid_to_context(isec->sid, &context, &size);
David P. Quigley42492592008-02-04 22:29:39 -08002883 if (error)
2884 return error;
2885 error = size;
2886 if (alloc) {
2887 *buffer = context;
2888 goto out_nofree;
2889 }
2890 kfree(context);
2891out_nofree:
2892 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893}
2894
2895static int selinux_inode_setsecurity(struct inode *inode, const char *name,
Eric Paris828dfe12008-04-17 13:17:49 -04002896 const void *value, size_t size, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897{
2898 struct inode_security_struct *isec = inode->i_security;
2899 u32 newsid;
2900 int rc;
2901
2902 if (strcmp(name, XATTR_SELINUX_SUFFIX))
2903 return -EOPNOTSUPP;
2904
2905 if (!value || !size)
2906 return -EACCES;
2907
Eric Paris828dfe12008-04-17 13:17:49 -04002908 rc = security_context_to_sid((void *)value, size, &newsid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 if (rc)
2910 return rc;
2911
2912 isec->sid = newsid;
David P. Quigleyddd29ec2009-09-09 14:25:37 -04002913 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 return 0;
2915}
2916
2917static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
2918{
2919 const int len = sizeof(XATTR_NAME_SELINUX);
2920 if (buffer && len <= buffer_size)
2921 memcpy(buffer, XATTR_NAME_SELINUX, len);
2922 return len;
2923}
2924
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02002925static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2926{
2927 struct inode_security_struct *isec = inode->i_security;
2928 *secid = isec->sid;
2929}
2930
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931/* file security operations */
2932
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002933static int selinux_revalidate_file_permission(struct file *file, int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934{
David Howells88e67f32008-11-14 10:39:21 +11002935 const struct cred *cred = current_cred();
Josef Sipek3d5ff522006-12-08 02:37:38 -08002936 struct inode *inode = file->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
2939 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2940 mask |= MAY_APPEND;
2941
Paul Moore389fb8002009-03-27 17:10:34 -04002942 return file_has_perm(cred, file,
2943 file_mask_to_av(inode->i_mode, mask));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944}
2945
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002946static int selinux_file_permission(struct file *file, int mask)
2947{
Stephen Smalley20dda182009-06-22 14:54:53 -04002948 struct inode *inode = file->f_path.dentry->d_inode;
2949 struct file_security_struct *fsec = file->f_security;
2950 struct inode_security_struct *isec = inode->i_security;
2951 u32 sid = current_sid();
2952
Paul Moore389fb8002009-03-27 17:10:34 -04002953 if (!mask)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002954 /* No permission to check. Existence test. */
2955 return 0;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002956
Stephen Smalley20dda182009-06-22 14:54:53 -04002957 if (sid == fsec->sid && fsec->isid == isec->sid &&
2958 fsec->pseqno == avc_policy_seqno())
Eric Paris83d49852012-04-04 13:45:40 -04002959 /* No change since file_open check. */
Stephen Smalley20dda182009-06-22 14:54:53 -04002960 return 0;
2961
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09002962 return selinux_revalidate_file_permission(file, mask);
2963}
2964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965static int selinux_file_alloc_security(struct file *file)
2966{
2967 return file_alloc_security(file);
2968}
2969
2970static void selinux_file_free_security(struct file *file)
2971{
2972 file_free_security(file);
2973}
2974
2975static int selinux_file_ioctl(struct file *file, unsigned int cmd,
2976 unsigned long arg)
2977{
David Howells88e67f32008-11-14 10:39:21 +11002978 const struct cred *cred = current_cred();
Eric Paris0b24dcb2011-02-25 15:39:20 -05002979 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
Eric Paris0b24dcb2011-02-25 15:39:20 -05002981 switch (cmd) {
2982 case FIONREAD:
2983 /* fall through */
2984 case FIBMAP:
2985 /* fall through */
2986 case FIGETBSZ:
2987 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04002988 case FS_IOC_GETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05002989 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04002990 case FS_IOC_GETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05002991 error = file_has_perm(cred, file, FILE__GETATTR);
2992 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
Al Viro2f99c362012-03-23 16:04:05 -04002994 case FS_IOC_SETFLAGS:
Eric Paris0b24dcb2011-02-25 15:39:20 -05002995 /* fall through */
Al Viro2f99c362012-03-23 16:04:05 -04002996 case FS_IOC_SETVERSION:
Eric Paris0b24dcb2011-02-25 15:39:20 -05002997 error = file_has_perm(cred, file, FILE__SETATTR);
2998 break;
2999
3000 /* sys_ioctl() checks */
3001 case FIONBIO:
3002 /* fall through */
3003 case FIOASYNC:
3004 error = file_has_perm(cred, file, 0);
3005 break;
3006
3007 case KDSKBENT:
3008 case KDSKBSENT:
Eric Paris6a9de492012-01-03 12:25:14 -05003009 error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3010 SECURITY_CAP_AUDIT);
Eric Paris0b24dcb2011-02-25 15:39:20 -05003011 break;
3012
3013 /* default case assumes that the command will go
3014 * to the file's ioctl() function.
3015 */
3016 default:
3017 error = file_has_perm(cred, file, FILE__IOCTL);
3018 }
3019 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020}
3021
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003022static int default_noexec;
3023
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3025{
David Howells88e67f32008-11-14 10:39:21 +11003026 const struct cred *cred = current_cred();
David Howellsd84f4f92008-11-14 10:39:23 +11003027 int rc = 0;
David Howells88e67f32008-11-14 10:39:21 +11003028
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003029 if (default_noexec &&
3030 (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 /*
3032 * We are making executable an anonymous mapping or a
3033 * private file mapping that will also be writable.
3034 * This has an additional check.
3035 */
David Howellsd84f4f92008-11-14 10:39:23 +11003036 rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 if (rc)
David Howellsd84f4f92008-11-14 10:39:23 +11003038 goto error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
3041 if (file) {
3042 /* read access is always possible with a mapping */
3043 u32 av = FILE__READ;
3044
3045 /* write access only matters if the mapping is shared */
3046 if (shared && (prot & PROT_WRITE))
3047 av |= FILE__WRITE;
3048
3049 if (prot & PROT_EXEC)
3050 av |= FILE__EXECUTE;
3051
David Howells88e67f32008-11-14 10:39:21 +11003052 return file_has_perm(cred, file, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 }
David Howellsd84f4f92008-11-14 10:39:23 +11003054
3055error:
3056 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057}
3058
Al Viroe5467852012-05-30 13:30:51 -04003059static int selinux_mmap_addr(unsigned long addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060{
Eric Parised032182007-06-28 15:55:21 -04003061 int rc = 0;
David Howells275bb412008-11-14 10:39:19 +11003062 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
Eric Paris84336d1a2009-07-31 12:54:05 -04003064 /*
3065 * notice that we are intentionally putting the SELinux check before
3066 * the secondary cap_file_mmap check. This is such a likely attempt
3067 * at bad behaviour/exploit that we always want to get the AVC, even
3068 * if DAC would have also denied the operation.
3069 */
Eric Parisa2551df2009-07-31 12:54:11 -04003070 if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
Eric Parised032182007-06-28 15:55:21 -04003071 rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
3072 MEMPROTECT__MMAP_ZERO, NULL);
Eric Paris84336d1a2009-07-31 12:54:05 -04003073 if (rc)
3074 return rc;
3075 }
3076
3077 /* do DAC check on address space usage */
Al Viroe5467852012-05-30 13:30:51 -04003078 return cap_mmap_addr(addr);
3079}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Al Viroe5467852012-05-30 13:30:51 -04003081static int selinux_mmap_file(struct file *file, unsigned long reqprot,
3082 unsigned long prot, unsigned long flags)
3083{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 if (selinux_checkreqprot)
3085 prot = reqprot;
3086
3087 return file_map_prot_check(file, prot,
3088 (flags & MAP_TYPE) == MAP_SHARED);
3089}
3090
3091static int selinux_file_mprotect(struct vm_area_struct *vma,
3092 unsigned long reqprot,
3093 unsigned long prot)
3094{
David Howells88e67f32008-11-14 10:39:21 +11003095 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
3097 if (selinux_checkreqprot)
3098 prot = reqprot;
3099
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04003100 if (default_noexec &&
3101 (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
James Morrisd541bbe2009-01-29 12:19:51 +11003102 int rc = 0;
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003103 if (vma->vm_start >= vma->vm_mm->start_brk &&
3104 vma->vm_end <= vma->vm_mm->brk) {
David Howellsd84f4f92008-11-14 10:39:23 +11003105 rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003106 } else if (!vma->vm_file &&
3107 vma->vm_start <= vma->vm_mm->start_stack &&
3108 vma->vm_end >= vma->vm_mm->start_stack) {
David Howells3b11a1d2008-11-14 10:39:26 +11003109 rc = current_has_perm(current, PROCESS__EXECSTACK);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003110 } else if (vma->vm_file && vma->anon_vma) {
3111 /*
3112 * We are making executable a file mapping that has
3113 * had some COW done. Since pages might have been
3114 * written, check ability to execute the possibly
3115 * modified content. This typically should only
3116 * occur for text relocations.
3117 */
David Howellsd84f4f92008-11-14 10:39:23 +11003118 rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
Stephen Smalleydb4c9642006-02-01 03:05:54 -08003119 }
Lorenzo Hernandez García-Hierro6b992192005-06-25 14:54:34 -07003120 if (rc)
3121 return rc;
3122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123
3124 return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
3125}
3126
3127static int selinux_file_lock(struct file *file, unsigned int cmd)
3128{
David Howells88e67f32008-11-14 10:39:21 +11003129 const struct cred *cred = current_cred();
3130
3131 return file_has_perm(cred, file, FILE__LOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132}
3133
3134static int selinux_file_fcntl(struct file *file, unsigned int cmd,
3135 unsigned long arg)
3136{
David Howells88e67f32008-11-14 10:39:21 +11003137 const struct cred *cred = current_cred();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 int err = 0;
3139
3140 switch (cmd) {
Eric Paris828dfe12008-04-17 13:17:49 -04003141 case F_SETFL:
3142 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3143 err = -EINVAL;
3144 break;
3145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
Eric Paris828dfe12008-04-17 13:17:49 -04003147 if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
David Howells88e67f32008-11-14 10:39:21 +11003148 err = file_has_perm(cred, file, FILE__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003150 }
3151 /* fall through */
3152 case F_SETOWN:
3153 case F_SETSIG:
3154 case F_GETFL:
3155 case F_GETOWN:
3156 case F_GETSIG:
Cyrill Gorcunov1d151c32012-07-30 14:43:00 -07003157 case F_GETOWNER_UIDS:
Eric Paris828dfe12008-04-17 13:17:49 -04003158 /* Just check FD__USE permission */
David Howells88e67f32008-11-14 10:39:21 +11003159 err = file_has_perm(cred, file, 0);
Eric Paris828dfe12008-04-17 13:17:49 -04003160 break;
3161 case F_GETLK:
3162 case F_SETLK:
3163 case F_SETLKW:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164#if BITS_PER_LONG == 32
Eric Paris828dfe12008-04-17 13:17:49 -04003165 case F_GETLK64:
3166 case F_SETLK64:
3167 case F_SETLKW64:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168#endif
Eric Paris828dfe12008-04-17 13:17:49 -04003169 if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
3170 err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003172 }
David Howells88e67f32008-11-14 10:39:21 +11003173 err = file_has_perm(cred, file, FILE__LOCK);
Eric Paris828dfe12008-04-17 13:17:49 -04003174 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 }
3176
3177 return err;
3178}
3179
3180static int selinux_file_set_fowner(struct file *file)
3181{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 struct file_security_struct *fsec;
3183
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 fsec = file->f_security;
David Howells275bb412008-11-14 10:39:19 +11003185 fsec->fown_sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
3187 return 0;
3188}
3189
3190static int selinux_file_send_sigiotask(struct task_struct *tsk,
3191 struct fown_struct *fown, int signum)
3192{
Eric Paris828dfe12008-04-17 13:17:49 -04003193 struct file *file;
Stephen Smalley65c90bc2009-05-04 15:43:18 -04003194 u32 sid = task_sid(tsk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 u32 perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 struct file_security_struct *fsec;
3197
3198 /* struct fown_struct is never outside the context of a struct file */
Eric Paris828dfe12008-04-17 13:17:49 -04003199 file = container_of(fown, struct file, f_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 fsec = file->f_security;
3202
3203 if (!signum)
3204 perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
3205 else
3206 perm = signal_to_av(signum);
3207
David Howells275bb412008-11-14 10:39:19 +11003208 return avc_has_perm(fsec->fown_sid, sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 SECCLASS_PROCESS, perm, NULL);
3210}
3211
3212static int selinux_file_receive(struct file *file)
3213{
David Howells88e67f32008-11-14 10:39:21 +11003214 const struct cred *cred = current_cred();
3215
3216 return file_has_perm(cred, file, file_to_av(file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217}
3218
Eric Paris83d49852012-04-04 13:45:40 -04003219static int selinux_file_open(struct file *file, const struct cred *cred)
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003220{
3221 struct file_security_struct *fsec;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003222 struct inode_security_struct *isec;
David Howellsd84f4f92008-11-14 10:39:23 +11003223
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003224 fsec = file->f_security;
Eric Paris602a8dd2012-04-04 15:01:42 -04003225 isec = file->f_path.dentry->d_inode->i_security;
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003226 /*
3227 * Save inode label and policy sequence number
3228 * at open-time so that selinux_file_permission
3229 * can determine whether revalidation is necessary.
3230 * Task label is already saved in the file security
3231 * struct as its SID.
3232 */
3233 fsec->isid = isec->sid;
3234 fsec->pseqno = avc_policy_seqno();
3235 /*
3236 * Since the inode label or policy seqno may have changed
3237 * between the selinux_inode_permission check and the saving
3238 * of state above, recheck that access is still permitted.
3239 * Otherwise, access might never be revalidated against the
3240 * new inode label or new policy.
3241 * This check is not redundant - do not remove.
3242 */
Eric Paris602a8dd2012-04-04 15:01:42 -04003243 return path_has_perm(cred, &file->f_path, open_file_to_av(file));
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09003244}
3245
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246/* task security operations */
3247
3248static int selinux_task_create(unsigned long clone_flags)
3249{
David Howells3b11a1d2008-11-14 10:39:26 +11003250 return current_has_perm(current, PROCESS__FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251}
3252
David Howellsf1752ee2008-11-14 10:39:17 +11003253/*
David Howellsee18d642009-09-02 09:14:21 +01003254 * allocate the SELinux part of blank credentials
3255 */
3256static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3257{
3258 struct task_security_struct *tsec;
3259
3260 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3261 if (!tsec)
3262 return -ENOMEM;
3263
3264 cred->security = tsec;
3265 return 0;
3266}
3267
3268/*
David Howellsf1752ee2008-11-14 10:39:17 +11003269 * detach and free the LSM part of a set of credentials
3270 */
3271static void selinux_cred_free(struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272{
David Howellsf1752ee2008-11-14 10:39:17 +11003273 struct task_security_struct *tsec = cred->security;
David Howellse0e81732009-09-02 09:13:40 +01003274
Tetsuo Handa2edeaa32011-02-07 13:36:10 +00003275 /*
3276 * cred->security == NULL if security_cred_alloc_blank() or
3277 * security_prepare_creds() returned an error.
3278 */
3279 BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
David Howellse0e81732009-09-02 09:13:40 +01003280 cred->security = (void *) 0x7UL;
David Howellsf1752ee2008-11-14 10:39:17 +11003281 kfree(tsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282}
3283
David Howellsd84f4f92008-11-14 10:39:23 +11003284/*
3285 * prepare a new set of credentials for modification
3286 */
3287static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3288 gfp_t gfp)
3289{
3290 const struct task_security_struct *old_tsec;
3291 struct task_security_struct *tsec;
3292
3293 old_tsec = old->security;
3294
3295 tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3296 if (!tsec)
3297 return -ENOMEM;
3298
3299 new->security = tsec;
3300 return 0;
3301}
3302
3303/*
David Howellsee18d642009-09-02 09:14:21 +01003304 * transfer the SELinux data to a blank set of creds
3305 */
3306static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3307{
3308 const struct task_security_struct *old_tsec = old->security;
3309 struct task_security_struct *tsec = new->security;
3310
3311 *tsec = *old_tsec;
3312}
3313
3314/*
David Howells3a3b7ce2008-11-14 10:39:28 +11003315 * set the security data for a kernel service
3316 * - all the creation contexts are set to unlabelled
3317 */
3318static int selinux_kernel_act_as(struct cred *new, u32 secid)
3319{
3320 struct task_security_struct *tsec = new->security;
3321 u32 sid = current_sid();
3322 int ret;
3323
3324 ret = avc_has_perm(sid, secid,
3325 SECCLASS_KERNEL_SERVICE,
3326 KERNEL_SERVICE__USE_AS_OVERRIDE,
3327 NULL);
3328 if (ret == 0) {
3329 tsec->sid = secid;
3330 tsec->create_sid = 0;
3331 tsec->keycreate_sid = 0;
3332 tsec->sockcreate_sid = 0;
3333 }
3334 return ret;
3335}
3336
3337/*
3338 * set the file creation context in a security record to the same as the
3339 * objective context of the specified inode
3340 */
3341static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
3342{
3343 struct inode_security_struct *isec = inode->i_security;
3344 struct task_security_struct *tsec = new->security;
3345 u32 sid = current_sid();
3346 int ret;
3347
3348 ret = avc_has_perm(sid, isec->sid,
3349 SECCLASS_KERNEL_SERVICE,
3350 KERNEL_SERVICE__CREATE_FILES_AS,
3351 NULL);
3352
3353 if (ret == 0)
3354 tsec->create_sid = isec->sid;
David Howellsef574712010-02-26 01:56:16 +00003355 return ret;
David Howells3a3b7ce2008-11-14 10:39:28 +11003356}
3357
Eric Parisdd8dbf22009-11-03 16:35:32 +11003358static int selinux_kernel_module_request(char *kmod_name)
Eric Paris25354c42009-08-13 09:45:03 -04003359{
Eric Parisdd8dbf22009-11-03 16:35:32 +11003360 u32 sid;
3361 struct common_audit_data ad;
3362
3363 sid = task_sid(current);
3364
Eric Paris50c205f2012-04-04 15:01:43 -04003365 ad.type = LSM_AUDIT_DATA_KMOD;
Eric Parisdd8dbf22009-11-03 16:35:32 +11003366 ad.u.kmod_name = kmod_name;
3367
3368 return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
3369 SYSTEM__MODULE_REQUEST, &ad);
Eric Paris25354c42009-08-13 09:45:03 -04003370}
3371
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
3373{
David Howells3b11a1d2008-11-14 10:39:26 +11003374 return current_has_perm(p, PROCESS__SETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375}
3376
3377static int selinux_task_getpgid(struct task_struct *p)
3378{
David Howells3b11a1d2008-11-14 10:39:26 +11003379 return current_has_perm(p, PROCESS__GETPGID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380}
3381
3382static int selinux_task_getsid(struct task_struct *p)
3383{
David Howells3b11a1d2008-11-14 10:39:26 +11003384 return current_has_perm(p, PROCESS__GETSESSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385}
3386
David Quigleyf9008e42006-06-30 01:55:46 -07003387static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3388{
David Howells275bb412008-11-14 10:39:19 +11003389 *secid = task_sid(p);
David Quigleyf9008e42006-06-30 01:55:46 -07003390}
3391
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392static int selinux_task_setnice(struct task_struct *p, int nice)
3393{
3394 int rc;
3395
Eric Paris200ac532009-02-12 15:01:04 -05003396 rc = cap_task_setnice(p, nice);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 if (rc)
3398 return rc;
3399
David Howells3b11a1d2008-11-14 10:39:26 +11003400 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401}
3402
James Morris03e68062006-06-23 02:03:58 -07003403static int selinux_task_setioprio(struct task_struct *p, int ioprio)
3404{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003405 int rc;
3406
Eric Paris200ac532009-02-12 15:01:04 -05003407 rc = cap_task_setioprio(p, ioprio);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003408 if (rc)
3409 return rc;
3410
David Howells3b11a1d2008-11-14 10:39:26 +11003411 return current_has_perm(p, PROCESS__SETSCHED);
James Morris03e68062006-06-23 02:03:58 -07003412}
3413
David Quigleya1836a42006-06-30 01:55:49 -07003414static int selinux_task_getioprio(struct task_struct *p)
3415{
David Howells3b11a1d2008-11-14 10:39:26 +11003416 return current_has_perm(p, PROCESS__GETSCHED);
David Quigleya1836a42006-06-30 01:55:49 -07003417}
3418
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003419static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
3420 struct rlimit *new_rlim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421{
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003422 struct rlimit *old_rlim = p->signal->rlim + resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
3424 /* Control the ability to change the hard limit (whether
3425 lowering or raising it), so that the hard limit can
3426 later be used as a safe reset point for the soft limit
David Howellsd84f4f92008-11-14 10:39:23 +11003427 upon context transitions. See selinux_bprm_committing_creds. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 if (old_rlim->rlim_max != new_rlim->rlim_max)
Jiri Slaby8fd00b42009-08-26 18:41:16 +02003429 return current_has_perm(p, PROCESS__SETRLIMIT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430
3431 return 0;
3432}
3433
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003434static int selinux_task_setscheduler(struct task_struct *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435{
Serge E. Hallynb5376772007-10-16 23:31:36 -07003436 int rc;
3437
KOSAKI Motohirob0ae1982010-10-15 04:21:18 +09003438 rc = cap_task_setscheduler(p);
Serge E. Hallynb5376772007-10-16 23:31:36 -07003439 if (rc)
3440 return rc;
3441
David Howells3b11a1d2008-11-14 10:39:26 +11003442 return current_has_perm(p, PROCESS__SETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443}
3444
3445static int selinux_task_getscheduler(struct task_struct *p)
3446{
David Howells3b11a1d2008-11-14 10:39:26 +11003447 return current_has_perm(p, PROCESS__GETSCHED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448}
3449
David Quigley35601542006-06-23 02:04:01 -07003450static int selinux_task_movememory(struct task_struct *p)
3451{
David Howells3b11a1d2008-11-14 10:39:26 +11003452 return current_has_perm(p, PROCESS__SETSCHED);
David Quigley35601542006-06-23 02:04:01 -07003453}
3454
David Quigleyf9008e42006-06-30 01:55:46 -07003455static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
3456 int sig, u32 secid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457{
3458 u32 perm;
3459 int rc;
3460
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 if (!sig)
3462 perm = PROCESS__SIGNULL; /* null signal; existence test */
3463 else
3464 perm = signal_to_av(sig);
David Quigleyf9008e42006-06-30 01:55:46 -07003465 if (secid)
David Howells275bb412008-11-14 10:39:19 +11003466 rc = avc_has_perm(secid, task_sid(p),
3467 SECCLASS_PROCESS, perm, NULL);
David Quigleyf9008e42006-06-30 01:55:46 -07003468 else
David Howells3b11a1d2008-11-14 10:39:26 +11003469 rc = current_has_perm(p, perm);
David Quigleyf9008e42006-06-30 01:55:46 -07003470 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471}
3472
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473static int selinux_task_wait(struct task_struct *p)
3474{
Eric Paris8a535142007-10-22 16:10:31 -04003475 return task_has_perm(p, current, PROCESS__SIGCHLD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476}
3477
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478static void selinux_task_to_inode(struct task_struct *p,
3479 struct inode *inode)
3480{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 struct inode_security_struct *isec = inode->i_security;
David Howells275bb412008-11-14 10:39:19 +11003482 u32 sid = task_sid(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
David Howells275bb412008-11-14 10:39:19 +11003484 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 isec->initialized = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486}
3487
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003489static int selinux_parse_skb_ipv4(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003490 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491{
3492 int offset, ihlen, ret = -EINVAL;
3493 struct iphdr _iph, *ih;
3494
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003495 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
3497 if (ih == NULL)
3498 goto out;
3499
3500 ihlen = ih->ihl * 4;
3501 if (ihlen < sizeof(_iph))
3502 goto out;
3503
Eric Paris48c62af2012-04-02 13:15:44 -04003504 ad->u.net->v4info.saddr = ih->saddr;
3505 ad->u.net->v4info.daddr = ih->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 ret = 0;
3507
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003508 if (proto)
3509 *proto = ih->protocol;
3510
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 switch (ih->protocol) {
Eric Paris828dfe12008-04-17 13:17:49 -04003512 case IPPROTO_TCP: {
3513 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
Eric Paris828dfe12008-04-17 13:17:49 -04003515 if (ntohs(ih->frag_off) & IP_OFFSET)
3516 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518 offset += ihlen;
3519 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3520 if (th == NULL)
3521 break;
3522
Eric Paris48c62af2012-04-02 13:15:44 -04003523 ad->u.net->sport = th->source;
3524 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527
Eric Paris828dfe12008-04-17 13:17:49 -04003528 case IPPROTO_UDP: {
3529 struct udphdr _udph, *uh;
3530
3531 if (ntohs(ih->frag_off) & IP_OFFSET)
3532 break;
3533
3534 offset += ihlen;
3535 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3536 if (uh == NULL)
3537 break;
3538
Eric Paris48c62af2012-04-02 13:15:44 -04003539 ad->u.net->sport = uh->source;
3540 ad->u.net->dport = uh->dest;
Eric Paris828dfe12008-04-17 13:17:49 -04003541 break;
3542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
James Morris2ee92d42006-11-13 16:09:01 -08003544 case IPPROTO_DCCP: {
3545 struct dccp_hdr _dccph, *dh;
3546
3547 if (ntohs(ih->frag_off) & IP_OFFSET)
3548 break;
3549
3550 offset += ihlen;
3551 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3552 if (dh == NULL)
3553 break;
3554
Eric Paris48c62af2012-04-02 13:15:44 -04003555 ad->u.net->sport = dh->dccph_sport;
3556 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003557 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003558 }
James Morris2ee92d42006-11-13 16:09:01 -08003559
Eric Paris828dfe12008-04-17 13:17:49 -04003560 default:
3561 break;
3562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563out:
3564 return ret;
3565}
3566
3567#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3568
3569/* Returns error only if unable to parse addresses */
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003570static int selinux_parse_skb_ipv6(struct sk_buff *skb,
Thomas Liu2bf49692009-07-14 12:14:09 -04003571 struct common_audit_data *ad, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572{
3573 u8 nexthdr;
3574 int ret = -EINVAL, offset;
3575 struct ipv6hdr _ipv6h, *ip6;
Jesse Gross75f28112011-11-30 17:05:51 -08003576 __be16 frag_off;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03003578 offset = skb_network_offset(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
3580 if (ip6 == NULL)
3581 goto out;
3582
Eric Paris48c62af2012-04-02 13:15:44 -04003583 ad->u.net->v6info.saddr = ip6->saddr;
3584 ad->u.net->v6info.daddr = ip6->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 ret = 0;
3586
3587 nexthdr = ip6->nexthdr;
3588 offset += sizeof(_ipv6h);
Jesse Gross75f28112011-11-30 17:05:51 -08003589 offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 if (offset < 0)
3591 goto out;
3592
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003593 if (proto)
3594 *proto = nexthdr;
3595
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 switch (nexthdr) {
3597 case IPPROTO_TCP: {
Eric Paris828dfe12008-04-17 13:17:49 -04003598 struct tcphdr _tcph, *th;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600 th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
3601 if (th == NULL)
3602 break;
3603
Eric Paris48c62af2012-04-02 13:15:44 -04003604 ad->u.net->sport = th->source;
3605 ad->u.net->dport = th->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 break;
3607 }
3608
3609 case IPPROTO_UDP: {
3610 struct udphdr _udph, *uh;
3611
3612 uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
3613 if (uh == NULL)
3614 break;
3615
Eric Paris48c62af2012-04-02 13:15:44 -04003616 ad->u.net->sport = uh->source;
3617 ad->u.net->dport = uh->dest;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 break;
3619 }
3620
James Morris2ee92d42006-11-13 16:09:01 -08003621 case IPPROTO_DCCP: {
3622 struct dccp_hdr _dccph, *dh;
3623
3624 dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
3625 if (dh == NULL)
3626 break;
3627
Eric Paris48c62af2012-04-02 13:15:44 -04003628 ad->u.net->sport = dh->dccph_sport;
3629 ad->u.net->dport = dh->dccph_dport;
James Morris2ee92d42006-11-13 16:09:01 -08003630 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003631 }
James Morris2ee92d42006-11-13 16:09:01 -08003632
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 /* includes fragments */
3634 default:
3635 break;
3636 }
3637out:
3638 return ret;
3639}
3640
3641#endif /* IPV6 */
3642
Thomas Liu2bf49692009-07-14 12:14:09 -04003643static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
David Howellscf9481e2008-07-27 21:31:07 +10003644 char **_addrp, int src, u8 *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645{
David Howellscf9481e2008-07-27 21:31:07 +10003646 char *addrp;
3647 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648
Eric Paris48c62af2012-04-02 13:15:44 -04003649 switch (ad->u.net->family) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 case PF_INET:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003651 ret = selinux_parse_skb_ipv4(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003652 if (ret)
3653 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003654 addrp = (char *)(src ? &ad->u.net->v4info.saddr :
3655 &ad->u.net->v4info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003656 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657
3658#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
3659 case PF_INET6:
Venkat Yekkirala67f83cb2006-11-08 17:04:26 -06003660 ret = selinux_parse_skb_ipv6(skb, ad, proto);
David Howellscf9481e2008-07-27 21:31:07 +10003661 if (ret)
3662 goto parse_error;
Eric Paris48c62af2012-04-02 13:15:44 -04003663 addrp = (char *)(src ? &ad->u.net->v6info.saddr :
3664 &ad->u.net->v6info.daddr);
David Howellscf9481e2008-07-27 21:31:07 +10003665 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666#endif /* IPV6 */
3667 default:
David Howellscf9481e2008-07-27 21:31:07 +10003668 addrp = NULL;
3669 goto okay;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 }
3671
David Howellscf9481e2008-07-27 21:31:07 +10003672parse_error:
3673 printk(KERN_WARNING
3674 "SELinux: failure in selinux_parse_skb(),"
3675 " unable to parse packet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 return ret;
David Howellscf9481e2008-07-27 21:31:07 +10003677
3678okay:
3679 if (_addrp)
3680 *_addrp = addrp;
3681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682}
3683
Paul Moore4f6a9932007-03-01 14:35:22 -05003684/**
Paul Moore220deb92008-01-29 08:38:23 -05003685 * selinux_skb_peerlbl_sid - Determine the peer label of a packet
Paul Moore4f6a9932007-03-01 14:35:22 -05003686 * @skb: the packet
Paul Moore75e22912008-01-29 08:38:04 -05003687 * @family: protocol family
Paul Moore220deb92008-01-29 08:38:23 -05003688 * @sid: the packet's peer label SID
Paul Moore4f6a9932007-03-01 14:35:22 -05003689 *
3690 * Description:
Paul Moore220deb92008-01-29 08:38:23 -05003691 * Check the various different forms of network peer labeling and determine
3692 * the peer label/SID for the packet; most of the magic actually occurs in
3693 * the security server function security_net_peersid_cmp(). The function
3694 * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
3695 * or -EACCES if @sid is invalid due to inconsistencies with the different
3696 * peer labels.
Paul Moore4f6a9932007-03-01 14:35:22 -05003697 *
3698 */
Paul Moore220deb92008-01-29 08:38:23 -05003699static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
Paul Moore4f6a9932007-03-01 14:35:22 -05003700{
Paul Moore71f1cb02008-01-29 08:51:16 -05003701 int err;
Paul Moore4f6a9932007-03-01 14:35:22 -05003702 u32 xfrm_sid;
3703 u32 nlbl_sid;
Paul Moore220deb92008-01-29 08:38:23 -05003704 u32 nlbl_type;
Paul Moore4f6a9932007-03-01 14:35:22 -05003705
3706 selinux_skb_xfrm_sid(skb, &xfrm_sid);
Paul Moore5dbe1eb2008-01-29 08:44:18 -05003707 selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
Paul Moore220deb92008-01-29 08:38:23 -05003708
Paul Moore71f1cb02008-01-29 08:51:16 -05003709 err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
3710 if (unlikely(err)) {
3711 printk(KERN_WARNING
3712 "SELinux: failure in selinux_skb_peerlbl_sid(),"
3713 " unable to determine packet's peer label\n");
Paul Moore220deb92008-01-29 08:38:23 -05003714 return -EACCES;
Paul Moore71f1cb02008-01-29 08:51:16 -05003715 }
Paul Moore220deb92008-01-29 08:38:23 -05003716
3717 return 0;
Paul Moore4f6a9932007-03-01 14:35:22 -05003718}
3719
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720/* socket security operations */
Paul Moored4f2d972010-04-22 14:46:18 -04003721
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003722static int socket_sockcreate_sid(const struct task_security_struct *tsec,
3723 u16 secclass, u32 *socksid)
Paul Moored4f2d972010-04-22 14:46:18 -04003724{
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003725 if (tsec->sockcreate_sid > SECSID_NULL) {
3726 *socksid = tsec->sockcreate_sid;
3727 return 0;
3728 }
3729
3730 return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
3731 socksid);
Paul Moored4f2d972010-04-22 14:46:18 -04003732}
3733
Paul Moore253bfae2010-04-22 14:46:19 -04003734static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735{
Paul Moore253bfae2010-04-22 14:46:19 -04003736 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003737 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04003738 struct lsm_network_audit net = {0,};
Paul Moore253bfae2010-04-22 14:46:19 -04003739 u32 tsid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Paul Moore253bfae2010-04-22 14:46:19 -04003741 if (sksec->sid == SECINITSID_KERNEL)
3742 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743
Eric Paris50c205f2012-04-04 15:01:43 -04003744 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04003745 ad.u.net = &net;
3746 ad.u.net->sk = sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747
Paul Moore253bfae2010-04-22 14:46:19 -04003748 return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749}
3750
3751static int selinux_socket_create(int family, int type,
3752 int protocol, int kern)
3753{
Paul Moore5fb49872010-04-22 14:46:19 -04003754 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003755 u32 newsid;
David Howells275bb412008-11-14 10:39:19 +11003756 u16 secclass;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003757 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
3759 if (kern)
Paul Moored4f2d972010-04-22 14:46:18 -04003760 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
David Howells275bb412008-11-14 10:39:19 +11003762 secclass = socket_type_to_security_class(family, type, protocol);
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003763 rc = socket_sockcreate_sid(tsec, secclass, &newsid);
3764 if (rc)
3765 return rc;
3766
Paul Moored4f2d972010-04-22 14:46:18 -04003767 return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768}
3769
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003770static int selinux_socket_post_create(struct socket *sock, int family,
3771 int type, int protocol, int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772{
Paul Moore5fb49872010-04-22 14:46:19 -04003773 const struct task_security_struct *tsec = current_security();
Paul Moored4f2d972010-04-22 14:46:18 -04003774 struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003775 struct sk_security_struct *sksec;
David Howells275bb412008-11-14 10:39:19 +11003776 int err = 0;
3777
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003778 isec->sclass = socket_type_to_security_class(family, type, protocol);
3779
David Howells275bb412008-11-14 10:39:19 +11003780 if (kern)
3781 isec->sid = SECINITSID_KERNEL;
Harry Ciao2ad18bd2011-03-02 13:32:34 +08003782 else {
3783 err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
3784 if (err)
3785 return err;
3786 }
David Howells275bb412008-11-14 10:39:19 +11003787
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 isec->initialized = 1;
3789
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003790 if (sock->sk) {
3791 sksec = sock->sk->sk_security;
3792 sksec->sid = isec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05003793 sksec->sclass = isec->sclass;
Paul Moore389fb8002009-03-27 17:10:34 -04003794 err = selinux_netlbl_socket_post_create(sock->sk, family);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07003795 }
3796
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07003797 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798}
3799
3800/* Range of port numbers used to automatically bind.
3801 Need to determine whether we should perform a name_bind
3802 permission check between the socket and the port number. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803
3804static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
3805{
Paul Moore253bfae2010-04-22 14:46:19 -04003806 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 u16 family;
3808 int err;
3809
Paul Moore253bfae2010-04-22 14:46:19 -04003810 err = sock_has_perm(current, sk, SOCKET__BIND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 if (err)
3812 goto out;
3813
3814 /*
3815 * If PF_INET or PF_INET6, check name_bind permission for the port.
James Morris13402582005-09-30 14:24:34 -04003816 * Multiple address binding for SCTP is not supported yet: we just
3817 * check the first address now.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 */
Paul Moore253bfae2010-04-22 14:46:19 -04003819 family = sk->sk_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 if (family == PF_INET || family == PF_INET6) {
3821 char *addrp;
Paul Moore253bfae2010-04-22 14:46:19 -04003822 struct sk_security_struct *sksec = sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04003823 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04003824 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 struct sockaddr_in *addr4 = NULL;
3826 struct sockaddr_in6 *addr6 = NULL;
3827 unsigned short snum;
James Morrise399f982008-06-12 01:39:58 +10003828 u32 sid, node_perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 if (family == PF_INET) {
3831 addr4 = (struct sockaddr_in *)address;
3832 snum = ntohs(addr4->sin_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 addrp = (char *)&addr4->sin_addr.s_addr;
3834 } else {
3835 addr6 = (struct sockaddr_in6 *)address;
3836 snum = ntohs(addr6->sin6_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 addrp = (char *)&addr6->sin6_addr.s6_addr;
3838 }
3839
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003840 if (snum) {
3841 int low, high;
3842
3843 inet_get_local_port_range(&low, &high);
3844
3845 if (snum < max(PROT_SOCK, low) || snum > high) {
Paul Moore3e112172008-04-10 10:48:14 -04003846 err = sel_netport_sid(sk->sk_protocol,
3847 snum, &sid);
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003848 if (err)
3849 goto out;
Eric Paris50c205f2012-04-04 15:01:43 -04003850 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04003851 ad.u.net = &net;
3852 ad.u.net->sport = htons(snum);
3853 ad.u.net->family = family;
Paul Moore253bfae2010-04-22 14:46:19 -04003854 err = avc_has_perm(sksec->sid, sid,
3855 sksec->sclass,
Stephen Hemminger227b60f2007-10-10 17:30:46 -07003856 SOCKET__NAME_BIND, &ad);
3857 if (err)
3858 goto out;
3859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 }
Eric Paris828dfe12008-04-17 13:17:49 -04003861
Paul Moore253bfae2010-04-22 14:46:19 -04003862 switch (sksec->sclass) {
James Morris13402582005-09-30 14:24:34 -04003863 case SECCLASS_TCP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 node_perm = TCP_SOCKET__NODE_BIND;
3865 break;
Eric Paris828dfe12008-04-17 13:17:49 -04003866
James Morris13402582005-09-30 14:24:34 -04003867 case SECCLASS_UDP_SOCKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 node_perm = UDP_SOCKET__NODE_BIND;
3869 break;
James Morris2ee92d42006-11-13 16:09:01 -08003870
3871 case SECCLASS_DCCP_SOCKET:
3872 node_perm = DCCP_SOCKET__NODE_BIND;
3873 break;
3874
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 default:
3876 node_perm = RAWIP_SOCKET__NODE_BIND;
3877 break;
3878 }
Eric Paris828dfe12008-04-17 13:17:49 -04003879
Paul Moore224dfbd2008-01-29 08:38:13 -05003880 err = sel_netnode_sid(addrp, family, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 if (err)
3882 goto out;
Eric Paris828dfe12008-04-17 13:17:49 -04003883
Eric Paris50c205f2012-04-04 15:01:43 -04003884 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04003885 ad.u.net = &net;
3886 ad.u.net->sport = htons(snum);
3887 ad.u.net->family = family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888
3889 if (family == PF_INET)
Eric Paris48c62af2012-04-02 13:15:44 -04003890 ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 else
Eric Paris48c62af2012-04-02 13:15:44 -04003892 ad.u.net->v6info.saddr = addr6->sin6_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893
Paul Moore253bfae2010-04-22 14:46:19 -04003894 err = avc_has_perm(sksec->sid, sid,
3895 sksec->sclass, node_perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 if (err)
3897 goto out;
3898 }
3899out:
3900 return err;
3901}
3902
3903static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
3904{
Paul Moore014ab192008-10-10 10:16:33 -04003905 struct sock *sk = sock->sk;
Paul Moore253bfae2010-04-22 14:46:19 -04003906 struct sk_security_struct *sksec = sk->sk_security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 int err;
3908
Paul Moore253bfae2010-04-22 14:46:19 -04003909 err = sock_has_perm(current, sk, SOCKET__CONNECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 if (err)
3911 return err;
3912
3913 /*
James Morris2ee92d42006-11-13 16:09:01 -08003914 * If a TCP or DCCP socket, check name_connect permission for the port.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 */
Paul Moore253bfae2010-04-22 14:46:19 -04003916 if (sksec->sclass == SECCLASS_TCP_SOCKET ||
3917 sksec->sclass == SECCLASS_DCCP_SOCKET) {
Thomas Liu2bf49692009-07-14 12:14:09 -04003918 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04003919 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 struct sockaddr_in *addr4 = NULL;
3921 struct sockaddr_in6 *addr6 = NULL;
3922 unsigned short snum;
James Morris2ee92d42006-11-13 16:09:01 -08003923 u32 sid, perm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924
3925 if (sk->sk_family == PF_INET) {
3926 addr4 = (struct sockaddr_in *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003927 if (addrlen < sizeof(struct sockaddr_in))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 return -EINVAL;
3929 snum = ntohs(addr4->sin_port);
3930 } else {
3931 addr6 = (struct sockaddr_in6 *)address;
Stephen Smalley911656f2005-07-28 21:16:21 -07003932 if (addrlen < SIN6_LEN_RFC2133)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 return -EINVAL;
3934 snum = ntohs(addr6->sin6_port);
3935 }
3936
Paul Moore3e112172008-04-10 10:48:14 -04003937 err = sel_netport_sid(sk->sk_protocol, snum, &sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 if (err)
3939 goto out;
3940
Paul Moore253bfae2010-04-22 14:46:19 -04003941 perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
James Morris2ee92d42006-11-13 16:09:01 -08003942 TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
3943
Eric Paris50c205f2012-04-04 15:01:43 -04003944 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04003945 ad.u.net = &net;
3946 ad.u.net->dport = htons(snum);
3947 ad.u.net->family = sk->sk_family;
Paul Moore253bfae2010-04-22 14:46:19 -04003948 err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 if (err)
3950 goto out;
3951 }
3952
Paul Moore014ab192008-10-10 10:16:33 -04003953 err = selinux_netlbl_socket_connect(sk, address);
3954
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955out:
3956 return err;
3957}
3958
3959static int selinux_socket_listen(struct socket *sock, int backlog)
3960{
Paul Moore253bfae2010-04-22 14:46:19 -04003961 return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962}
3963
3964static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3965{
3966 int err;
3967 struct inode_security_struct *isec;
3968 struct inode_security_struct *newisec;
3969
Paul Moore253bfae2010-04-22 14:46:19 -04003970 err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 if (err)
3972 return err;
3973
3974 newisec = SOCK_INODE(newsock)->i_security;
3975
3976 isec = SOCK_INODE(sock)->i_security;
3977 newisec->sclass = isec->sclass;
3978 newisec->sid = isec->sid;
3979 newisec->initialized = 1;
3980
3981 return 0;
3982}
3983
3984static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
Eric Paris828dfe12008-04-17 13:17:49 -04003985 int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986{
Paul Moore253bfae2010-04-22 14:46:19 -04003987 return sock_has_perm(current, sock->sk, SOCKET__WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988}
3989
3990static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
3991 int size, int flags)
3992{
Paul Moore253bfae2010-04-22 14:46:19 -04003993 return sock_has_perm(current, sock->sk, SOCKET__READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994}
3995
3996static int selinux_socket_getsockname(struct socket *sock)
3997{
Paul Moore253bfae2010-04-22 14:46:19 -04003998 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999}
4000
4001static int selinux_socket_getpeername(struct socket *sock)
4002{
Paul Moore253bfae2010-04-22 14:46:19 -04004003 return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004}
4005
Eric Paris828dfe12008-04-17 13:17:49 -04004006static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007{
Paul Mooref8687af2006-10-30 15:22:15 -08004008 int err;
4009
Paul Moore253bfae2010-04-22 14:46:19 -04004010 err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
Paul Mooref8687af2006-10-30 15:22:15 -08004011 if (err)
4012 return err;
4013
4014 return selinux_netlbl_socket_setsockopt(sock, level, optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015}
4016
4017static int selinux_socket_getsockopt(struct socket *sock, int level,
4018 int optname)
4019{
Paul Moore253bfae2010-04-22 14:46:19 -04004020 return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021}
4022
4023static int selinux_socket_shutdown(struct socket *sock, int how)
4024{
Paul Moore253bfae2010-04-22 14:46:19 -04004025 return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026}
4027
David S. Miller3610cda2011-01-05 15:38:53 -08004028static int selinux_socket_unix_stream_connect(struct sock *sock,
4029 struct sock *other,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 struct sock *newsk)
4031{
David S. Miller3610cda2011-01-05 15:38:53 -08004032 struct sk_security_struct *sksec_sock = sock->sk_security;
4033 struct sk_security_struct *sksec_other = other->sk_security;
Paul Moore4d1e2452010-04-22 14:46:18 -04004034 struct sk_security_struct *sksec_new = newsk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004035 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004036 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 int err;
4038
Eric Paris50c205f2012-04-04 15:01:43 -04004039 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04004040 ad.u.net = &net;
4041 ad.u.net->sk = other;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042
Paul Moore4d1e2452010-04-22 14:46:18 -04004043 err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
4044 sksec_other->sclass,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 UNIX_STREAM_SOCKET__CONNECTTO, &ad);
4046 if (err)
4047 return err;
4048
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 /* server child socket */
Paul Moore4d1e2452010-04-22 14:46:18 -04004050 sksec_new->peer_sid = sksec_sock->sid;
4051 err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
4052 &sksec_new->sid);
4053 if (err)
4054 return err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004055
Paul Moore4d1e2452010-04-22 14:46:18 -04004056 /* connecting socket */
4057 sksec_sock->peer_sid = sksec_new->sid;
4058
4059 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060}
4061
4062static int selinux_socket_unix_may_send(struct socket *sock,
4063 struct socket *other)
4064{
Paul Moore253bfae2010-04-22 14:46:19 -04004065 struct sk_security_struct *ssec = sock->sk->sk_security;
4066 struct sk_security_struct *osec = other->sk->sk_security;
Thomas Liu2bf49692009-07-14 12:14:09 -04004067 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004068 struct lsm_network_audit net = {0,};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
Eric Paris50c205f2012-04-04 15:01:43 -04004070 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04004071 ad.u.net = &net;
4072 ad.u.net->sk = other->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
Paul Moore253bfae2010-04-22 14:46:19 -04004074 return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4075 &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076}
4077
Paul Mooreeffad8d2008-01-29 08:49:27 -05004078static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
4079 u32 peer_sid,
Thomas Liu2bf49692009-07-14 12:14:09 -04004080 struct common_audit_data *ad)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004081{
4082 int err;
4083 u32 if_sid;
4084 u32 node_sid;
4085
4086 err = sel_netif_sid(ifindex, &if_sid);
4087 if (err)
4088 return err;
4089 err = avc_has_perm(peer_sid, if_sid,
4090 SECCLASS_NETIF, NETIF__INGRESS, ad);
4091 if (err)
4092 return err;
4093
4094 err = sel_netnode_sid(addrp, family, &node_sid);
4095 if (err)
4096 return err;
4097 return avc_has_perm(peer_sid, node_sid,
4098 SECCLASS_NODE, NODE__RECVFROM, ad);
4099}
4100
Paul Moore220deb92008-01-29 08:38:23 -05004101static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
Paul Moored8395c82008-10-10 10:16:30 -04004102 u16 family)
Paul Moore220deb92008-01-29 08:38:23 -05004103{
Paul Moore277d3422008-12-31 12:54:11 -05004104 int err = 0;
Paul Moore220deb92008-01-29 08:38:23 -05004105 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004106 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004107 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004108 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004109 char *addrp;
4110
Eric Paris50c205f2012-04-04 15:01:43 -04004111 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04004112 ad.u.net = &net;
4113 ad.u.net->netif = skb->skb_iif;
4114 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004115 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4116 if (err)
4117 return err;
Paul Moore220deb92008-01-29 08:38:23 -05004118
Paul Moore58bfbb52009-03-27 17:10:41 -04004119 if (selinux_secmark_enabled()) {
Paul Moore220deb92008-01-29 08:38:23 -05004120 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
Paul Moored8395c82008-10-10 10:16:30 -04004121 PACKET__RECV, &ad);
Paul Moore58bfbb52009-03-27 17:10:41 -04004122 if (err)
4123 return err;
4124 }
Paul Moore220deb92008-01-29 08:38:23 -05004125
Steffen Klassertb9679a72011-02-23 12:55:21 +01004126 err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4127 if (err)
4128 return err;
4129 err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004130
James Morris4e5ab4c2006-06-09 00:33:33 -07004131 return err;
4132}
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004133
James Morris4e5ab4c2006-06-09 00:33:33 -07004134static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
4135{
Paul Moore220deb92008-01-29 08:38:23 -05004136 int err;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004137 struct sk_security_struct *sksec = sk->sk_security;
Paul Moore220deb92008-01-29 08:38:23 -05004138 u16 family = sk->sk_family;
4139 u32 sk_sid = sksec->sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004140 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004141 struct lsm_network_audit net = {0,};
Paul Moore220deb92008-01-29 08:38:23 -05004142 char *addrp;
Paul Moored8395c82008-10-10 10:16:30 -04004143 u8 secmark_active;
4144 u8 peerlbl_active;
James Morris4e5ab4c2006-06-09 00:33:33 -07004145
James Morris4e5ab4c2006-06-09 00:33:33 -07004146 if (family != PF_INET && family != PF_INET6)
Paul Moore220deb92008-01-29 08:38:23 -05004147 return 0;
James Morris4e5ab4c2006-06-09 00:33:33 -07004148
4149 /* Handle mapped IPv4 packets arriving via IPv6 sockets */
Al Viro87fcd702006-12-04 22:00:55 +00004150 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
James Morris4e5ab4c2006-06-09 00:33:33 -07004151 family = PF_INET;
4152
Paul Moored8395c82008-10-10 10:16:30 -04004153 /* If any sort of compatibility mode is enabled then handoff processing
4154 * to the selinux_sock_rcv_skb_compat() function to deal with the
4155 * special handling. We do this in an attempt to keep this function
4156 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004157 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004158 return selinux_sock_rcv_skb_compat(sk, skb, family);
4159
4160 secmark_active = selinux_secmark_enabled();
4161 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4162 if (!secmark_active && !peerlbl_active)
4163 return 0;
4164
Eric Paris50c205f2012-04-04 15:01:43 -04004165 ad.type = LSM_AUDIT_DATA_NET;
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 Moore224dfbd2008-01-29 08:38:13 -05004169 err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
James Morris4e5ab4c2006-06-09 00:33:33 -07004170 if (err)
Paul Moore220deb92008-01-29 08:38:23 -05004171 return err;
James Morris4e5ab4c2006-06-09 00:33:33 -07004172
Paul Moored8395c82008-10-10 10:16:30 -04004173 if (peerlbl_active) {
Paul Moored621d352008-01-29 08:43:36 -05004174 u32 peer_sid;
4175
4176 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4177 if (err)
4178 return err;
Eric Dumazet8964be42009-11-20 15:35:04 -08004179 err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
Paul Mooreeffad8d2008-01-29 08:49:27 -05004180 peer_sid, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004181 if (err) {
4182 selinux_netlbl_err(skb, err, 0);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004183 return err;
Paul Mooredfaebe92008-10-10 10:16:31 -04004184 }
Paul Moored621d352008-01-29 08:43:36 -05004185 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
4186 PEER__RECV, &ad);
Paul Mooredfaebe92008-10-10 10:16:31 -04004187 if (err)
4188 selinux_netlbl_err(skb, err, 0);
Paul Moored621d352008-01-29 08:43:36 -05004189 }
4190
Paul Moored8395c82008-10-10 10:16:30 -04004191 if (secmark_active) {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004192 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
4193 PACKET__RECV, &ad);
4194 if (err)
4195 return err;
4196 }
4197
Paul Moored621d352008-01-29 08:43:36 -05004198 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199}
4200
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004201static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
4202 int __user *optlen, unsigned len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203{
4204 int err = 0;
4205 char *scontext;
4206 u32 scontext_len;
Paul Moore253bfae2010-04-22 14:46:19 -04004207 struct sk_security_struct *sksec = sock->sk->sk_security;
Paul Moore3de4bab2006-11-17 17:38:54 -05004208 u32 peer_sid = SECSID_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Paul Moore253bfae2010-04-22 14:46:19 -04004210 if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4211 sksec->sclass == SECCLASS_TCP_SOCKET)
Eric Parisdd3e7832010-04-07 15:08:46 -04004212 peer_sid = sksec->peer_sid;
Paul Moore253bfae2010-04-22 14:46:19 -04004213 if (peer_sid == SECSID_NULL)
4214 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004216 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 if (err)
Paul Moore253bfae2010-04-22 14:46:19 -04004218 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
4220 if (scontext_len > len) {
4221 err = -ERANGE;
4222 goto out_len;
4223 }
4224
4225 if (copy_to_user(optval, scontext, scontext_len))
4226 err = -EFAULT;
4227
4228out_len:
4229 if (put_user(scontext_len, optlen))
4230 err = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 kfree(scontext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 return err;
4233}
4234
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004235static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004236{
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004237 u32 peer_secid = SECSID_NULL;
Paul Moore75e22912008-01-29 08:38:04 -05004238 u16 family;
Catherine Zhang877ce7c2006-06-29 12:27:47 -07004239
Paul Mooreaa862902008-10-10 10:16:29 -04004240 if (skb && skb->protocol == htons(ETH_P_IP))
4241 family = PF_INET;
4242 else if (skb && skb->protocol == htons(ETH_P_IPV6))
4243 family = PF_INET6;
4244 else if (sock)
Paul Moore75e22912008-01-29 08:38:04 -05004245 family = sock->sk->sk_family;
Paul Moore75e22912008-01-29 08:38:04 -05004246 else
4247 goto out;
4248
4249 if (sock && family == PF_UNIX)
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02004250 selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
Paul Moore3de4bab2006-11-17 17:38:54 -05004251 else if (skb)
Paul Moore220deb92008-01-29 08:38:23 -05004252 selinux_skb_peerlbl_sid(skb, family, &peer_secid);
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004253
Paul Moore75e22912008-01-29 08:38:04 -05004254out:
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07004255 *secid = peer_secid;
Paul Moore75e22912008-01-29 08:38:04 -05004256 if (peer_secid == SECSID_NULL)
4257 return -EINVAL;
4258 return 0;
Catherine Zhang2c7946a2006-03-20 22:41:23 -08004259}
4260
Al Viro7d877f32005-10-21 03:20:43 -04004261static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262{
Paul Moore84914b72010-04-22 14:46:18 -04004263 struct sk_security_struct *sksec;
4264
4265 sksec = kzalloc(sizeof(*sksec), priority);
4266 if (!sksec)
4267 return -ENOMEM;
4268
4269 sksec->peer_sid = SECINITSID_UNLABELED;
4270 sksec->sid = SECINITSID_UNLABELED;
4271 selinux_netlbl_sk_security_reset(sksec);
4272 sk->sk_security = sksec;
4273
4274 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275}
4276
4277static void selinux_sk_free_security(struct sock *sk)
4278{
Paul Moore84914b72010-04-22 14:46:18 -04004279 struct sk_security_struct *sksec = sk->sk_security;
4280
4281 sk->sk_security = NULL;
4282 selinux_netlbl_sk_security_free(sksec);
4283 kfree(sksec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284}
4285
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004286static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4287{
Eric Parisdd3e7832010-04-07 15:08:46 -04004288 struct sk_security_struct *sksec = sk->sk_security;
4289 struct sk_security_struct *newsksec = newsk->sk_security;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004290
Eric Parisdd3e7832010-04-07 15:08:46 -04004291 newsksec->sid = sksec->sid;
4292 newsksec->peer_sid = sksec->peer_sid;
4293 newsksec->sclass = sksec->sclass;
Paul Moore99f59ed2006-08-29 17:53:48 -07004294
Eric Parisdd3e7832010-04-07 15:08:46 -04004295 selinux_netlbl_sk_security_reset(newsksec);
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004296}
4297
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004298static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004299{
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004300 if (!sk)
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004301 *secid = SECINITSID_ANY_SOCKET;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004302 else {
4303 struct sk_security_struct *sksec = sk->sk_security;
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004304
Venkat Yekkiralabeb8d132006-08-04 23:12:42 -07004305 *secid = sksec->sid;
Venkat Yekkirala892c1412006-08-04 23:08:56 -07004306 }
Trent Jaegerd28d1e02005-12-13 23:12:40 -08004307}
4308
Eric Paris828dfe12008-04-17 13:17:49 -04004309static void selinux_sock_graft(struct sock *sk, struct socket *parent)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004310{
4311 struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
4312 struct sk_security_struct *sksec = sk->sk_security;
4313
David Woodhouse2148ccc2006-09-29 15:50:25 -07004314 if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
4315 sk->sk_family == PF_UNIX)
4316 isec->sid = sksec->sid;
Paul Moore220deb92008-01-29 08:38:23 -05004317 sksec->sclass = isec->sclass;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004318}
4319
Adrian Bunk9a673e52006-08-15 00:03:53 -07004320static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4321 struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004322{
4323 struct sk_security_struct *sksec = sk->sk_security;
4324 int err;
Paul Mooreaa862902008-10-10 10:16:29 -04004325 u16 family = sk->sk_family;
Venkat Yekkirala7420ed22006-08-04 23:17:57 -07004326 u32 newsid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004327 u32 peersid;
4328
Paul Mooreaa862902008-10-10 10:16:29 -04004329 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4330 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4331 family = PF_INET;
4332
4333 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
Paul Moore220deb92008-01-29 08:38:23 -05004334 if (err)
4335 return err;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004336 if (peersid == SECSID_NULL) {
4337 req->secid = sksec->sid;
Paul Moore3de4bab2006-11-17 17:38:54 -05004338 req->peer_secid = SECSID_NULL;
Paul Moore389fb8002009-03-27 17:10:34 -04004339 } else {
4340 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4341 if (err)
4342 return err;
4343 req->secid = newsid;
4344 req->peer_secid = peersid;
Venkat Yekkiralaa51c64f2006-07-27 22:01:34 -07004345 }
4346
Paul Moore389fb8002009-03-27 17:10:34 -04004347 return selinux_netlbl_inet_conn_request(req, family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004348}
4349
Adrian Bunk9a673e52006-08-15 00:03:53 -07004350static void selinux_inet_csk_clone(struct sock *newsk,
4351 const struct request_sock *req)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004352{
4353 struct sk_security_struct *newsksec = newsk->sk_security;
4354
4355 newsksec->sid = req->secid;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004356 newsksec->peer_sid = req->peer_secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004357 /* NOTE: Ideally, we should also get the isec->sid for the
4358 new socket in sync, but we don't have the isec available yet.
4359 So we will wait until sock_graft to do it, by which
4360 time it will have been created and available. */
Paul Moore99f59ed2006-08-29 17:53:48 -07004361
Paul Moore9f2ad662006-11-17 17:38:53 -05004362 /* We don't need to take any sort of lock here as we are the only
4363 * thread with access to newsksec */
Paul Moore389fb8002009-03-27 17:10:34 -04004364 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004365}
4366
Paul Moore014ab192008-10-10 10:16:33 -04004367static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004368{
Paul Mooreaa862902008-10-10 10:16:29 -04004369 u16 family = sk->sk_family;
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004370 struct sk_security_struct *sksec = sk->sk_security;
4371
Paul Mooreaa862902008-10-10 10:16:29 -04004372 /* handle mapped IPv4 packets arriving via IPv6 sockets */
4373 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
4374 family = PF_INET;
4375
4376 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
Venkat Yekkirala6b877692006-11-08 17:04:09 -06004377}
4378
Eric Paris2606fd12010-10-13 16:24:41 -04004379static int selinux_secmark_relabel_packet(u32 sid)
4380{
4381 const struct task_security_struct *__tsec;
4382 u32 tsid;
4383
4384 __tsec = current_security();
4385 tsid = __tsec->sid;
4386
4387 return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
4388}
4389
4390static void selinux_secmark_refcount_inc(void)
4391{
4392 atomic_inc(&selinux_secmark_refcount);
4393}
4394
4395static void selinux_secmark_refcount_dec(void)
4396{
4397 atomic_dec(&selinux_secmark_refcount);
4398}
4399
Adrian Bunk9a673e52006-08-15 00:03:53 -07004400static void selinux_req_classify_flow(const struct request_sock *req,
4401 struct flowi *fl)
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004402{
David S. Miller1d28f422011-03-12 00:29:39 -05004403 fl->flowi_secid = req->secid;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004404}
4405
Paul Mooreed6d76e2009-08-28 18:12:49 -04004406static int selinux_tun_dev_create(void)
4407{
4408 u32 sid = current_sid();
4409
4410 /* we aren't taking into account the "sockcreate" SID since the socket
4411 * that is being created here is not a socket in the traditional sense,
4412 * instead it is a private sock, accessible only to the kernel, and
4413 * representing a wide range of network traffic spanning multiple
4414 * connections unlike traditional sockets - check the TUN driver to
4415 * get a better understanding of why this socket is special */
4416
4417 return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
4418 NULL);
4419}
4420
4421static void selinux_tun_dev_post_create(struct sock *sk)
4422{
4423 struct sk_security_struct *sksec = sk->sk_security;
4424
4425 /* we don't currently perform any NetLabel based labeling here and it
4426 * isn't clear that we would want to do so anyway; while we could apply
4427 * labeling without the support of the TUN user the resulting labeled
4428 * traffic from the other end of the connection would almost certainly
4429 * cause confusion to the TUN user that had no idea network labeling
4430 * protocols were being used */
4431
4432 /* see the comments in selinux_tun_dev_create() about why we don't use
4433 * the sockcreate SID here */
4434
4435 sksec->sid = current_sid();
4436 sksec->sclass = SECCLASS_TUN_SOCKET;
4437}
4438
4439static int selinux_tun_dev_attach(struct sock *sk)
4440{
4441 struct sk_security_struct *sksec = sk->sk_security;
4442 u32 sid = current_sid();
4443 int err;
4444
4445 err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
4446 TUN_SOCKET__RELABELFROM, NULL);
4447 if (err)
4448 return err;
4449 err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
4450 TUN_SOCKET__RELABELTO, NULL);
4451 if (err)
4452 return err;
4453
4454 sksec->sid = sid;
4455
4456 return 0;
4457}
4458
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
4460{
4461 int err = 0;
4462 u32 perm;
4463 struct nlmsghdr *nlh;
Paul Moore253bfae2010-04-22 14:46:19 -04004464 struct sk_security_struct *sksec = sk->sk_security;
Eric Paris828dfe12008-04-17 13:17:49 -04004465
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 if (skb->len < NLMSG_SPACE(0)) {
4467 err = -EINVAL;
4468 goto out;
4469 }
Arnaldo Carvalho de Melob529ccf2007-04-25 19:08:35 -07004470 nlh = nlmsg_hdr(skb);
Eric Paris828dfe12008-04-17 13:17:49 -04004471
Paul Moore253bfae2010-04-22 14:46:19 -04004472 err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 if (err) {
4474 if (err == -EINVAL) {
David Woodhouse9ad9ad32005-06-22 15:04:33 +01004475 audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 "SELinux: unrecognized netlink message"
4477 " type=%hu for sclass=%hu\n",
Paul Moore253bfae2010-04-22 14:46:19 -04004478 nlh->nlmsg_type, sksec->sclass);
Eric Paris39c9aed2008-11-05 09:34:42 -05004479 if (!selinux_enforcing || security_get_allow_unknown())
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 err = 0;
4481 }
4482
4483 /* Ignore */
4484 if (err == -ENOENT)
4485 err = 0;
4486 goto out;
4487 }
4488
Paul Moore253bfae2010-04-22 14:46:19 -04004489 err = sock_has_perm(current, sk, perm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490out:
4491 return err;
4492}
4493
4494#ifdef CONFIG_NETFILTER
4495
Paul Mooreeffad8d2008-01-29 08:49:27 -05004496static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
4497 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498{
Paul Mooredfaebe92008-10-10 10:16:31 -04004499 int err;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004500 char *addrp;
4501 u32 peer_sid;
Thomas Liu2bf49692009-07-14 12:14:09 -04004502 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004503 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004504 u8 secmark_active;
Paul Moore948bf852008-10-10 10:16:32 -04004505 u8 netlbl_active;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004506 u8 peerlbl_active;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004507
Paul Mooreeffad8d2008-01-29 08:49:27 -05004508 if (!selinux_policycap_netpeer)
4509 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004510
Paul Mooreeffad8d2008-01-29 08:49:27 -05004511 secmark_active = selinux_secmark_enabled();
Paul Moore948bf852008-10-10 10:16:32 -04004512 netlbl_active = netlbl_enabled();
4513 peerlbl_active = netlbl_active || selinux_xfrm_enabled();
Paul Mooreeffad8d2008-01-29 08:49:27 -05004514 if (!secmark_active && !peerlbl_active)
4515 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004516
Paul Moored8395c82008-10-10 10:16:30 -04004517 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
4518 return NF_DROP;
4519
Eric Paris50c205f2012-04-04 15:01:43 -04004520 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04004521 ad.u.net = &net;
4522 ad.u.net->netif = ifindex;
4523 ad.u.net->family = family;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004524 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
4525 return NF_DROP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526
Paul Mooredfaebe92008-10-10 10:16:31 -04004527 if (peerlbl_active) {
4528 err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
4529 peer_sid, &ad);
4530 if (err) {
4531 selinux_netlbl_err(skb, err, 1);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004532 return NF_DROP;
Paul Mooredfaebe92008-10-10 10:16:31 -04004533 }
4534 }
Paul Mooreeffad8d2008-01-29 08:49:27 -05004535
4536 if (secmark_active)
4537 if (avc_has_perm(peer_sid, skb->secmark,
4538 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
4539 return NF_DROP;
4540
Paul Moore948bf852008-10-10 10:16:32 -04004541 if (netlbl_active)
4542 /* we do this in the FORWARD path and not the POST_ROUTING
4543 * path because we want to make sure we apply the necessary
4544 * labeling before IPsec is applied so we can leverage AH
4545 * protection */
4546 if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
4547 return NF_DROP;
4548
Paul Mooreeffad8d2008-01-29 08:49:27 -05004549 return NF_ACCEPT;
4550}
4551
4552static unsigned int selinux_ipv4_forward(unsigned int hooknum,
4553 struct sk_buff *skb,
4554 const struct net_device *in,
4555 const struct net_device *out,
4556 int (*okfn)(struct sk_buff *))
4557{
4558 return selinux_ip_forward(skb, in->ifindex, PF_INET);
4559}
4560
4561#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
4562static unsigned int selinux_ipv6_forward(unsigned int hooknum,
4563 struct sk_buff *skb,
4564 const struct net_device *in,
4565 const struct net_device *out,
4566 int (*okfn)(struct sk_buff *))
4567{
4568 return selinux_ip_forward(skb, in->ifindex, PF_INET6);
4569}
4570#endif /* IPV6 */
4571
Paul Moore948bf852008-10-10 10:16:32 -04004572static unsigned int selinux_ip_output(struct sk_buff *skb,
4573 u16 family)
4574{
4575 u32 sid;
4576
4577 if (!netlbl_enabled())
4578 return NF_ACCEPT;
4579
4580 /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
4581 * because we want to make sure we apply the necessary labeling
4582 * before IPsec is applied so we can leverage AH protection */
4583 if (skb->sk) {
4584 struct sk_security_struct *sksec = skb->sk->sk_security;
4585 sid = sksec->sid;
4586 } else
4587 sid = SECINITSID_KERNEL;
4588 if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
4589 return NF_DROP;
4590
4591 return NF_ACCEPT;
4592}
4593
4594static unsigned int selinux_ipv4_output(unsigned int hooknum,
4595 struct sk_buff *skb,
4596 const struct net_device *in,
4597 const struct net_device *out,
4598 int (*okfn)(struct sk_buff *))
4599{
4600 return selinux_ip_output(skb, PF_INET);
4601}
4602
Paul Mooreeffad8d2008-01-29 08:49:27 -05004603static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
4604 int ifindex,
Paul Moored8395c82008-10-10 10:16:30 -04004605 u16 family)
James Morris4e5ab4c2006-06-09 00:33:33 -07004606{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004607 struct sock *sk = skb->sk;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004608 struct sk_security_struct *sksec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004609 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004610 struct lsm_network_audit net = {0,};
Paul Moored8395c82008-10-10 10:16:30 -04004611 char *addrp;
4612 u8 proto;
James Morris4e5ab4c2006-06-09 00:33:33 -07004613
Paul Mooreeffad8d2008-01-29 08:49:27 -05004614 if (sk == NULL)
4615 return NF_ACCEPT;
Venkat Yekkirala4237c752006-07-24 23:32:50 -07004616 sksec = sk->sk_security;
James Morris4e5ab4c2006-06-09 00:33:33 -07004617
Eric Paris50c205f2012-04-04 15:01:43 -04004618 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04004619 ad.u.net = &net;
4620 ad.u.net->netif = ifindex;
4621 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004622 if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
4623 return NF_DROP;
4624
Paul Moore58bfbb52009-03-27 17:10:41 -04004625 if (selinux_secmark_enabled())
Paul Mooreeffad8d2008-01-29 08:49:27 -05004626 if (avc_has_perm(sksec->sid, skb->secmark,
Paul Moored8395c82008-10-10 10:16:30 -04004627 SECCLASS_PACKET, PACKET__SEND, &ad))
Eric Paris2fe66ec2010-11-23 06:28:08 +00004628 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004629
Steffen Klassertb9679a72011-02-23 12:55:21 +01004630 if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
4631 return NF_DROP_ERR(-ECONNREFUSED);
James Morris4e5ab4c2006-06-09 00:33:33 -07004632
Paul Mooreeffad8d2008-01-29 08:49:27 -05004633 return NF_ACCEPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634}
4635
Paul Mooreeffad8d2008-01-29 08:49:27 -05004636static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4637 u16 family)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004639 u32 secmark_perm;
4640 u32 peer_sid;
4641 struct sock *sk;
Thomas Liu2bf49692009-07-14 12:14:09 -04004642 struct common_audit_data ad;
Eric Paris48c62af2012-04-02 13:15:44 -04004643 struct lsm_network_audit net = {0,};
Paul Mooreeffad8d2008-01-29 08:49:27 -05004644 char *addrp;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004645 u8 secmark_active;
4646 u8 peerlbl_active;
4647
Paul Mooreeffad8d2008-01-29 08:49:27 -05004648 /* If any sort of compatibility mode is enabled then handoff processing
4649 * to the selinux_ip_postroute_compat() function to deal with the
4650 * special handling. We do this in an attempt to keep this function
4651 * as fast and as clean as possible. */
Paul Moore58bfbb52009-03-27 17:10:41 -04004652 if (!selinux_policycap_netpeer)
Paul Moored8395c82008-10-10 10:16:30 -04004653 return selinux_ip_postroute_compat(skb, ifindex, family);
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004654#ifdef CONFIG_XFRM
Paul Mooreeffad8d2008-01-29 08:49:27 -05004655 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
4656 * packet transformation so allow the packet to pass without any checks
4657 * since we'll have another chance to perform access control checks
4658 * when the packet is on it's final way out.
4659 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
4660 * is NULL, in this case go ahead and apply access control. */
Eric Dumazetadf30902009-06-02 05:19:30 +00004661 if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004662 return NF_ACCEPT;
Alexey Dobriyandef8b4f2008-10-28 13:24:06 -07004663#endif
Paul Mooreeffad8d2008-01-29 08:49:27 -05004664 secmark_active = selinux_secmark_enabled();
4665 peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
4666 if (!secmark_active && !peerlbl_active)
4667 return NF_ACCEPT;
4668
Paul Moored8395c82008-10-10 10:16:30 -04004669 /* if the packet is being forwarded then get the peer label from the
4670 * packet itself; otherwise check to see if it is from a local
4671 * application or the kernel, if from an application get the peer label
4672 * from the sending socket, otherwise use the kernel's sid */
Paul Mooreeffad8d2008-01-29 08:49:27 -05004673 sk = skb->sk;
Paul Moored8395c82008-10-10 10:16:30 -04004674 if (sk == NULL) {
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004675 if (skb->skb_iif) {
4676 secmark_perm = PACKET__FORWARD_OUT;
Paul Moored8395c82008-10-10 10:16:30 -04004677 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004678 return NF_DROP;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004679 } else {
4680 secmark_perm = PACKET__SEND;
Paul Moored8395c82008-10-10 10:16:30 -04004681 peer_sid = SECINITSID_KERNEL;
Steffen Klassert4a7ab3d2011-02-23 12:56:23 +01004682 }
Paul Moored8395c82008-10-10 10:16:30 -04004683 } else {
Paul Mooreeffad8d2008-01-29 08:49:27 -05004684 struct sk_security_struct *sksec = sk->sk_security;
4685 peer_sid = sksec->sid;
4686 secmark_perm = PACKET__SEND;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004687 }
4688
Eric Paris50c205f2012-04-04 15:01:43 -04004689 ad.type = LSM_AUDIT_DATA_NET;
Eric Paris48c62af2012-04-02 13:15:44 -04004690 ad.u.net = &net;
4691 ad.u.net->netif = ifindex;
4692 ad.u.net->family = family;
Paul Moored8395c82008-10-10 10:16:30 -04004693 if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
Eric Paris04f6d702010-11-23 06:28:02 +00004694 return NF_DROP;
Paul Moored8395c82008-10-10 10:16:30 -04004695
Paul Mooreeffad8d2008-01-29 08:49:27 -05004696 if (secmark_active)
4697 if (avc_has_perm(peer_sid, skb->secmark,
4698 SECCLASS_PACKET, secmark_perm, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004699 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004700
4701 if (peerlbl_active) {
4702 u32 if_sid;
4703 u32 node_sid;
4704
4705 if (sel_netif_sid(ifindex, &if_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004706 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004707 if (avc_has_perm(peer_sid, if_sid,
4708 SECCLASS_NETIF, NETIF__EGRESS, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004709 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004710
4711 if (sel_netnode_sid(addrp, family, &node_sid))
Eric Paris04f6d702010-11-23 06:28:02 +00004712 return NF_DROP;
Paul Mooreeffad8d2008-01-29 08:49:27 -05004713 if (avc_has_perm(peer_sid, node_sid,
4714 SECCLASS_NODE, NODE__SENDTO, &ad))
Eric Paris1f1aaf82010-11-16 11:52:57 +00004715 return NF_DROP_ERR(-ECONNREFUSED);
Paul Mooreeffad8d2008-01-29 08:49:27 -05004716 }
4717
4718 return NF_ACCEPT;
4719}
4720
4721static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
4722 struct sk_buff *skb,
4723 const struct net_device *in,
4724 const struct net_device *out,
4725 int (*okfn)(struct sk_buff *))
4726{
4727 return selinux_ip_postroute(skb, out->ifindex, PF_INET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728}
4729
4730#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Paul Mooreeffad8d2008-01-29 08:49:27 -05004731static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
4732 struct sk_buff *skb,
4733 const struct net_device *in,
4734 const struct net_device *out,
4735 int (*okfn)(struct sk_buff *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736{
Paul Mooreeffad8d2008-01-29 08:49:27 -05004737 return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739#endif /* IPV6 */
4740
4741#endif /* CONFIG_NETFILTER */
4742
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
4744{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 int err;
4746
Eric Paris200ac532009-02-12 15:01:04 -05004747 err = cap_netlink_send(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 if (err)
4749 return err;
4750
Stephen Smalley941fc5b2009-10-01 14:48:23 -04004751 return selinux_nlmsg_perm(sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752}
4753
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754static int ipc_alloc_security(struct task_struct *task,
4755 struct kern_ipc_perm *perm,
4756 u16 sclass)
4757{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 struct ipc_security_struct *isec;
David Howells275bb412008-11-14 10:39:19 +11004759 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
James Morris89d155e2005-10-30 14:59:21 -08004761 isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 if (!isec)
4763 return -ENOMEM;
4764
David Howells275bb412008-11-14 10:39:19 +11004765 sid = task_sid(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 isec->sclass = sclass;
David Howells275bb412008-11-14 10:39:19 +11004767 isec->sid = sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 perm->security = isec;
4769
4770 return 0;
4771}
4772
4773static void ipc_free_security(struct kern_ipc_perm *perm)
4774{
4775 struct ipc_security_struct *isec = perm->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 perm->security = NULL;
4777 kfree(isec);
4778}
4779
4780static int msg_msg_alloc_security(struct msg_msg *msg)
4781{
4782 struct msg_security_struct *msec;
4783
James Morris89d155e2005-10-30 14:59:21 -08004784 msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 if (!msec)
4786 return -ENOMEM;
4787
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 msec->sid = SECINITSID_UNLABELED;
4789 msg->security = msec;
4790
4791 return 0;
4792}
4793
4794static void msg_msg_free_security(struct msg_msg *msg)
4795{
4796 struct msg_security_struct *msec = msg->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797
4798 msg->security = NULL;
4799 kfree(msec);
4800}
4801
4802static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
Stephen Smalley6af963f2005-05-01 08:58:39 -07004803 u32 perms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004806 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004807 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 isec = ipc_perms->security;
4810
Eric Paris50c205f2012-04-04 15:01:43 -04004811 ad.type = LSM_AUDIT_DATA_IPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 ad.u.ipc_id = ipc_perms->key;
4813
David Howells275bb412008-11-14 10:39:19 +11004814 return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815}
4816
4817static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
4818{
4819 return msg_msg_alloc_security(msg);
4820}
4821
4822static void selinux_msg_msg_free_security(struct msg_msg *msg)
4823{
4824 msg_msg_free_security(msg);
4825}
4826
4827/* message queue security operations */
4828static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
4829{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004831 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004832 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 int rc;
4834
4835 rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
4836 if (rc)
4837 return rc;
4838
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 isec = msq->q_perm.security;
4840
Eric Paris50c205f2012-04-04 15:01:43 -04004841 ad.type = LSM_AUDIT_DATA_IPC;
Eric Paris828dfe12008-04-17 13:17:49 -04004842 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843
David Howells275bb412008-11-14 10:39:19 +11004844 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 MSGQ__CREATE, &ad);
4846 if (rc) {
4847 ipc_free_security(&msq->q_perm);
4848 return rc;
4849 }
4850 return 0;
4851}
4852
4853static void selinux_msg_queue_free_security(struct msg_queue *msq)
4854{
4855 ipc_free_security(&msq->q_perm);
4856}
4857
4858static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
4859{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004861 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004862 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 isec = msq->q_perm.security;
4865
Eric Paris50c205f2012-04-04 15:01:43 -04004866 ad.type = LSM_AUDIT_DATA_IPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 ad.u.ipc_id = msq->q_perm.key;
4868
David Howells275bb412008-11-14 10:39:19 +11004869 return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 MSGQ__ASSOCIATE, &ad);
4871}
4872
4873static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
4874{
4875 int err;
4876 int perms;
4877
Eric Paris828dfe12008-04-17 13:17:49 -04004878 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 case IPC_INFO:
4880 case MSG_INFO:
4881 /* No specific object, just general system-wide information. */
4882 return task_has_system(current, SYSTEM__IPC_INFO);
4883 case IPC_STAT:
4884 case MSG_STAT:
4885 perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
4886 break;
4887 case IPC_SET:
4888 perms = MSGQ__SETATTR;
4889 break;
4890 case IPC_RMID:
4891 perms = MSGQ__DESTROY;
4892 break;
4893 default:
4894 return 0;
4895 }
4896
Stephen Smalley6af963f2005-05-01 08:58:39 -07004897 err = ipc_has_perm(&msq->q_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 return err;
4899}
4900
4901static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
4902{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 struct ipc_security_struct *isec;
4904 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004905 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004906 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 int rc;
4908
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 isec = msq->q_perm.security;
4910 msec = msg->security;
4911
4912 /*
4913 * First time through, need to assign label to the message
4914 */
4915 if (msec->sid == SECINITSID_UNLABELED) {
4916 /*
4917 * Compute new sid based on current process and
4918 * message queue this message will be stored in
4919 */
David Howells275bb412008-11-14 10:39:19 +11004920 rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
Eric Paris652bb9b2011-02-01 11:05:40 -05004921 NULL, &msec->sid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 if (rc)
4923 return rc;
4924 }
4925
Eric Paris50c205f2012-04-04 15:01:43 -04004926 ad.type = LSM_AUDIT_DATA_IPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 ad.u.ipc_id = msq->q_perm.key;
4928
4929 /* Can this process write to the queue? */
David Howells275bb412008-11-14 10:39:19 +11004930 rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 MSGQ__WRITE, &ad);
4932 if (!rc)
4933 /* Can this process send the message */
David Howells275bb412008-11-14 10:39:19 +11004934 rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
4935 MSG__SEND, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 if (!rc)
4937 /* Can the message be put in the queue? */
David Howells275bb412008-11-14 10:39:19 +11004938 rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
4939 MSGQ__ENQUEUE, &ad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940
4941 return rc;
4942}
4943
4944static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
4945 struct task_struct *target,
4946 long type, int mode)
4947{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 struct ipc_security_struct *isec;
4949 struct msg_security_struct *msec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004950 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004951 u32 sid = task_sid(target);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 int rc;
4953
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 isec = msq->q_perm.security;
4955 msec = msg->security;
4956
Eric Paris50c205f2012-04-04 15:01:43 -04004957 ad.type = LSM_AUDIT_DATA_IPC;
Eric Paris828dfe12008-04-17 13:17:49 -04004958 ad.u.ipc_id = msq->q_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959
David Howells275bb412008-11-14 10:39:19 +11004960 rc = avc_has_perm(sid, isec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 SECCLASS_MSGQ, MSGQ__READ, &ad);
4962 if (!rc)
David Howells275bb412008-11-14 10:39:19 +11004963 rc = avc_has_perm(sid, msec->sid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 SECCLASS_MSG, MSG__RECEIVE, &ad);
4965 return rc;
4966}
4967
4968/* Shared Memory security operations */
4969static int selinux_shm_alloc_security(struct shmid_kernel *shp)
4970{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04004972 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11004973 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 int rc;
4975
4976 rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
4977 if (rc)
4978 return rc;
4979
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 isec = shp->shm_perm.security;
4981
Eric Paris50c205f2012-04-04 15:01:43 -04004982 ad.type = LSM_AUDIT_DATA_IPC;
Eric Paris828dfe12008-04-17 13:17:49 -04004983 ad.u.ipc_id = shp->shm_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
David Howells275bb412008-11-14 10:39:19 +11004985 rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 SHM__CREATE, &ad);
4987 if (rc) {
4988 ipc_free_security(&shp->shm_perm);
4989 return rc;
4990 }
4991 return 0;
4992}
4993
4994static void selinux_shm_free_security(struct shmid_kernel *shp)
4995{
4996 ipc_free_security(&shp->shm_perm);
4997}
4998
4999static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
5000{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005002 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005003 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 isec = shp->shm_perm.security;
5006
Eric Paris50c205f2012-04-04 15:01:43 -04005007 ad.type = LSM_AUDIT_DATA_IPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 ad.u.ipc_id = shp->shm_perm.key;
5009
David Howells275bb412008-11-14 10:39:19 +11005010 return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 SHM__ASSOCIATE, &ad);
5012}
5013
5014/* Note, at this point, shp is locked down */
5015static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
5016{
5017 int perms;
5018 int err;
5019
Eric Paris828dfe12008-04-17 13:17:49 -04005020 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 case IPC_INFO:
5022 case SHM_INFO:
5023 /* No specific object, just general system-wide information. */
5024 return task_has_system(current, SYSTEM__IPC_INFO);
5025 case IPC_STAT:
5026 case SHM_STAT:
5027 perms = SHM__GETATTR | SHM__ASSOCIATE;
5028 break;
5029 case IPC_SET:
5030 perms = SHM__SETATTR;
5031 break;
5032 case SHM_LOCK:
5033 case SHM_UNLOCK:
5034 perms = SHM__LOCK;
5035 break;
5036 case IPC_RMID:
5037 perms = SHM__DESTROY;
5038 break;
5039 default:
5040 return 0;
5041 }
5042
Stephen Smalley6af963f2005-05-01 08:58:39 -07005043 err = ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 return err;
5045}
5046
5047static int selinux_shm_shmat(struct shmid_kernel *shp,
5048 char __user *shmaddr, int shmflg)
5049{
5050 u32 perms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
5052 if (shmflg & SHM_RDONLY)
5053 perms = SHM__READ;
5054 else
5055 perms = SHM__READ | SHM__WRITE;
5056
Stephen Smalley6af963f2005-05-01 08:58:39 -07005057 return ipc_has_perm(&shp->shm_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058}
5059
5060/* Semaphore security operations */
5061static int selinux_sem_alloc_security(struct sem_array *sma)
5062{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005064 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005065 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 int rc;
5067
5068 rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
5069 if (rc)
5070 return rc;
5071
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 isec = sma->sem_perm.security;
5073
Eric Paris50c205f2012-04-04 15:01:43 -04005074 ad.type = LSM_AUDIT_DATA_IPC;
Eric Paris828dfe12008-04-17 13:17:49 -04005075 ad.u.ipc_id = sma->sem_perm.key;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076
David Howells275bb412008-11-14 10:39:19 +11005077 rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 SEM__CREATE, &ad);
5079 if (rc) {
5080 ipc_free_security(&sma->sem_perm);
5081 return rc;
5082 }
5083 return 0;
5084}
5085
5086static void selinux_sem_free_security(struct sem_array *sma)
5087{
5088 ipc_free_security(&sma->sem_perm);
5089}
5090
5091static int selinux_sem_associate(struct sem_array *sma, int semflg)
5092{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 struct ipc_security_struct *isec;
Thomas Liu2bf49692009-07-14 12:14:09 -04005094 struct common_audit_data ad;
David Howells275bb412008-11-14 10:39:19 +11005095 u32 sid = current_sid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 isec = sma->sem_perm.security;
5098
Eric Paris50c205f2012-04-04 15:01:43 -04005099 ad.type = LSM_AUDIT_DATA_IPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 ad.u.ipc_id = sma->sem_perm.key;
5101
David Howells275bb412008-11-14 10:39:19 +11005102 return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 SEM__ASSOCIATE, &ad);
5104}
5105
5106/* Note, at this point, sma is locked down */
5107static int selinux_sem_semctl(struct sem_array *sma, int cmd)
5108{
5109 int err;
5110 u32 perms;
5111
Eric Paris828dfe12008-04-17 13:17:49 -04005112 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 case IPC_INFO:
5114 case SEM_INFO:
5115 /* No specific object, just general system-wide information. */
5116 return task_has_system(current, SYSTEM__IPC_INFO);
5117 case GETPID:
5118 case GETNCNT:
5119 case GETZCNT:
5120 perms = SEM__GETATTR;
5121 break;
5122 case GETVAL:
5123 case GETALL:
5124 perms = SEM__READ;
5125 break;
5126 case SETVAL:
5127 case SETALL:
5128 perms = SEM__WRITE;
5129 break;
5130 case IPC_RMID:
5131 perms = SEM__DESTROY;
5132 break;
5133 case IPC_SET:
5134 perms = SEM__SETATTR;
5135 break;
5136 case IPC_STAT:
5137 case SEM_STAT:
5138 perms = SEM__GETATTR | SEM__ASSOCIATE;
5139 break;
5140 default:
5141 return 0;
5142 }
5143
Stephen Smalley6af963f2005-05-01 08:58:39 -07005144 err = ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 return err;
5146}
5147
5148static int selinux_sem_semop(struct sem_array *sma,
5149 struct sembuf *sops, unsigned nsops, int alter)
5150{
5151 u32 perms;
5152
5153 if (alter)
5154 perms = SEM__READ | SEM__WRITE;
5155 else
5156 perms = SEM__READ;
5157
Stephen Smalley6af963f2005-05-01 08:58:39 -07005158 return ipc_has_perm(&sma->sem_perm, perms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159}
5160
5161static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
5162{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 u32 av = 0;
5164
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 av = 0;
5166 if (flag & S_IRUGO)
5167 av |= IPC__UNIX_READ;
5168 if (flag & S_IWUGO)
5169 av |= IPC__UNIX_WRITE;
5170
5171 if (av == 0)
5172 return 0;
5173
Stephen Smalley6af963f2005-05-01 08:58:39 -07005174 return ipc_has_perm(ipcp, av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175}
5176
Ahmed S. Darwish713a04a2008-03-01 21:52:30 +02005177static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
5178{
5179 struct ipc_security_struct *isec = ipcp->security;
5180 *secid = isec->sid;
5181}
5182
Eric Paris828dfe12008-04-17 13:17:49 -04005183static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184{
5185 if (inode)
5186 inode_doinit_with_dentry(inode, dentry);
5187}
5188
5189static int selinux_getprocattr(struct task_struct *p,
Al Viro04ff9702007-03-12 16:17:58 +00005190 char *name, char **value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191{
David Howells275bb412008-11-14 10:39:19 +11005192 const struct task_security_struct *__tsec;
Dustin Kirkland8c8570f2005-11-03 17:15:16 +00005193 u32 sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 int error;
Al Viro04ff9702007-03-12 16:17:58 +00005195 unsigned len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196
5197 if (current != p) {
David Howells3b11a1d2008-11-14 10:39:26 +11005198 error = current_has_perm(p, PROCESS__GETATTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 if (error)
5200 return error;
5201 }
5202
David Howells275bb412008-11-14 10:39:19 +11005203 rcu_read_lock();
5204 __tsec = __task_cred(p)->security;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205
5206 if (!strcmp(name, "current"))
David Howells275bb412008-11-14 10:39:19 +11005207 sid = __tsec->sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 else if (!strcmp(name, "prev"))
David Howells275bb412008-11-14 10:39:19 +11005209 sid = __tsec->osid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 else if (!strcmp(name, "exec"))
David Howells275bb412008-11-14 10:39:19 +11005211 sid = __tsec->exec_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 else if (!strcmp(name, "fscreate"))
David Howells275bb412008-11-14 10:39:19 +11005213 sid = __tsec->create_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005214 else if (!strcmp(name, "keycreate"))
David Howells275bb412008-11-14 10:39:19 +11005215 sid = __tsec->keycreate_sid;
Eric Paris42c3e032006-06-26 00:26:03 -07005216 else if (!strcmp(name, "sockcreate"))
David Howells275bb412008-11-14 10:39:19 +11005217 sid = __tsec->sockcreate_sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 else
David Howells275bb412008-11-14 10:39:19 +11005219 goto invalid;
5220 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221
5222 if (!sid)
5223 return 0;
5224
Al Viro04ff9702007-03-12 16:17:58 +00005225 error = security_sid_to_context(sid, value, &len);
5226 if (error)
5227 return error;
5228 return len;
David Howells275bb412008-11-14 10:39:19 +11005229
5230invalid:
5231 rcu_read_unlock();
5232 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233}
5234
5235static int selinux_setprocattr(struct task_struct *p,
5236 char *name, void *value, size_t size)
5237{
5238 struct task_security_struct *tsec;
Roland McGrath03563572008-03-26 15:46:39 -07005239 struct task_struct *tracer;
David Howellsd84f4f92008-11-14 10:39:23 +11005240 struct cred *new;
5241 u32 sid = 0, ptsid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 int error;
5243 char *str = value;
5244
5245 if (current != p) {
5246 /* SELinux only allows a process to change its own
5247 security attributes. */
5248 return -EACCES;
5249 }
5250
5251 /*
5252 * Basic control over ability to set these attributes at all.
5253 * current == p, but we'll pass them separately in case the
5254 * above restriction is ever removed.
5255 */
5256 if (!strcmp(name, "exec"))
David Howells3b11a1d2008-11-14 10:39:26 +11005257 error = current_has_perm(p, PROCESS__SETEXEC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 else if (!strcmp(name, "fscreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005259 error = current_has_perm(p, PROCESS__SETFSCREATE);
Michael LeMay4eb582c2006-06-26 00:24:57 -07005260 else if (!strcmp(name, "keycreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005261 error = current_has_perm(p, PROCESS__SETKEYCREATE);
Eric Paris42c3e032006-06-26 00:26:03 -07005262 else if (!strcmp(name, "sockcreate"))
David Howells3b11a1d2008-11-14 10:39:26 +11005263 error = current_has_perm(p, PROCESS__SETSOCKCREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 else if (!strcmp(name, "current"))
David Howells3b11a1d2008-11-14 10:39:26 +11005265 error = current_has_perm(p, PROCESS__SETCURRENT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 else
5267 error = -EINVAL;
5268 if (error)
5269 return error;
5270
5271 /* Obtain a SID for the context, if one was specified. */
5272 if (size && str[1] && str[1] != '\n') {
5273 if (str[size-1] == '\n') {
5274 str[size-1] = 0;
5275 size--;
5276 }
5277 error = security_context_to_sid(value, size, &sid);
Stephen Smalley12b29f32008-05-07 13:03:20 -04005278 if (error == -EINVAL && !strcmp(name, "fscreate")) {
Eric Parisd6ea83e2012-04-04 13:45:49 -04005279 if (!capable(CAP_MAC_ADMIN)) {
5280 struct audit_buffer *ab;
5281 size_t audit_size;
5282
5283 /* We strip a nul only if it is at the end, otherwise the
5284 * context contains a nul and we should audit that */
5285 if (str[size - 1] == '\0')
5286 audit_size = size - 1;
5287 else
5288 audit_size = size;
5289 ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
5290 audit_log_format(ab, "op=fscreate invalid_context=");
5291 audit_log_n_untrustedstring(ab, value, audit_size);
5292 audit_log_end(ab);
5293
Stephen Smalley12b29f32008-05-07 13:03:20 -04005294 return error;
Eric Parisd6ea83e2012-04-04 13:45:49 -04005295 }
Stephen Smalley12b29f32008-05-07 13:03:20 -04005296 error = security_context_to_sid_force(value, size,
5297 &sid);
5298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 if (error)
5300 return error;
5301 }
5302
David Howellsd84f4f92008-11-14 10:39:23 +11005303 new = prepare_creds();
5304 if (!new)
5305 return -ENOMEM;
5306
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 /* Permission checking based on the specified context is
5308 performed during the actual operation (execve,
5309 open/mkdir/...), when we know the full context of the
David Howellsd84f4f92008-11-14 10:39:23 +11005310 operation. See selinux_bprm_set_creds for the execve
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 checks and may_create for the file creation checks. The
5312 operation will then fail if the context is not permitted. */
David Howellsd84f4f92008-11-14 10:39:23 +11005313 tsec = new->security;
5314 if (!strcmp(name, "exec")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 tsec->exec_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005316 } else if (!strcmp(name, "fscreate")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 tsec->create_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005318 } else if (!strcmp(name, "keycreate")) {
Michael LeMay4eb582c2006-06-26 00:24:57 -07005319 error = may_create_key(sid, p);
5320 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005321 goto abort_change;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005322 tsec->keycreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005323 } else if (!strcmp(name, "sockcreate")) {
Eric Paris42c3e032006-06-26 00:26:03 -07005324 tsec->sockcreate_sid = sid;
David Howellsd84f4f92008-11-14 10:39:23 +11005325 } else if (!strcmp(name, "current")) {
5326 error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 if (sid == 0)
David Howellsd84f4f92008-11-14 10:39:23 +11005328 goto abort_change;
KaiGai Koheid9250de2008-08-28 16:35:57 +09005329
David Howellsd84f4f92008-11-14 10:39:23 +11005330 /* Only allow single threaded processes to change context */
5331 error = -EPERM;
Oleg Nesterov5bb459b2009-07-10 03:48:23 +02005332 if (!current_is_single_threaded()) {
David Howellsd84f4f92008-11-14 10:39:23 +11005333 error = security_bounded_transition(tsec->sid, sid);
5334 if (error)
5335 goto abort_change;
Eric Paris828dfe12008-04-17 13:17:49 -04005336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337
5338 /* Check permissions for the transition. */
5339 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
Eric Paris828dfe12008-04-17 13:17:49 -04005340 PROCESS__DYNTRANSITION, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 if (error)
David Howellsd84f4f92008-11-14 10:39:23 +11005342 goto abort_change;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343
5344 /* Check for ptracing, and update the task SID if ok.
5345 Otherwise, leave SID unchanged and fail. */
David Howellsd84f4f92008-11-14 10:39:23 +11005346 ptsid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 task_lock(p);
Tejun Heo06d98472011-06-17 16:50:40 +02005348 tracer = ptrace_parent(p);
David Howellsd84f4f92008-11-14 10:39:23 +11005349 if (tracer)
5350 ptsid = task_sid(tracer);
5351 task_unlock(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
David Howellsd84f4f92008-11-14 10:39:23 +11005353 if (tracer) {
5354 error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
5355 PROCESS__PTRACE, NULL);
5356 if (error)
5357 goto abort_change;
5358 }
5359
5360 tsec->sid = sid;
5361 } else {
5362 error = -EINVAL;
5363 goto abort_change;
5364 }
5365
5366 commit_creds(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 return size;
David Howellsd84f4f92008-11-14 10:39:23 +11005368
5369abort_change:
5370 abort_creds(new);
5371 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372}
5373
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005374static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
5375{
5376 return security_sid_to_context(secid, secdata, seclen);
5377}
5378
David Howells7bf570d2008-04-29 20:52:51 +01005379static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
David Howells63cb3442008-01-15 23:47:35 +00005380{
5381 return security_context_to_sid(secdata, seclen, secid);
5382}
5383
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005384static void selinux_release_secctx(char *secdata, u32 seclen)
5385{
Paul Moore088999e2007-08-01 11:12:58 -04005386 kfree(secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005387}
5388
David P. Quigley1ee65e32009-09-03 14:25:57 -04005389/*
5390 * called with inode->i_mutex locked
5391 */
5392static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
5393{
5394 return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
5395}
5396
5397/*
5398 * called with inode->i_mutex locked
5399 */
5400static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
5401{
5402 return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
5403}
5404
5405static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
5406{
5407 int len = 0;
5408 len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
5409 ctx, true);
5410 if (len < 0)
5411 return len;
5412 *ctxlen = len;
5413 return 0;
5414}
Michael LeMayd7200242006-06-22 14:47:17 -07005415#ifdef CONFIG_KEYS
5416
David Howellsd84f4f92008-11-14 10:39:23 +11005417static int selinux_key_alloc(struct key *k, const struct cred *cred,
David Howells7e047ef2006-06-26 00:24:50 -07005418 unsigned long flags)
Michael LeMayd7200242006-06-22 14:47:17 -07005419{
David Howellsd84f4f92008-11-14 10:39:23 +11005420 const struct task_security_struct *tsec;
Michael LeMayd7200242006-06-22 14:47:17 -07005421 struct key_security_struct *ksec;
5422
5423 ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
5424 if (!ksec)
5425 return -ENOMEM;
5426
David Howellsd84f4f92008-11-14 10:39:23 +11005427 tsec = cred->security;
5428 if (tsec->keycreate_sid)
5429 ksec->sid = tsec->keycreate_sid;
Michael LeMay4eb582c2006-06-26 00:24:57 -07005430 else
David Howellsd84f4f92008-11-14 10:39:23 +11005431 ksec->sid = tsec->sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005432
David Howells275bb412008-11-14 10:39:19 +11005433 k->security = ksec;
Michael LeMayd7200242006-06-22 14:47:17 -07005434 return 0;
5435}
5436
5437static void selinux_key_free(struct key *k)
5438{
5439 struct key_security_struct *ksec = k->security;
5440
5441 k->security = NULL;
5442 kfree(ksec);
5443}
5444
5445static int selinux_key_permission(key_ref_t key_ref,
David Howellsd84f4f92008-11-14 10:39:23 +11005446 const struct cred *cred,
5447 key_perm_t perm)
Michael LeMayd7200242006-06-22 14:47:17 -07005448{
5449 struct key *key;
Michael LeMayd7200242006-06-22 14:47:17 -07005450 struct key_security_struct *ksec;
David Howells275bb412008-11-14 10:39:19 +11005451 u32 sid;
Michael LeMayd7200242006-06-22 14:47:17 -07005452
5453 /* if no specific permissions are requested, we skip the
5454 permission check. No serious, additional covert channels
5455 appear to be created. */
5456 if (perm == 0)
5457 return 0;
5458
David Howellsd84f4f92008-11-14 10:39:23 +11005459 sid = cred_sid(cred);
David Howells275bb412008-11-14 10:39:19 +11005460
5461 key = key_ref_to_ptr(key_ref);
5462 ksec = key->security;
5463
5464 return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
Michael LeMayd7200242006-06-22 14:47:17 -07005465}
5466
David Howells70a5bb72008-04-29 01:01:26 -07005467static int selinux_key_getsecurity(struct key *key, char **_buffer)
5468{
5469 struct key_security_struct *ksec = key->security;
5470 char *context = NULL;
5471 unsigned len;
5472 int rc;
5473
5474 rc = security_sid_to_context(ksec->sid, &context, &len);
5475 if (!rc)
5476 rc = len;
5477 *_buffer = context;
5478 return rc;
5479}
5480
Michael LeMayd7200242006-06-22 14:47:17 -07005481#endif
5482
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483static struct security_operations selinux_ops = {
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005484 .name = "selinux",
5485
Ingo Molnar9e488582009-05-07 19:26:19 +10005486 .ptrace_access_check = selinux_ptrace_access_check,
David Howells5cd9c582008-08-14 11:37:28 +01005487 .ptrace_traceme = selinux_ptrace_traceme,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 .capget = selinux_capget,
David Howellsd84f4f92008-11-14 10:39:23 +11005489 .capset = selinux_capset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 .capable = selinux_capable,
5491 .quotactl = selinux_quotactl,
5492 .quota_on = selinux_quota_on,
5493 .syslog = selinux_syslog,
5494 .vm_enough_memory = selinux_vm_enough_memory,
5495
5496 .netlink_send = selinux_netlink_send,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
David Howellsa6f76f22008-11-14 10:39:24 +11005498 .bprm_set_creds = selinux_bprm_set_creds,
David Howellsa6f76f22008-11-14 10:39:24 +11005499 .bprm_committing_creds = selinux_bprm_committing_creds,
5500 .bprm_committed_creds = selinux_bprm_committed_creds,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 .bprm_secureexec = selinux_bprm_secureexec,
5502
5503 .sb_alloc_security = selinux_sb_alloc_security,
5504 .sb_free_security = selinux_sb_free_security,
5505 .sb_copy_data = selinux_sb_copy_data,
Eric Paris026eb162011-03-03 16:09:14 -05005506 .sb_remount = selinux_sb_remount,
Eric Paris828dfe12008-04-17 13:17:49 -04005507 .sb_kern_mount = selinux_sb_kern_mount,
Eric Paris2069f452008-07-04 09:47:13 +10005508 .sb_show_options = selinux_sb_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 .sb_statfs = selinux_sb_statfs,
5510 .sb_mount = selinux_mount,
5511 .sb_umount = selinux_umount,
Eric Parisc9180a52007-11-30 13:00:35 -05005512 .sb_set_mnt_opts = selinux_set_mnt_opts,
Eric Paris828dfe12008-04-17 13:17:49 -04005513 .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
Eric Parise0007522008-03-05 10:31:54 -05005514 .sb_parse_opts_str = selinux_parse_opts_str,
5515
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
5517 .inode_alloc_security = selinux_inode_alloc_security,
5518 .inode_free_security = selinux_inode_free_security,
Stephen Smalley5e41ff92005-09-09 13:01:35 -07005519 .inode_init_security = selinux_inode_init_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 .inode_create = selinux_inode_create,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 .inode_link = selinux_inode_link,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 .inode_unlink = selinux_inode_unlink,
5523 .inode_symlink = selinux_inode_symlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 .inode_mkdir = selinux_inode_mkdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 .inode_rmdir = selinux_inode_rmdir,
5526 .inode_mknod = selinux_inode_mknod,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 .inode_rename = selinux_inode_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 .inode_readlink = selinux_inode_readlink,
5529 .inode_follow_link = selinux_inode_follow_link,
5530 .inode_permission = selinux_inode_permission,
5531 .inode_setattr = selinux_inode_setattr,
5532 .inode_getattr = selinux_inode_getattr,
5533 .inode_setxattr = selinux_inode_setxattr,
5534 .inode_post_setxattr = selinux_inode_post_setxattr,
5535 .inode_getxattr = selinux_inode_getxattr,
5536 .inode_listxattr = selinux_inode_listxattr,
5537 .inode_removexattr = selinux_inode_removexattr,
Eric Paris828dfe12008-04-17 13:17:49 -04005538 .inode_getsecurity = selinux_inode_getsecurity,
5539 .inode_setsecurity = selinux_inode_setsecurity,
5540 .inode_listsecurity = selinux_inode_listsecurity,
Eric Parisf5269712008-05-14 11:27:45 -04005541 .inode_getsecid = selinux_inode_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542
5543 .file_permission = selinux_file_permission,
5544 .file_alloc_security = selinux_file_alloc_security,
5545 .file_free_security = selinux_file_free_security,
5546 .file_ioctl = selinux_file_ioctl,
Al Viroe5467852012-05-30 13:30:51 -04005547 .mmap_file = selinux_mmap_file,
5548 .mmap_addr = selinux_mmap_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 .file_mprotect = selinux_file_mprotect,
5550 .file_lock = selinux_file_lock,
5551 .file_fcntl = selinux_file_fcntl,
5552 .file_set_fowner = selinux_file_set_fowner,
5553 .file_send_sigiotask = selinux_file_send_sigiotask,
5554 .file_receive = selinux_file_receive,
5555
Eric Paris83d49852012-04-04 13:45:40 -04005556 .file_open = selinux_file_open,
Yuichi Nakamura788e7dd2007-09-14 09:27:07 +09005557
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 .task_create = selinux_task_create,
David Howellsee18d642009-09-02 09:14:21 +01005559 .cred_alloc_blank = selinux_cred_alloc_blank,
David Howellsf1752ee2008-11-14 10:39:17 +11005560 .cred_free = selinux_cred_free,
David Howellsd84f4f92008-11-14 10:39:23 +11005561 .cred_prepare = selinux_cred_prepare,
David Howellsee18d642009-09-02 09:14:21 +01005562 .cred_transfer = selinux_cred_transfer,
David Howells3a3b7ce2008-11-14 10:39:28 +11005563 .kernel_act_as = selinux_kernel_act_as,
5564 .kernel_create_files_as = selinux_kernel_create_files_as,
Eric Paris25354c42009-08-13 09:45:03 -04005565 .kernel_module_request = selinux_kernel_module_request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 .task_setpgid = selinux_task_setpgid,
5567 .task_getpgid = selinux_task_getpgid,
Eric Paris828dfe12008-04-17 13:17:49 -04005568 .task_getsid = selinux_task_getsid,
David Quigleyf9008e42006-06-30 01:55:46 -07005569 .task_getsecid = selinux_task_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 .task_setnice = selinux_task_setnice,
James Morris03e68062006-06-23 02:03:58 -07005571 .task_setioprio = selinux_task_setioprio,
David Quigleya1836a42006-06-30 01:55:49 -07005572 .task_getioprio = selinux_task_getioprio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 .task_setrlimit = selinux_task_setrlimit,
5574 .task_setscheduler = selinux_task_setscheduler,
5575 .task_getscheduler = selinux_task_getscheduler,
David Quigley35601542006-06-23 02:04:01 -07005576 .task_movememory = selinux_task_movememory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 .task_kill = selinux_task_kill,
5578 .task_wait = selinux_task_wait,
Eric Paris828dfe12008-04-17 13:17:49 -04005579 .task_to_inode = selinux_task_to_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
5581 .ipc_permission = selinux_ipc_permission,
Eric Parisf5269712008-05-14 11:27:45 -04005582 .ipc_getsecid = selinux_ipc_getsecid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
5584 .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
5585 .msg_msg_free_security = selinux_msg_msg_free_security,
5586
5587 .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
5588 .msg_queue_free_security = selinux_msg_queue_free_security,
5589 .msg_queue_associate = selinux_msg_queue_associate,
5590 .msg_queue_msgctl = selinux_msg_queue_msgctl,
5591 .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
5592 .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
5593
5594 .shm_alloc_security = selinux_shm_alloc_security,
5595 .shm_free_security = selinux_shm_free_security,
5596 .shm_associate = selinux_shm_associate,
5597 .shm_shmctl = selinux_shm_shmctl,
5598 .shm_shmat = selinux_shm_shmat,
5599
Eric Paris828dfe12008-04-17 13:17:49 -04005600 .sem_alloc_security = selinux_sem_alloc_security,
5601 .sem_free_security = selinux_sem_free_security,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 .sem_associate = selinux_sem_associate,
5603 .sem_semctl = selinux_sem_semctl,
5604 .sem_semop = selinux_sem_semop,
5605
Eric Paris828dfe12008-04-17 13:17:49 -04005606 .d_instantiate = selinux_d_instantiate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607
Eric Paris828dfe12008-04-17 13:17:49 -04005608 .getprocattr = selinux_getprocattr,
5609 .setprocattr = selinux_setprocattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005611 .secid_to_secctx = selinux_secid_to_secctx,
David Howells63cb3442008-01-15 23:47:35 +00005612 .secctx_to_secid = selinux_secctx_to_secid,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005613 .release_secctx = selinux_release_secctx,
David P. Quigley1ee65e32009-09-03 14:25:57 -04005614 .inode_notifysecctx = selinux_inode_notifysecctx,
5615 .inode_setsecctx = selinux_inode_setsecctx,
5616 .inode_getsecctx = selinux_inode_getsecctx,
Catherine Zhangdc49c1f2006-08-02 14:12:06 -07005617
Eric Paris828dfe12008-04-17 13:17:49 -04005618 .unix_stream_connect = selinux_socket_unix_stream_connect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 .unix_may_send = selinux_socket_unix_may_send,
5620
5621 .socket_create = selinux_socket_create,
5622 .socket_post_create = selinux_socket_post_create,
5623 .socket_bind = selinux_socket_bind,
5624 .socket_connect = selinux_socket_connect,
5625 .socket_listen = selinux_socket_listen,
5626 .socket_accept = selinux_socket_accept,
5627 .socket_sendmsg = selinux_socket_sendmsg,
5628 .socket_recvmsg = selinux_socket_recvmsg,
5629 .socket_getsockname = selinux_socket_getsockname,
5630 .socket_getpeername = selinux_socket_getpeername,
5631 .socket_getsockopt = selinux_socket_getsockopt,
5632 .socket_setsockopt = selinux_socket_setsockopt,
5633 .socket_shutdown = selinux_socket_shutdown,
5634 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
Catherine Zhang2c7946a2006-03-20 22:41:23 -08005635 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
5636 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 .sk_alloc_security = selinux_sk_alloc_security,
5638 .sk_free_security = selinux_sk_free_security,
Venkat Yekkirala892c1412006-08-04 23:08:56 -07005639 .sk_clone_security = selinux_sk_clone_security,
Eric Paris828dfe12008-04-17 13:17:49 -04005640 .sk_getsecid = selinux_sk_getsecid,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005641 .sock_graft = selinux_sock_graft,
5642 .inet_conn_request = selinux_inet_conn_request,
5643 .inet_csk_clone = selinux_inet_csk_clone,
Venkat Yekkirala6b877692006-11-08 17:04:09 -06005644 .inet_conn_established = selinux_inet_conn_established,
Eric Paris2606fd12010-10-13 16:24:41 -04005645 .secmark_relabel_packet = selinux_secmark_relabel_packet,
5646 .secmark_refcount_inc = selinux_secmark_refcount_inc,
5647 .secmark_refcount_dec = selinux_secmark_refcount_dec,
Venkat Yekkirala4237c752006-07-24 23:32:50 -07005648 .req_classify_flow = selinux_req_classify_flow,
Paul Mooreed6d76e2009-08-28 18:12:49 -04005649 .tun_dev_create = selinux_tun_dev_create,
5650 .tun_dev_post_create = selinux_tun_dev_post_create,
5651 .tun_dev_attach = selinux_tun_dev_attach,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005652
5653#ifdef CONFIG_SECURITY_NETWORK_XFRM
5654 .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
5655 .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
5656 .xfrm_policy_free_security = selinux_xfrm_policy_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005657 .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005658 .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
5659 .xfrm_state_free_security = selinux_xfrm_state_free,
Catherine Zhangc8c05a82006-06-08 23:39:49 -07005660 .xfrm_state_delete_security = selinux_xfrm_state_delete,
Eric Paris828dfe12008-04-17 13:17:49 -04005661 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005662 .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
Venkat Yekkiralae0d1caa2006-07-24 23:29:07 -07005663 .xfrm_decode_session = selinux_xfrm_decode_session,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664#endif
Michael LeMayd7200242006-06-22 14:47:17 -07005665
5666#ifdef CONFIG_KEYS
Eric Paris828dfe12008-04-17 13:17:49 -04005667 .key_alloc = selinux_key_alloc,
5668 .key_free = selinux_key_free,
5669 .key_permission = selinux_key_permission,
David Howells70a5bb72008-04-29 01:01:26 -07005670 .key_getsecurity = selinux_key_getsecurity,
Michael LeMayd7200242006-06-22 14:47:17 -07005671#endif
Ahmed S. Darwish9d57a7f2008-03-01 22:03:14 +02005672
5673#ifdef CONFIG_AUDIT
5674 .audit_rule_init = selinux_audit_rule_init,
5675 .audit_rule_known = selinux_audit_rule_known,
5676 .audit_rule_match = selinux_audit_rule_match,
5677 .audit_rule_free = selinux_audit_rule_free,
5678#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679};
5680
5681static __init int selinux_init(void)
5682{
Ahmed S. Darwish076c54c2008-03-06 18:09:10 +02005683 if (!security_module_enable(&selinux_ops)) {
5684 selinux_enabled = 0;
5685 return 0;
5686 }
5687
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 if (!selinux_enabled) {
5689 printk(KERN_INFO "SELinux: Disabled at boot.\n");
5690 return 0;
5691 }
5692
5693 printk(KERN_INFO "SELinux: Initializing.\n");
5694
5695 /* Set the security state for the initial task. */
David Howellsd84f4f92008-11-14 10:39:23 +11005696 cred_init_security();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
Stephen Smalleyfcaaade2010-04-28 15:57:57 -04005698 default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
5699
James Morris7cae7e22006-03-22 00:09:22 -08005700 sel_inode_cache = kmem_cache_create("selinux_inode_security",
5701 sizeof(struct inode_security_struct),
Paul Mundt20c2df82007-07-20 10:11:58 +09005702 0, SLAB_PANIC, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 avc_init();
5704
Eric Paris828dfe12008-04-17 13:17:49 -04005705 if (register_security(&selinux_ops))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 panic("SELinux: Unable to register with kernel.\n");
5707
Eric Paris828dfe12008-04-17 13:17:49 -04005708 if (selinux_enforcing)
Eric Parisfadcdb42007-02-22 18:11:31 -05005709 printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
Eric Paris828dfe12008-04-17 13:17:49 -04005710 else
Eric Parisfadcdb42007-02-22 18:11:31 -05005711 printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
Michael LeMayd7200242006-06-22 14:47:17 -07005712
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 return 0;
5714}
5715
Al Viroe8c26252010-03-23 06:36:54 -04005716static void delayed_superblock_init(struct super_block *sb, void *unused)
5717{
5718 superblock_doinit(sb, NULL);
5719}
5720
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721void selinux_complete_init(void)
5722{
Eric Parisfadcdb42007-02-22 18:11:31 -05005723 printk(KERN_DEBUG "SELinux: Completing initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
5725 /* Set up any superblocks initialized prior to the policy load. */
Eric Parisfadcdb42007-02-22 18:11:31 -05005726 printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n");
Al Viroe8c26252010-03-23 06:36:54 -04005727 iterate_supers(delayed_superblock_init, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728}
5729
5730/* SELinux requires early initialization in order to label
5731 all processes and objects when they are created. */
5732security_initcall(selinux_init);
5733
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005734#if defined(CONFIG_NETFILTER)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
Paul Mooreeffad8d2008-01-29 08:49:27 -05005736static struct nf_hook_ops selinux_ipv4_ops[] = {
5737 {
5738 .hook = selinux_ipv4_postroute,
5739 .owner = THIS_MODULE,
Alban Crequy2597a832012-05-14 03:56:39 +00005740 .pf = NFPROTO_IPV4,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005741 .hooknum = NF_INET_POST_ROUTING,
5742 .priority = NF_IP_PRI_SELINUX_LAST,
5743 },
5744 {
5745 .hook = selinux_ipv4_forward,
5746 .owner = THIS_MODULE,
Alban Crequy2597a832012-05-14 03:56:39 +00005747 .pf = NFPROTO_IPV4,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005748 .hooknum = NF_INET_FORWARD,
5749 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Moore948bf852008-10-10 10:16:32 -04005750 },
5751 {
5752 .hook = selinux_ipv4_output,
5753 .owner = THIS_MODULE,
Alban Crequy2597a832012-05-14 03:56:39 +00005754 .pf = NFPROTO_IPV4,
Paul Moore948bf852008-10-10 10:16:32 -04005755 .hooknum = NF_INET_LOCAL_OUT,
5756 .priority = NF_IP_PRI_SELINUX_FIRST,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758};
5759
5760#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
5761
Paul Mooreeffad8d2008-01-29 08:49:27 -05005762static struct nf_hook_ops selinux_ipv6_ops[] = {
5763 {
5764 .hook = selinux_ipv6_postroute,
5765 .owner = THIS_MODULE,
Alban Crequy2597a832012-05-14 03:56:39 +00005766 .pf = NFPROTO_IPV6,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005767 .hooknum = NF_INET_POST_ROUTING,
5768 .priority = NF_IP6_PRI_SELINUX_LAST,
5769 },
5770 {
5771 .hook = selinux_ipv6_forward,
5772 .owner = THIS_MODULE,
Alban Crequy2597a832012-05-14 03:56:39 +00005773 .pf = NFPROTO_IPV6,
Paul Mooreeffad8d2008-01-29 08:49:27 -05005774 .hooknum = NF_INET_FORWARD,
5775 .priority = NF_IP6_PRI_SELINUX_FIRST,
5776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777};
5778
5779#endif /* IPV6 */
5780
5781static int __init selinux_nf_ip_init(void)
5782{
5783 int err = 0;
5784
5785 if (!selinux_enabled)
5786 goto out;
Eric Parisfadcdb42007-02-22 18:11:31 -05005787
5788 printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
5789
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005790 err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
5791 if (err)
5792 panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793
5794#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005795 err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
5796 if (err)
5797 panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798#endif /* IPV6 */
Trent Jaegerd28d1e02005-12-13 23:12:40 -08005799
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800out:
5801 return err;
5802}
5803
5804__initcall(selinux_nf_ip_init);
5805
5806#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5807static void selinux_nf_ip_exit(void)
5808{
Eric Parisfadcdb42007-02-22 18:11:31 -05005809 printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005811 nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
Alexey Dobriyan6c5a9d22008-07-26 17:48:15 -07005813 nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814#endif /* IPV6 */
5815}
5816#endif
5817
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005818#else /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819
5820#ifdef CONFIG_SECURITY_SELINUX_DISABLE
5821#define selinux_nf_ip_exit()
5822#endif
5823
Stephen Smalleyc2b507f2006-02-04 23:27:50 -08005824#endif /* CONFIG_NETFILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825
5826#ifdef CONFIG_SECURITY_SELINUX_DISABLE
Eric Paris828dfe12008-04-17 13:17:49 -04005827static int selinux_disabled;
5828
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829int selinux_disable(void)
5830{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 if (ss_initialized) {
5832 /* Not permitted after initial policy load. */
5833 return -EINVAL;
5834 }
5835
5836 if (selinux_disabled) {
5837 /* Only do this once. */
5838 return -EINVAL;
5839 }
5840
5841 printk(KERN_INFO "SELinux: Disabled at runtime.\n");
5842
5843 selinux_disabled = 1;
Stephen Smalley30d55282006-05-03 10:52:36 -04005844 selinux_enabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
wzt.wzt@gmail.com189b3b12010-02-23 23:15:28 +08005846 reset_security_ops();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
Eric Parisaf8ff042009-09-20 21:23:01 -04005848 /* Try to destroy the avc node cache */
5849 avc_disable();
5850
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 /* Unregister netfilter hooks. */
5852 selinux_nf_ip_exit();
5853
5854 /* Unregister selinuxfs. */
5855 exit_sel_fs();
5856
5857 return 0;
5858}
5859#endif