2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* NSA Security-Enhanced Linux (SELinux) security module
|
|
|
|
*
|
|
|
|
* This file contains the SELinux security data structures for kernel objects.
|
|
|
|
*
|
2017-08-18 01:32:36 +08:00
|
|
|
* Author(s): Stephen Smalley, <sds@tycho.nsa.gov>
|
2008-04-23 05:46:10 +08:00
|
|
|
* Chris Vance, <cvance@nai.com>
|
|
|
|
* Wayne Salamon, <wsalamon@nai.com>
|
|
|
|
* James Morris <jmorris@redhat.com>
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Copyright (C) 2001,2002 Networks Associates Technology, Inc.
|
|
|
|
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
2017-05-19 20:48:56 +08:00
|
|
|
* Copyright (C) 2016 Mellanox Technologies
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2,
|
2008-04-23 05:46:10 +08:00
|
|
|
* as published by the Free Software Foundation.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
#ifndef _SELINUX_OBJSEC_H_
|
|
|
|
#define _SELINUX_OBJSEC_H_
|
|
|
|
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/binfmts.h>
|
|
|
|
#include <linux/in.h>
|
2006-11-18 06:38:53 +08:00
|
|
|
#include <linux/spinlock.h>
|
2014-09-11 05:09:57 +08:00
|
|
|
#include <net/net_namespace.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include "flask.h"
|
|
|
|
#include "avc.h"
|
|
|
|
|
|
|
|
struct task_security_struct {
|
2008-04-23 05:46:10 +08:00
|
|
|
u32 osid; /* SID prior to last execve */
|
|
|
|
u32 sid; /* current SID */
|
|
|
|
u32 exec_sid; /* exec SID */
|
|
|
|
u32 create_sid; /* fscreate SID */
|
|
|
|
u32 keycreate_sid; /* keycreate SID */
|
|
|
|
u32 sockcreate_sid; /* fscreate SID */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2017-01-09 23:07:31 +08:00
|
|
|
/*
|
|
|
|
* get the subjective security ID of the current task
|
|
|
|
*/
|
|
|
|
static inline u32 current_sid(void)
|
|
|
|
{
|
|
|
|
const struct task_security_struct *tsec = current_security();
|
|
|
|
|
|
|
|
return tsec->sid;
|
|
|
|
}
|
|
|
|
|
2015-12-25 00:09:40 +08:00
|
|
|
enum label_initialized {
|
2016-03-29 03:16:53 +08:00
|
|
|
LABEL_INVALID, /* invalid or not initialized */
|
selinux: Convert isec->lock into a spinlock
Convert isec->lock from a mutex into a spinlock. Instead of holding
the lock while sleeping in inode_doinit_with_dentry, set
isec->initialized to LABEL_PENDING and release the lock. Then, when
the sid has been determined, re-acquire the lock. If isec->initialized
is still set to LABEL_PENDING, set isec->sid; otherwise, the sid has
been set by another task (LABEL_INITIALIZED) or invalidated
(LABEL_INVALID) in the meantime.
This fixes a deadlock on gfs2 where
* one task is in inode_doinit_with_dentry -> gfs2_getxattr, holds
isec->lock, and tries to acquire the inode's glock, and
* another task is in do_xmote -> inode_go_inval ->
selinux_inode_invalidate_secctx, holds the inode's glock, and
tries to acquire isec->lock.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
[PM: minor tweaks to keep checkpatch.pl happy]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-11-15 18:06:40 +08:00
|
|
|
LABEL_INITIALIZED, /* initialized */
|
|
|
|
LABEL_PENDING
|
2015-12-25 00:09:40 +08:00
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
struct inode_security_struct {
|
2008-04-23 05:46:10 +08:00
|
|
|
struct inode *inode; /* back pointer to inode object */
|
SELinux: Fix possible NULL pointer dereference in selinux_inode_permission()
While running stress tests on adding and deleting ftrace instances I hit
this bug:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
IP: selinux_inode_permission+0x85/0x160
PGD 63681067 PUD 7ddbe067 PMD 0
Oops: 0000 [#1] PREEMPT
CPU: 0 PID: 5634 Comm: ftrace-test-mki Not tainted 3.13.0-rc4-test-00033-gd2a6dde-dirty #20
Hardware name: /DG965MQ, BIOS MQ96510J.86A.0372.2006.0605.1717 06/05/2006
task: ffff880078375800 ti: ffff88007ddb0000 task.ti: ffff88007ddb0000
RIP: 0010:[<ffffffff812d8bc5>] [<ffffffff812d8bc5>] selinux_inode_permission+0x85/0x160
RSP: 0018:ffff88007ddb1c48 EFLAGS: 00010246
RAX: 0000000000000000 RBX: 0000000000800000 RCX: ffff88006dd43840
RDX: 0000000000000001 RSI: 0000000000000081 RDI: ffff88006ee46000
RBP: ffff88007ddb1c88 R08: 0000000000000000 R09: ffff88007ddb1c54
R10: 6e6576652f6f6f66 R11: 0000000000000003 R12: 0000000000000000
R13: 0000000000000081 R14: ffff88006ee46000 R15: 0000000000000000
FS: 00007f217b5b6700(0000) GS:ffffffff81e21000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033^M
CR2: 0000000000000020 CR3: 000000006a0fe000 CR4: 00000000000007f0
Call Trace:
security_inode_permission+0x1c/0x30
__inode_permission+0x41/0xa0
inode_permission+0x18/0x50
link_path_walk+0x66/0x920
path_openat+0xa6/0x6c0
do_filp_open+0x43/0xa0
do_sys_open+0x146/0x240
SyS_open+0x1e/0x20
system_call_fastpath+0x16/0x1b
Code: 84 a1 00 00 00 81 e3 00 20 00 00 89 d8 83 c8 02 40 f6 c6 04 0f 45 d8 40 f6 c6 08 74 71 80 cf 02 49 8b 46 38 4c 8d 4d cc 45 31 c0 <0f> b7 50 20 8b 70 1c 48 8b 41 70 89 d9 8b 78 04 e8 36 cf ff ff
RIP selinux_inode_permission+0x85/0x160
CR2: 0000000000000020
Investigating, I found that the inode->i_security was NULL, and the
dereference of it caused the oops.
in selinux_inode_permission():
isec = inode->i_security;
rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
Note, the crash came from stressing the deletion and reading of debugfs
files. I was not able to recreate this via normal files. But I'm not
sure they are safe. It may just be that the race window is much harder
to hit.
What seems to have happened (and what I have traced), is the file is
being opened at the same time the file or directory is being deleted.
As the dentry and inode locks are not held during the path walk, nor is
the inodes ref counts being incremented, there is nothing saving these
structures from being discarded except for an rcu_read_lock().
The rcu_read_lock() protects against freeing of the inode, but it does
not protect freeing of the inode_security_struct. Now if the freeing of
the i_security happens with a call_rcu(), and the i_security field of
the inode is not changed (it gets freed as the inode gets freed) then
there will be no issue here. (Linus Torvalds suggested not setting the
field to NULL such that we do not need to check if it is NULL in the
permission check).
Note, this is a hack, but it fixes the problem at hand. A real fix is
to restructure the destroy_inode() to call all the destructor handlers
from the RCU callback. But that is a major job to do, and requires a
lot of work. For now, we just band-aid this bug with this fix (it
works), and work on a more maintainable solution in the future.
Link: http://lkml.kernel.org/r/20140109101932.0508dec7@gandalf.local.home
Link: http://lkml.kernel.org/r/20140109182756.17abaaa8@gandalf.local.home
Cc: stable@vger.kernel.org
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-01-10 10:46:34 +08:00
|
|
|
union {
|
|
|
|
struct list_head list; /* list of inode_security_struct */
|
|
|
|
struct rcu_head rcu; /* for freeing the inode_security_struct */
|
|
|
|
};
|
2008-04-23 05:46:10 +08:00
|
|
|
u32 task_sid; /* SID of creating task */
|
|
|
|
u32 sid; /* SID of this object */
|
|
|
|
u16 sclass; /* security class of this object */
|
|
|
|
unsigned char initialized; /* initialization flag */
|
selinux: Convert isec->lock into a spinlock
Convert isec->lock from a mutex into a spinlock. Instead of holding
the lock while sleeping in inode_doinit_with_dentry, set
isec->initialized to LABEL_PENDING and release the lock. Then, when
the sid has been determined, re-acquire the lock. If isec->initialized
is still set to LABEL_PENDING, set isec->sid; otherwise, the sid has
been set by another task (LABEL_INITIALIZED) or invalidated
(LABEL_INVALID) in the meantime.
This fixes a deadlock on gfs2 where
* one task is in inode_doinit_with_dentry -> gfs2_getxattr, holds
isec->lock, and tries to acquire the inode's glock, and
* another task is in do_xmote -> inode_go_inval ->
selinux_inode_invalidate_secctx, holds the inode's glock, and
tries to acquire isec->lock.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
[PM: minor tweaks to keep checkpatch.pl happy]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-11-15 18:06:40 +08:00
|
|
|
spinlock_t lock;
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct file_security_struct {
|
2008-04-23 05:46:10 +08:00
|
|
|
u32 sid; /* SID of open file description */
|
|
|
|
u32 fown_sid; /* SID of file owner (for SIGIO) */
|
|
|
|
u32 isid; /* SID of inode at the time of file open */
|
|
|
|
u32 pseqno; /* Policy seqno at the time of file open */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct superblock_security_struct {
|
2008-04-23 05:46:10 +08:00
|
|
|
struct super_block *sb; /* back pointer to sb object */
|
2006-07-10 19:43:53 +08:00
|
|
|
u32 sid; /* SID of file system superblock */
|
2005-04-17 06:20:36 +08:00
|
|
|
u32 def_sid; /* default SID for labeling */
|
2006-07-10 19:43:53 +08:00
|
|
|
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
|
2012-10-10 22:38:47 +08:00
|
|
|
unsigned short behavior; /* labeling behavior */
|
2012-10-10 04:20:08 +08:00
|
|
|
unsigned short flags; /* which mount options were specified */
|
2006-09-26 14:32:02 +08:00
|
|
|
struct mutex lock;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct list_head isec_head;
|
|
|
|
spinlock_t isec_lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct msg_security_struct {
|
2008-04-23 05:46:10 +08:00
|
|
|
u32 sid; /* SID of message */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ipc_security_struct {
|
|
|
|
u16 sclass; /* security class of this object */
|
2008-04-23 05:46:10 +08:00
|
|
|
u32 sid; /* SID of IPC resource */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct netif_security_struct {
|
2014-09-11 05:09:57 +08:00
|
|
|
struct net *ns; /* network namespace */
|
2008-01-29 21:38:08 +08:00
|
|
|
int ifindex; /* device index */
|
|
|
|
u32 sid; /* SID for this interface */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2008-01-29 21:38:13 +08:00
|
|
|
struct netnode_security_struct {
|
|
|
|
union {
|
|
|
|
__be32 ipv4; /* IPv4 node address */
|
|
|
|
struct in6_addr ipv6; /* IPv6 node address */
|
|
|
|
} addr;
|
|
|
|
u32 sid; /* SID for this node */
|
|
|
|
u16 family; /* address family */
|
|
|
|
};
|
|
|
|
|
2008-04-10 22:48:14 +08:00
|
|
|
struct netport_security_struct {
|
|
|
|
u32 sid; /* SID for this node */
|
|
|
|
u16 port; /* port number */
|
|
|
|
u8 protocol; /* transport protocol */
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
struct sk_security_struct {
|
2008-01-29 21:38:23 +08:00
|
|
|
#ifdef CONFIG_NETLABEL
|
2006-08-05 14:17:57 +08:00
|
|
|
enum { /* NetLabel state */
|
|
|
|
NLBL_UNSET = 0,
|
|
|
|
NLBL_REQUIRE,
|
|
|
|
NLBL_LABELED,
|
2008-10-10 22:16:32 +08:00
|
|
|
NLBL_REQSKB,
|
2008-10-10 22:16:33 +08:00
|
|
|
NLBL_CONNLABELED,
|
2006-08-05 14:17:57 +08:00
|
|
|
} nlbl_state;
|
2008-10-10 22:16:33 +08:00
|
|
|
struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */
|
2006-08-05 14:17:57 +08:00
|
|
|
#endif
|
2008-10-10 22:16:33 +08:00
|
|
|
u32 sid; /* SID of this object */
|
|
|
|
u32 peer_sid; /* SID of peer */
|
|
|
|
u16 sclass; /* sock security class */
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2013-01-14 15:12:19 +08:00
|
|
|
struct tun_security_struct {
|
|
|
|
u32 sid; /* SID for the tun device sockets */
|
|
|
|
};
|
|
|
|
|
2006-06-23 05:47:17 +08:00
|
|
|
struct key_security_struct {
|
2008-04-23 05:46:10 +08:00
|
|
|
u32 sid; /* SID of key */
|
2006-06-23 05:47:17 +08:00
|
|
|
};
|
|
|
|
|
2017-05-19 20:48:56 +08:00
|
|
|
struct ib_security_struct {
|
|
|
|
u32 sid; /* SID of the queue pair or MAD agent */
|
|
|
|
};
|
|
|
|
|
2017-05-19 20:48:59 +08:00
|
|
|
struct pkey_security_struct {
|
|
|
|
u64 subnet_prefix; /* Port subnet prefix */
|
|
|
|
u16 pkey; /* PKey number */
|
|
|
|
u32 sid; /* SID of pkey */
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
extern unsigned int selinux_checkreqprot;
|
|
|
|
|
|
|
|
#endif /* _SELINUX_OBJSEC_H_ */
|