Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
3e5f206c
Commit
3e5f206c
authored
Aug 15, 2015
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'next' of
git://git.infradead.org/users/pcmoore/selinux
into next
parents
0e38c358
fda4d578
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
915 additions
and
110 deletions
+915
-110
include/linux/lsm_audit.h
include/linux/lsm_audit.h
+7
-0
scripts/selinux/mdp/mdp.c
scripts/selinux/mdp/mdp.c
+1
-0
security/lsm_audit.c
security/lsm_audit.c
+15
-0
security/selinux/avc.c
security/selinux/avc.c
+402
-16
security/selinux/hooks.c
security/selinux/hooks.c
+97
-50
security/selinux/include/avc.h
security/selinux/include/avc.h
+6
-0
security/selinux/include/security.h
security/selinux/include/security.h
+30
-2
security/selinux/ss/avtab.c
security/selinux/ss/avtab.c
+90
-14
security/selinux/ss/avtab.h
security/selinux/ss/avtab.h
+32
-1
security/selinux/ss/conditional.c
security/selinux/ss/conditional.c
+27
-5
security/selinux/ss/conditional.h
security/selinux/ss/conditional.h
+4
-2
security/selinux/ss/policydb.c
security/selinux/ss/policydb.c
+5
-0
security/selinux/ss/services.c
security/selinux/ss/services.c
+193
-20
security/selinux/ss/services.h
security/selinux/ss/services.h
+6
-0
No files found.
include/linux/lsm_audit.h
View file @
3e5f206c
...
...
@@ -40,6 +40,11 @@ struct lsm_network_audit {
}
fam
;
};
struct
lsm_ioctlop_audit
{
struct
path
path
;
u16
cmd
;
};
/* Auxiliary data to use in generating the audit record. */
struct
common_audit_data
{
char
type
;
...
...
@@ -53,6 +58,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_KMOD 8
#define LSM_AUDIT_DATA_INODE 9
#define LSM_AUDIT_DATA_DENTRY 10
#define LSM_AUDIT_DATA_IOCTL_OP 11
union
{
struct
path
path
;
struct
dentry
*
dentry
;
...
...
@@ -68,6 +74,7 @@ struct common_audit_data {
}
key_struct
;
#endif
char
*
kmod_name
;
struct
lsm_ioctlop_audit
*
op
;
}
u
;
/* this union contains LSM specific data */
union
{
...
...
scripts/selinux/mdp/mdp.c
View file @
3e5f206c
...
...
@@ -98,6 +98,7 @@ int main(int argc, char *argv[])
/* types, roles, and allows */
fprintf
(
fout
,
"type base_t;
\n
"
);
fprintf
(
fout
,
"role base_r;
\n
"
);
fprintf
(
fout
,
"role base_r types { base_t };
\n
"
);
for
(
i
=
0
;
secclass_map
[
i
].
name
;
i
++
)
fprintf
(
fout
,
"allow base_t base_t:%s *;
\n
"
,
...
...
security/lsm_audit.c
View file @
3e5f206c
...
...
@@ -245,6 +245,21 @@ static void dump_common_audit_data(struct audit_buffer *ab,
}
break
;
}
case
LSM_AUDIT_DATA_IOCTL_OP
:
{
struct
inode
*
inode
;
audit_log_d_path
(
ab
,
" path="
,
&
a
->
u
.
op
->
path
);
inode
=
a
->
u
.
op
->
path
.
dentry
->
d_inode
;
if
(
inode
)
{
audit_log_format
(
ab
,
" dev="
);
audit_log_untrustedstring
(
ab
,
inode
->
i_sb
->
s_id
);
audit_log_format
(
ab
,
" ino=%lu"
,
inode
->
i_ino
);
}
audit_log_format
(
ab
,
" ioctlcmd=%hx"
,
a
->
u
.
op
->
cmd
);
break
;
}
case
LSM_AUDIT_DATA_DENTRY
:
{
struct
inode
*
inode
;
...
...
security/selinux/avc.c
View file @
3e5f206c
...
...
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/percpu.h>
#include <linux/list.h>
#include <net/sock.h>
#include <linux/un.h>
#include <net/af_unix.h>
...
...
@@ -48,6 +49,7 @@ struct avc_entry {
u32
tsid
;
u16
tclass
;
struct
av_decision
avd
;
struct
avc_xperms_node
*
xp_node
;
};
struct
avc_node
{
...
...
@@ -56,6 +58,16 @@ struct avc_node {
struct
rcu_head
rhead
;
};
struct
avc_xperms_decision_node
{
struct
extended_perms_decision
xpd
;
struct
list_head
xpd_list
;
/* list of extended_perms_decision */
};
struct
avc_xperms_node
{
struct
extended_perms
xp
;
struct
list_head
xpd_head
;
/* list head of extended_perms_decision */
};
struct
avc_cache
{
struct
hlist_head
slots
[
AVC_CACHE_SLOTS
];
/* head for avc_node->list */
spinlock_t
slots_lock
[
AVC_CACHE_SLOTS
];
/* lock for writes */
...
...
@@ -80,6 +92,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
static
struct
avc_cache
avc_cache
;
static
struct
avc_callback_node
*
avc_callbacks
;
static
struct
kmem_cache
*
avc_node_cachep
;
static
struct
kmem_cache
*
avc_xperms_data_cachep
;
static
struct
kmem_cache
*
avc_xperms_decision_cachep
;
static
struct
kmem_cache
*
avc_xperms_cachep
;
static
inline
int
avc_hash
(
u32
ssid
,
u32
tsid
,
u16
tclass
)
{
...
...
@@ -101,6 +116,7 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
return
;
}
BUG_ON
(
!
tclass
||
tclass
>=
ARRAY_SIZE
(
secclass_map
));
perms
=
secclass_map
[
tclass
-
1
].
perms
;
audit_log_format
(
ab
,
" {"
);
...
...
@@ -149,7 +165,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla
kfree
(
scontext
);
}
BUG_ON
(
tclass
>=
ARRAY_SIZE
(
secclass_map
));
BUG_ON
(
!
tclass
||
tclass
>=
ARRAY_SIZE
(
secclass_map
));
audit_log_format
(
ab
,
" tclass=%s"
,
secclass_map
[
tclass
-
1
].
name
);
}
...
...
@@ -171,6 +187,16 @@ void __init avc_init(void)
avc_node_cachep
=
kmem_cache_create
(
"avc_node"
,
sizeof
(
struct
avc_node
),
0
,
SLAB_PANIC
,
NULL
);
avc_xperms_cachep
=
kmem_cache_create
(
"avc_xperms_node"
,
sizeof
(
struct
avc_xperms_node
),
0
,
SLAB_PANIC
,
NULL
);
avc_xperms_decision_cachep
=
kmem_cache_create
(
"avc_xperms_decision_node"
,
sizeof
(
struct
avc_xperms_decision_node
),
0
,
SLAB_PANIC
,
NULL
);
avc_xperms_data_cachep
=
kmem_cache_create
(
"avc_xperms_data"
,
sizeof
(
struct
extended_perms_data
),
0
,
SLAB_PANIC
,
NULL
);
audit_log
(
current
->
audit_context
,
GFP_KERNEL
,
AUDIT_KERNEL
,
"AVC INITIALIZED
\n
"
);
}
...
...
@@ -205,9 +231,261 @@ int avc_get_hash_stats(char *page)
slots_used
,
AVC_CACHE_SLOTS
,
max_chain_len
);
}
/*
* using a linked list for extended_perms_decision lookup because the list is
* always small. i.e. less than 5, typically 1
*/
static
struct
extended_perms_decision
*
avc_xperms_decision_lookup
(
u8
driver
,
struct
avc_xperms_node
*
xp_node
)
{
struct
avc_xperms_decision_node
*
xpd_node
;
list_for_each_entry
(
xpd_node
,
&
xp_node
->
xpd_head
,
xpd_list
)
{
if
(
xpd_node
->
xpd
.
driver
==
driver
)
return
&
xpd_node
->
xpd
;
}
return
NULL
;
}
static
inline
unsigned
int
avc_xperms_has_perm
(
struct
extended_perms_decision
*
xpd
,
u8
perm
,
u8
which
)
{
unsigned
int
rc
=
0
;
if
((
which
==
XPERMS_ALLOWED
)
&&
(
xpd
->
used
&
XPERMS_ALLOWED
))
rc
=
security_xperm_test
(
xpd
->
allowed
->
p
,
perm
);
else
if
((
which
==
XPERMS_AUDITALLOW
)
&&
(
xpd
->
used
&
XPERMS_AUDITALLOW
))
rc
=
security_xperm_test
(
xpd
->
auditallow
->
p
,
perm
);
else
if
((
which
==
XPERMS_DONTAUDIT
)
&&
(
xpd
->
used
&
XPERMS_DONTAUDIT
))
rc
=
security_xperm_test
(
xpd
->
dontaudit
->
p
,
perm
);
return
rc
;
}
static
void
avc_xperms_allow_perm
(
struct
avc_xperms_node
*
xp_node
,
u8
driver
,
u8
perm
)
{
struct
extended_perms_decision
*
xpd
;
security_xperm_set
(
xp_node
->
xp
.
drivers
.
p
,
driver
);
xpd
=
avc_xperms_decision_lookup
(
driver
,
xp_node
);
if
(
xpd
&&
xpd
->
allowed
)
security_xperm_set
(
xpd
->
allowed
->
p
,
perm
);
}
static
void
avc_xperms_decision_free
(
struct
avc_xperms_decision_node
*
xpd_node
)
{
struct
extended_perms_decision
*
xpd
;
xpd
=
&
xpd_node
->
xpd
;
if
(
xpd
->
allowed
)
kmem_cache_free
(
avc_xperms_data_cachep
,
xpd
->
allowed
);
if
(
xpd
->
auditallow
)
kmem_cache_free
(
avc_xperms_data_cachep
,
xpd
->
auditallow
);
if
(
xpd
->
dontaudit
)
kmem_cache_free
(
avc_xperms_data_cachep
,
xpd
->
dontaudit
);
kmem_cache_free
(
avc_xperms_decision_cachep
,
xpd_node
);
}
static
void
avc_xperms_free
(
struct
avc_xperms_node
*
xp_node
)
{
struct
avc_xperms_decision_node
*
xpd_node
,
*
tmp
;
if
(
!
xp_node
)
return
;
list_for_each_entry_safe
(
xpd_node
,
tmp
,
&
xp_node
->
xpd_head
,
xpd_list
)
{
list_del
(
&
xpd_node
->
xpd_list
);
avc_xperms_decision_free
(
xpd_node
);
}
kmem_cache_free
(
avc_xperms_cachep
,
xp_node
);
}
static
void
avc_copy_xperms_decision
(
struct
extended_perms_decision
*
dest
,
struct
extended_perms_decision
*
src
)
{
dest
->
driver
=
src
->
driver
;
dest
->
used
=
src
->
used
;
if
(
dest
->
used
&
XPERMS_ALLOWED
)
memcpy
(
dest
->
allowed
->
p
,
src
->
allowed
->
p
,
sizeof
(
src
->
allowed
->
p
));
if
(
dest
->
used
&
XPERMS_AUDITALLOW
)
memcpy
(
dest
->
auditallow
->
p
,
src
->
auditallow
->
p
,
sizeof
(
src
->
auditallow
->
p
));
if
(
dest
->
used
&
XPERMS_DONTAUDIT
)
memcpy
(
dest
->
dontaudit
->
p
,
src
->
dontaudit
->
p
,
sizeof
(
src
->
dontaudit
->
p
));
}
/*
* similar to avc_copy_xperms_decision, but only copy decision
* information relevant to this perm
*/
static
inline
void
avc_quick_copy_xperms_decision
(
u8
perm
,
struct
extended_perms_decision
*
dest
,
struct
extended_perms_decision
*
src
)
{
/*
* compute index of the u32 of the 256 bits (8 u32s) that contain this
* command permission
*/
u8
i
=
perm
>>
5
;
dest
->
used
=
src
->
used
;
if
(
dest
->
used
&
XPERMS_ALLOWED
)
dest
->
allowed
->
p
[
i
]
=
src
->
allowed
->
p
[
i
];
if
(
dest
->
used
&
XPERMS_AUDITALLOW
)
dest
->
auditallow
->
p
[
i
]
=
src
->
auditallow
->
p
[
i
];
if
(
dest
->
used
&
XPERMS_DONTAUDIT
)
dest
->
dontaudit
->
p
[
i
]
=
src
->
dontaudit
->
p
[
i
];
}
static
struct
avc_xperms_decision_node
*
avc_xperms_decision_alloc
(
u8
which
)
{
struct
avc_xperms_decision_node
*
xpd_node
;
struct
extended_perms_decision
*
xpd
;
xpd_node
=
kmem_cache_zalloc
(
avc_xperms_decision_cachep
,
GFP_ATOMIC
|
__GFP_NOMEMALLOC
);
if
(
!
xpd_node
)
return
NULL
;
xpd
=
&
xpd_node
->
xpd
;
if
(
which
&
XPERMS_ALLOWED
)
{
xpd
->
allowed
=
kmem_cache_zalloc
(
avc_xperms_data_cachep
,
GFP_ATOMIC
|
__GFP_NOMEMALLOC
);
if
(
!
xpd
->
allowed
)
goto
error
;
}
if
(
which
&
XPERMS_AUDITALLOW
)
{
xpd
->
auditallow
=
kmem_cache_zalloc
(
avc_xperms_data_cachep
,
GFP_ATOMIC
|
__GFP_NOMEMALLOC
);
if
(
!
xpd
->
auditallow
)
goto
error
;
}
if
(
which
&
XPERMS_DONTAUDIT
)
{
xpd
->
dontaudit
=
kmem_cache_zalloc
(
avc_xperms_data_cachep
,
GFP_ATOMIC
|
__GFP_NOMEMALLOC
);
if
(
!
xpd
->
dontaudit
)
goto
error
;
}
return
xpd_node
;
error:
avc_xperms_decision_free
(
xpd_node
);
return
NULL
;
}
static
int
avc_add_xperms_decision
(
struct
avc_node
*
node
,
struct
extended_perms_decision
*
src
)
{
struct
avc_xperms_decision_node
*
dest_xpd
;
node
->
ae
.
xp_node
->
xp
.
len
++
;
dest_xpd
=
avc_xperms_decision_alloc
(
src
->
used
);
if
(
!
dest_xpd
)
return
-
ENOMEM
;
avc_copy_xperms_decision
(
&
dest_xpd
->
xpd
,
src
);
list_add
(
&
dest_xpd
->
xpd_list
,
&
node
->
ae
.
xp_node
->
xpd_head
);
return
0
;
}
static
struct
avc_xperms_node
*
avc_xperms_alloc
(
void
)
{
struct
avc_xperms_node
*
xp_node
;
xp_node
=
kmem_cache_zalloc
(
avc_xperms_cachep
,
GFP_ATOMIC
|
__GFP_NOMEMALLOC
);
if
(
!
xp_node
)
return
xp_node
;
INIT_LIST_HEAD
(
&
xp_node
->
xpd_head
);
return
xp_node
;
}
static
int
avc_xperms_populate
(
struct
avc_node
*
node
,
struct
avc_xperms_node
*
src
)
{
struct
avc_xperms_node
*
dest
;
struct
avc_xperms_decision_node
*
dest_xpd
;
struct
avc_xperms_decision_node
*
src_xpd
;
if
(
src
->
xp
.
len
==
0
)
return
0
;
dest
=
avc_xperms_alloc
();
if
(
!
dest
)
return
-
ENOMEM
;
memcpy
(
dest
->
xp
.
drivers
.
p
,
src
->
xp
.
drivers
.
p
,
sizeof
(
dest
->
xp
.
drivers
.
p
));
dest
->
xp
.
len
=
src
->
xp
.
len
;
/* for each source xpd allocate a destination xpd and copy */
list_for_each_entry
(
src_xpd
,
&
src
->
xpd_head
,
xpd_list
)
{
dest_xpd
=
avc_xperms_decision_alloc
(
src_xpd
->
xpd
.
used
);
if
(
!
dest_xpd
)
goto
error
;
avc_copy_xperms_decision
(
&
dest_xpd
->
xpd
,
&
src_xpd
->
xpd
);
list_add
(
&
dest_xpd
->
xpd_list
,
&
dest
->
xpd_head
);
}
node
->
ae
.
xp_node
=
dest
;
return
0
;
error:
avc_xperms_free
(
dest
);
return
-
ENOMEM
;
}
static
inline
u32
avc_xperms_audit_required
(
u32
requested
,
struct
av_decision
*
avd
,
struct
extended_perms_decision
*
xpd
,
u8
perm
,
int
result
,
u32
*
deniedp
)
{
u32
denied
,
audited
;
denied
=
requested
&
~
avd
->
allowed
;
if
(
unlikely
(
denied
))
{
audited
=
denied
&
avd
->
auditdeny
;
if
(
audited
&&
xpd
)
{
if
(
avc_xperms_has_perm
(
xpd
,
perm
,
XPERMS_DONTAUDIT
))
audited
&=
~
requested
;
}
}
else
if
(
result
)
{
audited
=
denied
=
requested
;
}
else
{
audited
=
requested
&
avd
->
auditallow
;
if
(
audited
&&
xpd
)
{
if
(
!
avc_xperms_has_perm
(
xpd
,
perm
,
XPERMS_AUDITALLOW
))
audited
&=
~
requested
;
}
}
*
deniedp
=
denied
;
return
audited
;
}
static
inline
int
avc_xperms_audit
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
requested
,
struct
av_decision
*
avd
,
struct
extended_perms_decision
*
xpd
,
u8
perm
,
int
result
,
struct
common_audit_data
*
ad
)
{
u32
audited
,
denied
;
audited
=
avc_xperms_audit_required
(
requested
,
avd
,
xpd
,
perm
,
result
,
&
denied
);
if
(
likely
(
!
audited
))
return
0
;
return
slow_avc_audit
(
ssid
,
tsid
,
tclass
,
requested
,
audited
,
denied
,
result
,
ad
,
0
);
}
static
void
avc_node_free
(
struct
rcu_head
*
rhead
)
{
struct
avc_node
*
node
=
container_of
(
rhead
,
struct
avc_node
,
rhead
);
avc_xperms_free
(
node
->
ae
.
xp_node
);
kmem_cache_free
(
avc_node_cachep
,
node
);
avc_cache_stats_incr
(
frees
);
}
...
...
@@ -221,6 +499,7 @@ static void avc_node_delete(struct avc_node *node)
static
void
avc_node_kill
(
struct
avc_node
*
node
)
{
avc_xperms_free
(
node
->
ae
.
xp_node
);
kmem_cache_free
(
avc_node_cachep
,
node
);
avc_cache_stats_incr
(
frees
);
atomic_dec
(
&
avc_cache
.
active_nodes
);
...
...
@@ -367,6 +646,7 @@ static int avc_latest_notif_update(int seqno, int is_insert)
* @tsid: target security identifier
* @tclass: target security class
* @avd: resulting av decision
* @xp_node: resulting extended permissions
*
* Insert an AVC entry for the SID pair
* (@ssid, @tsid) and class @tclass.
...
...
@@ -378,7 +658,9 @@ static int avc_latest_notif_update(int seqno, int is_insert)
* the access vectors into a cache entry, returns
* avc_node inserted. Otherwise, this function returns NULL.
*/
static
struct
avc_node
*
avc_insert
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
struct
av_decision
*
avd
)
static
struct
avc_node
*
avc_insert
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
struct
av_decision
*
avd
,
struct
avc_xperms_node
*
xp_node
)
{
struct
avc_node
*
pos
,
*
node
=
NULL
;
int
hvalue
;
...
...
@@ -391,10 +673,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec
if
(
node
)
{
struct
hlist_head
*
head
;
spinlock_t
*
lock
;
int
rc
=
0
;
hvalue
=
avc_hash
(
ssid
,
tsid
,
tclass
);
avc_node_populate
(
node
,
ssid
,
tsid
,
tclass
,
avd
);
rc
=
avc_xperms_populate
(
node
,
xp_node
);
if
(
rc
)
{
kmem_cache_free
(
avc_node_cachep
,
node
);
return
NULL
;
}
head
=
&
avc_cache
.
slots
[
hvalue
];
lock
=
&
avc_cache
.
slots_lock
[
hvalue
];
...
...
@@ -523,14 +810,17 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
* @perms : Permission mask bits
* @ssid,@tsid,@tclass : identifier of an AVC entry
* @seqno : sequence number when decision was made
* @xpd: extended_perms_decision to be added to the node
*
* if a valid AVC entry doesn't exist,this function returns -ENOENT.
* if kmalloc() called internal returns NULL, this function returns -ENOMEM.
* otherwise, this function updates the AVC entry. The original AVC-entry object
* will release later by RCU.
*/
static
int
avc_update_node
(
u32
event
,
u32
perms
,
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
seqno
)
static
int
avc_update_node
(
u32
event
,
u32
perms
,
u8
driver
,
u8
xperm
,
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
seqno
,
struct
extended_perms_decision
*
xpd
,
u32
flags
)
{
int
hvalue
,
rc
=
0
;
unsigned
long
flag
;
...
...
@@ -574,9 +864,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
avc_node_populate
(
node
,
ssid
,
tsid
,
tclass
,
&
orig
->
ae
.
avd
);
if
(
orig
->
ae
.
xp_node
)
{
rc
=
avc_xperms_populate
(
node
,
orig
->
ae
.
xp_node
);
if
(
rc
)
{
kmem_cache_free
(
avc_node_cachep
,
node
);
goto
out_unlock
;
}
}
switch
(
event
)
{
case
AVC_CALLBACK_GRANT
:
node
->
ae
.
avd
.
allowed
|=
perms
;
if
(
node
->
ae
.
xp_node
&&
(
flags
&
AVC_EXTENDED_PERMS
))
avc_xperms_allow_perm
(
node
->
ae
.
xp_node
,
driver
,
xperm
);
break
;
case
AVC_CALLBACK_TRY_REVOKE
:
case
AVC_CALLBACK_REVOKE
:
...
...
@@ -594,6 +894,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
case
AVC_CALLBACK_AUDITDENY_DISABLE
:
node
->
ae
.
avd
.
auditdeny
&=
~
perms
;
break
;
case
AVC_CALLBACK_ADD_XPERMS
:
avc_add_xperms_decision
(
node
,
xpd
);
break
;
}
avc_node_replace
(
node
,
orig
);
out_unlock:
...
...
@@ -665,17 +968,19 @@ int avc_ss_reset(u32 seqno)
* results in a bigger stack frame.
*/
static
noinline
struct
avc_node
*
avc_compute_av
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
struct
av_decision
*
avd
)
u16
tclass
,
struct
av_decision
*
avd
,
struct
avc_xperms_node
*
xp_node
)
{
rcu_read_unlock
();
security_compute_av
(
ssid
,
tsid
,
tclass
,
avd
);
INIT_LIST_HEAD
(
&
xp_node
->
xpd_head
);
security_compute_av
(
ssid
,
tsid
,
tclass
,
avd
,
&
xp_node
->
xp
);
rcu_read_lock
();
return
avc_insert
(
ssid
,
tsid
,
tclass
,
avd
);
return
avc_insert
(
ssid
,
tsid
,
tclass
,
avd
,
xp_node
);
}
static
noinline
int
avc_denied
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
requested
,
unsigned
flags
,
u8
driver
,
u8
xperm
,
unsigned
flags
,
struct
av_decision
*
avd
)
{
if
(
flags
&
AVC_STRICT
)
...
...
@@ -684,11 +989,91 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
if
(
selinux_enforcing
&&
!
(
avd
->
flags
&
AVD_FLAGS_PERMISSIVE
))
return
-
EACCES
;
avc_update_node
(
AVC_CALLBACK_GRANT
,
requested
,
ssid
,
tsid
,
tclass
,
avd
->
seqno
);
avc_update_node
(
AVC_CALLBACK_GRANT
,
requested
,
driver
,
xperm
,
ssid
,
tsid
,
tclass
,
avd
->
seqno
,
NULL
,
flags
);
return
0
;
}
/*
* The avc extended permissions logic adds an additional 256 bits of
* permissions to an avc node when extended permissions for that node are
* specified in the avtab. If the additional 256 permissions is not adequate,
* as-is the case with ioctls, then multiple may be chained together and the
* driver field is used to specify which set contains the permission.
*/
int
avc_has_extended_perms
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
requested
,
u8
driver
,
u8
xperm
,
struct
common_audit_data
*
ad
)
{
struct
avc_node
*
node
;
struct
av_decision
avd
;
u32
denied
;
struct
extended_perms_decision
local_xpd
;
struct
extended_perms_decision
*
xpd
=
NULL
;
struct
extended_perms_data
allowed
;
struct
extended_perms_data
auditallow
;
struct
extended_perms_data
dontaudit
;
struct
avc_xperms_node
local_xp_node
;
struct
avc_xperms_node
*
xp_node
;
int
rc
=
0
,
rc2
;
xp_node
=
&
local_xp_node
;
BUG_ON
(
!
requested
);
rcu_read_lock
();
node
=
avc_lookup
(
ssid
,
tsid
,
tclass
);
if
(
unlikely
(
!
node
))
{
node
=
avc_compute_av
(
ssid
,
tsid
,
tclass
,
&
avd
,
xp_node
);
}
else
{
memcpy
(
&
avd
,
&
node
->
ae
.
avd
,
sizeof
(
avd
));
xp_node
=
node
->
ae
.
xp_node
;
}
/* if extended permissions are not defined, only consider av_decision */
if
(
!
xp_node
||
!
xp_node
->
xp
.
len
)
goto
decision
;
local_xpd
.
allowed
=
&
allowed
;
local_xpd
.
auditallow
=
&
auditallow
;
local_xpd
.
dontaudit
=
&
dontaudit
;
xpd
=
avc_xperms_decision_lookup
(
driver
,
xp_node
);
if
(
unlikely
(
!
xpd
))
{
/*
* Compute the extended_perms_decision only if the driver
* is flagged
*/
if
(
!
security_xperm_test
(
xp_node
->
xp
.
drivers
.
p
,
driver
))
{
avd
.
allowed
&=
~
requested
;
goto
decision
;
}
rcu_read_unlock
();
security_compute_xperms_decision
(
ssid
,
tsid
,
tclass
,
driver
,
&
local_xpd
);
rcu_read_lock
();
avc_update_node
(
AVC_CALLBACK_ADD_XPERMS
,
requested
,
driver
,
xperm
,
ssid
,
tsid
,
tclass
,
avd
.
seqno
,
&
local_xpd
,
0
);
}
else
{
avc_quick_copy_xperms_decision
(
xperm
,
&
local_xpd
,
xpd
);
}
xpd
=
&
local_xpd
;
if
(
!
avc_xperms_has_perm
(
xpd
,
xperm
,
XPERMS_ALLOWED
))
avd
.
allowed
&=
~
requested
;
decision:
denied
=
requested
&
~
(
avd
.
allowed
);
if
(
unlikely
(
denied
))
rc
=
avc_denied
(
ssid
,
tsid
,
tclass
,
requested
,
driver
,
xperm
,
AVC_EXTENDED_PERMS
,
&
avd
);
rcu_read_unlock
();
rc2
=
avc_xperms_audit
(
ssid
,
tsid
,
tclass
,
requested
,
&
avd
,
xpd
,
xperm
,
rc
,
ad
);
if
(
rc2
)
return
rc2
;
return
rc
;
}
/**
* avc_has_perm_noaudit - Check permissions but perform no auditing.
...
...
@@ -716,6 +1101,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
struct
av_decision
*
avd
)
{
struct
avc_node
*
node
;
struct
avc_xperms_node
xp_node
;
int
rc
=
0
;
u32
denied
;
...
...
@@ -725,13 +1111,13 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
node
=
avc_lookup
(
ssid
,
tsid
,
tclass
);
if
(
unlikely
(
!
node
))
node
=
avc_compute_av
(
ssid
,
tsid
,
tclass
,
avd
);
node
=
avc_compute_av
(
ssid
,
tsid
,
tclass
,
avd
,
&
xp_node
);
else
memcpy
(
avd
,
&
node
->
ae
.
avd
,
sizeof
(
*
avd
));
denied
=
requested
&
~
(
avd
->
allowed
);
if
(
unlikely
(
denied
))
rc
=
avc_denied
(
ssid
,
tsid
,
tclass
,
requested
,
flags
,
avd
);
rc
=
avc_denied
(
ssid
,
tsid
,
tclass
,
requested
,
0
,
0
,
flags
,
avd
);
rcu_read_unlock
();
return
rc
;
...
...
security/selinux/hooks.c
View file @
3e5f206c
...
...
@@ -254,10 +254,21 @@ static void inode_free_security(struct inode *inode)
struct
inode_security_struct
*
isec
=
inode
->
i_security
;
struct
superblock_security_struct
*
sbsec
=
inode
->
i_sb
->
s_security
;
/*
* As not all inode security structures are in a list, we check for
* empty list outside of the lock to make sure that we won't waste
* time taking a lock doing nothing.
*
* The list_del_init() function can be safely called more than once.
* It should not be possible for this function to be called with
* concurrent list_add(), but for better safety against future changes
* in the code, we use list_empty_careful() here.
*/
if
(
!
list_empty_careful
(
&
isec
->
list
))
{
spin_lock
(
&
sbsec
->
isec_lock
);
if
(
!
list_empty
(
&
isec
->
list
))
list_del_init
(
&
isec
->
list
);
spin_unlock
(
&
sbsec
->
isec_lock
);
}
/*
* The inode may still be referenced in a path walk and
...
...
@@ -1698,6 +1709,32 @@ static int file_has_perm(const struct cred *cred,
return
rc
;
}
/*
* Determine the label for an inode that might be unioned.
*/
static
int
selinux_determine_inode_label
(
const
struct
inode
*
dir
,
const
struct
qstr
*
name
,
u16
tclass
,
u32
*
_new_isid
)
{
const
struct
superblock_security_struct
*
sbsec
=
dir
->
i_sb
->
s_security
;
const
struct
inode_security_struct
*
dsec
=
dir
->
i_security
;
const
struct
task_security_struct
*
tsec
=
current_security
();
if
((
sbsec
->
flags
&
SE_SBINITIALIZED
)
&&
(
sbsec
->
behavior
==
SECURITY_FS_USE_MNTPOINT
))
{
*
_new_isid
=
sbsec
->
mntpoint_sid
;
}
else
if
((
sbsec
->
flags
&
SBLABEL_MNT
)
&&
tsec
->
create_sid
)
{
*
_new_isid
=
tsec
->
create_sid
;
}
else
{
return
security_transition_sid
(
tsec
->
sid
,
dsec
->
sid
,
tclass
,
name
,
_new_isid
);
}
return
0
;
}
/* Check whether a task can create a file. */
static
int
may_create
(
struct
inode
*
dir
,
struct
dentry
*
dentry
,
...
...
@@ -1714,7 +1751,6 @@ static int may_create(struct inode *dir,
sbsec
=
dir
->
i_sb
->
s_security
;
sid
=
tsec
->
sid
;
newsid
=
tsec
->
create_sid
;
ad
.
type
=
LSM_AUDIT_DATA_DENTRY
;
ad
.
u
.
dentry
=
dentry
;
...
...
@@ -1725,12 +1761,10 @@ static int may_create(struct inode *dir,
if
(
rc
)
return
rc
;
if
(
!
newsid
||
!
(
sbsec
->
flags
&
SBLABEL_MNT
))
{
rc
=
security_transition_sid
(
sid
,
dsec
->
sid
,
tclass
,
&
dentry
->
d_name
,
&
newsid
);
rc
=
selinux_determine_inode_label
(
dir
,
&
dentry
->
d_name
,
tclass
,
&
newsid
);
if
(
rc
)
return
rc
;
}
rc
=
avc_has_perm
(
sid
,
newsid
,
tclass
,
FILE__CREATE
,
&
ad
);
if
(
rc
)
...
...
@@ -2704,32 +2738,14 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
struct
qstr
*
name
,
void
**
ctx
,
u32
*
ctxlen
)
{
const
struct
cred
*
cred
=
current_cred
();
struct
task_security_struct
*
tsec
;
struct
inode_security_struct
*
dsec
;
struct
superblock_security_struct
*
sbsec
;
struct
inode
*
dir
=
d_backing_inode
(
dentry
->
d_parent
);
u32
newsid
;
int
rc
;
tsec
=
cred
->
security
;
dsec
=
dir
->
i_security
;
sbsec
=
dir
->
i_sb
->
s_security
;
if
(
tsec
->
create_sid
&&
sbsec
->
behavior
!=
SECURITY_FS_USE_MNTPOINT
)
{
newsid
=
tsec
->
create_sid
;
}
else
{
rc
=
security_transition_sid
(
tsec
->
sid
,
dsec
->
sid
,
rc
=
selinux_determine_inode_label
(
d_inode
(
dentry
->
d_parent
),
name
,
inode_mode_to_security_class
(
mode
),
name
,
&
newsid
);
if
(
rc
)
{
printk
(
KERN_WARNING
"%s: security_transition_sid failed, rc=%d
\n
"
,
__func__
,
-
rc
);
if
(
rc
)
return
rc
;
}
}
return
security_sid_to_context
(
newsid
,
(
char
**
)
ctx
,
ctxlen
);
}
...
...
@@ -2752,22 +2768,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
sid
=
tsec
->
sid
;
newsid
=
tsec
->
create_sid
;
if
((
sbsec
->
flags
&
SE_SBINITIALIZED
)
&&
(
sbsec
->
behavior
==
SECURITY_FS_USE_MNTPOINT
))
newsid
=
sbsec
->
mntpoint_sid
;
else
if
(
!
newsid
||
!
(
sbsec
->
flags
&
SBLABEL_MNT
))
{
rc
=
security_transition_sid
(
sid
,
dsec
->
sid
,
rc
=
selinux_determine_inode_label
(
dir
,
qstr
,
inode_mode_to_security_class
(
inode
->
i_mode
),
qstr
,
&
newsid
);
if
(
rc
)
{
printk
(
KERN_WARNING
"%s: "
"security_transition_sid failed, rc=%d (dev=%s "
"ino=%ld)
\n
"
,
__func__
,
-
rc
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
);
&
newsid
);
if
(
rc
)
return
rc
;
}
}
/* Possibly defer initialization to selinux_complete_init. */
if
(
sbsec
->
flags
&
SE_SBINITIALIZED
)
{
...
...
@@ -3228,6 +3234,46 @@ static void selinux_file_free_security(struct file *file)
file_free_security
(
file
);
}
/*
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
*/
int
ioctl_has_perm
(
const
struct
cred
*
cred
,
struct
file
*
file
,
u32
requested
,
u16
cmd
)
{
struct
common_audit_data
ad
;
struct
file_security_struct
*
fsec
=
file
->
f_security
;
struct
inode
*
inode
=
file_inode
(
file
);
struct
inode_security_struct
*
isec
=
inode
->
i_security
;
struct
lsm_ioctlop_audit
ioctl
;
u32
ssid
=
cred_sid
(
cred
);
int
rc
;
u8
driver
=
cmd
>>
8
;
u8
xperm
=
cmd
&
0xff
;
ad
.
type
=
LSM_AUDIT_DATA_IOCTL_OP
;
ad
.
u
.
op
=
&
ioctl
;
ad
.
u
.
op
->
cmd
=
cmd
;
ad
.
u
.
op
->
path
=
file
->
f_path
;
if
(
ssid
!=
fsec
->
sid
)
{
rc
=
avc_has_perm
(
ssid
,
fsec
->
sid
,
SECCLASS_FD
,
FD__USE
,
&
ad
);
if
(
rc
)
goto
out
;
}
if
(
unlikely
(
IS_PRIVATE
(
inode
)))
return
0
;
rc
=
avc_has_extended_perms
(
ssid
,
isec
->
sid
,
isec
->
sclass
,
requested
,
driver
,
xperm
,
&
ad
);
out:
return
rc
;
}
static
int
selinux_file_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
...
...
@@ -3270,7 +3316,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
* to the file's ioctl() function.
*/
default:
error
=
file_has_perm
(
cred
,
file
,
FILE__IOCTL
);
error
=
ioctl_has_perm
(
cred
,
file
,
FILE__IOCTL
,
(
u16
)
cmd
);
}
return
error
;
}
...
...
@@ -4520,6 +4566,7 @@ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority
sksec
->
peer_sid
=
SECINITSID_UNLABELED
;
sksec
->
sid
=
SECINITSID_UNLABELED
;
sksec
->
sclass
=
SECCLASS_SOCKET
;
selinux_netlbl_sk_security_reset
(
sksec
);
sk
->
sk_security
=
sksec
;
...
...
security/selinux/include/avc.h
View file @
3e5f206c
...
...
@@ -143,6 +143,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
}
#define AVC_STRICT 1
/* Ignore permissive mode. */
#define AVC_EXTENDED_PERMS 2
/* update extended permissions */
int
avc_has_perm_noaudit
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
requested
,
unsigned
flags
,
...
...
@@ -156,6 +157,10 @@ int avc_has_perm_flags(u32 ssid, u32 tsid,
struct
common_audit_data
*
auditdata
,
int
flags
);
int
avc_has_extended_perms
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
u32
requested
,
u8
driver
,
u8
perm
,
struct
common_audit_data
*
ad
);
u32
avc_policy_seqno
(
void
);
#define AVC_CALLBACK_GRANT 1
...
...
@@ -166,6 +171,7 @@ u32 avc_policy_seqno(void);
#define AVC_CALLBACK_AUDITALLOW_DISABLE 32
#define AVC_CALLBACK_AUDITDENY_ENABLE 64
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
#define AVC_CALLBACK_ADD_XPERMS 256
int
avc_add_callback
(
int
(
*
callback
)(
u32
event
),
u32
events
);
...
...
security/selinux/include/security.h
View file @
3e5f206c
...
...
@@ -35,13 +35,14 @@
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
#define POLICYDB_VERSION_DEFAULT_TYPE 28
#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
#define POLICYDB_VERSION_XPERMS_IOCTL 30
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
#else
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_
CONSTRAINT_NAMES
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_
XPERMS_IOCTL
#endif
/* Mask for just the mount related flags */
...
...
@@ -109,11 +110,38 @@ struct av_decision {
u32
flags
;
};
#define XPERMS_ALLOWED 1
#define XPERMS_AUDITALLOW 2
#define XPERMS_DONTAUDIT 4
#define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f))
#define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f)))
struct
extended_perms_data
{
u32
p
[
8
];
};
struct
extended_perms_decision
{
u8
used
;
u8
driver
;
struct
extended_perms_data
*
allowed
;
struct
extended_perms_data
*
auditallow
;
struct
extended_perms_data
*
dontaudit
;
};
struct
extended_perms
{
u16
len
;
/* length associated decision chain */
struct
extended_perms_data
drivers
;
/* flag drivers that are used */
};
/* definitions of av_decision.flags */
#define AVD_FLAGS_PERMISSIVE 0x0001
void
security_compute_av
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
struct
av_decision
*
avd
);
u16
tclass
,
struct
av_decision
*
avd
,
struct
extended_perms
*
xperms
);
void
security_compute_xperms_decision
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
u8
driver
,
struct
extended_perms_decision
*
xpermd
);
void
security_compute_av_user
(
u32
ssid
,
u32
tsid
,
u16
tclass
,
struct
av_decision
*
avd
);
...
...
security/selinux/ss/avtab.c
View file @
3e5f206c
...
...
@@ -24,6 +24,7 @@
#include "policydb.h"
static
struct
kmem_cache
*
avtab_node_cachep
;
static
struct
kmem_cache
*
avtab_xperms_cachep
;
/* Based on MurmurHash3, written by Austin Appleby and placed in the
* public domain.
...
...
@@ -70,11 +71,24 @@ avtab_insert_node(struct avtab *h, int hvalue,
struct
avtab_key
*
key
,
struct
avtab_datum
*
datum
)
{
struct
avtab_node
*
newnode
;
struct
avtab_extended_perms
*
xperms
;
newnode
=
kmem_cache_zalloc
(
avtab_node_cachep
,
GFP_KERNEL
);
if
(
newnode
==
NULL
)
return
NULL
;
newnode
->
key
=
*
key
;
newnode
->
datum
=
*
datum
;
if
(
key
->
specified
&
AVTAB_XPERMS
)
{
xperms
=
kmem_cache_zalloc
(
avtab_xperms_cachep
,
GFP_KERNEL
);
if
(
xperms
==
NULL
)
{
kmem_cache_free
(
avtab_node_cachep
,
newnode
);
return
NULL
;
}
*
xperms
=
*
(
datum
->
u
.
xperms
);
newnode
->
datum
.
u
.
xperms
=
xperms
;
}
else
{
newnode
->
datum
.
u
.
data
=
datum
->
u
.
data
;
}
if
(
prev
)
{
newnode
->
next
=
prev
->
next
;
prev
->
next
=
newnode
;
...
...
@@ -107,8 +121,12 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
if
(
key
->
source_type
==
cur
->
key
.
source_type
&&
key
->
target_type
==
cur
->
key
.
target_type
&&
key
->
target_class
==
cur
->
key
.
target_class
&&
(
specified
&
cur
->
key
.
specified
))
(
specified
&
cur
->
key
.
specified
))
{
/* extended perms may not be unique */
if
(
specified
&
AVTAB_XPERMS
)
break
;
return
-
EEXIST
;
}
if
(
key
->
source_type
<
cur
->
key
.
source_type
)
break
;
if
(
key
->
source_type
==
cur
->
key
.
source_type
&&
...
...
@@ -271,6 +289,9 @@ void avtab_destroy(struct avtab *h)
while
(
cur
)
{
temp
=
cur
;
cur
=
cur
->
next
;
if
(
temp
->
key
.
specified
&
AVTAB_XPERMS
)
kmem_cache_free
(
avtab_xperms_cachep
,
temp
->
datum
.
u
.
xperms
);
kmem_cache_free
(
avtab_node_cachep
,
temp
);
}
}
...
...
@@ -359,7 +380,10 @@ static uint16_t spec_order[] = {
AVTAB_AUDITALLOW
,
AVTAB_TRANSITION
,
AVTAB_CHANGE
,
AVTAB_MEMBER
AVTAB_MEMBER
,
AVTAB_XPERMS_ALLOWED
,
AVTAB_XPERMS_AUDITALLOW
,
AVTAB_XPERMS_DONTAUDIT
};
int
avtab_read_item
(
struct
avtab
*
a
,
void
*
fp
,
struct
policydb
*
pol
,
...
...
@@ -369,10 +393,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
{
__le16
buf16
[
4
];
u16
enabled
;
__le32
buf32
[
7
];
u32
items
,
items2
,
val
,
vers
=
pol
->
policyvers
;
struct
avtab_key
key
;
struct
avtab_datum
datum
;
struct
avtab_extended_perms
xperms
;
__le32
buf32
[
ARRAY_SIZE
(
xperms
.
perms
.
p
)];
int
i
,
rc
;
unsigned
set
;
...
...
@@ -429,11 +454,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
printk
(
KERN_ERR
"SELinux: avtab: entry has both access vectors and types
\n
"
);
return
-
EINVAL
;
}
if
(
val
&
AVTAB_XPERMS
)
{
printk
(
KERN_ERR
"SELinux: avtab: entry has extended permissions
\n
"
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
spec_order
);
i
++
)
{
if
(
val
&
spec_order
[
i
])
{
key
.
specified
=
spec_order
[
i
]
|
enabled
;
datum
.
data
=
le32_to_cpu
(
buf32
[
items
++
]);
datum
.
u
.
data
=
le32_to_cpu
(
buf32
[
items
++
]);
rc
=
insertf
(
a
,
&
key
,
&
datum
,
p
);
if
(
rc
)
return
rc
;
...
...
@@ -476,14 +505,42 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
return
-
EINVAL
;
}
if
((
vers
<
POLICYDB_VERSION_XPERMS_IOCTL
)
&&
(
key
.
specified
&
AVTAB_XPERMS
))
{
printk
(
KERN_ERR
"SELinux: avtab: policy version %u does not "
"support extended permissions rules and one "
"was specified
\n
"
,
vers
);
return
-
EINVAL
;
}
else
if
(
key
.
specified
&
AVTAB_XPERMS
)
{
memset
(
&
xperms
,
0
,
sizeof
(
struct
avtab_extended_perms
));
rc
=
next_entry
(
&
xperms
.
specified
,
fp
,
sizeof
(
u8
));
if
(
rc
)
{
printk
(
KERN_ERR
"SELinux: avtab: truncated entry
\n
"
);
return
rc
;
}
rc
=
next_entry
(
&
xperms
.
driver
,
fp
,
sizeof
(
u8
));
if
(
rc
)
{
printk
(
KERN_ERR
"SELinux: avtab: truncated entry
\n
"
);
return
rc
;
}
rc
=
next_entry
(
buf32
,
fp
,
sizeof
(
u32
)
*
ARRAY_SIZE
(
xperms
.
perms
.
p
));
if
(
rc
)
{
printk
(
KERN_ERR
"SELinux: avtab: truncated entry
\n
"
);
return
rc
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
xperms
.
perms
.
p
);
i
++
)
xperms
.
perms
.
p
[
i
]
=
le32_to_cpu
(
buf32
[
i
]);
datum
.
u
.
xperms
=
&
xperms
;
}
else
{
rc
=
next_entry
(
buf32
,
fp
,
sizeof
(
u32
));
if
(
rc
)
{
printk
(
KERN_ERR
"SELinux: avtab: truncated entry
\n
"
);
return
rc
;
}
datum
.
data
=
le32_to_cpu
(
*
buf32
);
datum
.
u
.
data
=
le32_to_cpu
(
*
buf32
);
}
if
((
key
.
specified
&
AVTAB_TYPE
)
&&
!
policydb_type_isvalid
(
pol
,
datum
.
data
))
{
!
policydb_type_isvalid
(
pol
,
datum
.
u
.
data
))
{
printk
(
KERN_ERR
"SELinux: avtab: invalid type
\n
"
);
return
-
EINVAL
;
}
...
...
@@ -543,8 +600,9 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
int
avtab_write_item
(
struct
policydb
*
p
,
struct
avtab_node
*
cur
,
void
*
fp
)
{
__le16
buf16
[
4
];
__le32
buf32
[
1
];
__le32
buf32
[
ARRAY_SIZE
(
cur
->
datum
.
u
.
xperms
->
perms
.
p
)
];
int
rc
;
unsigned
int
i
;
buf16
[
0
]
=
cpu_to_le16
(
cur
->
key
.
source_type
);
buf16
[
1
]
=
cpu_to_le16
(
cur
->
key
.
target_type
);
...
...
@@ -553,8 +611,22 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
rc
=
put_entry
(
buf16
,
sizeof
(
u16
),
4
,
fp
);
if
(
rc
)
return
rc
;
buf32
[
0
]
=
cpu_to_le32
(
cur
->
datum
.
data
);
if
(
cur
->
key
.
specified
&
AVTAB_XPERMS
)
{
rc
=
put_entry
(
&
cur
->
datum
.
u
.
xperms
->
specified
,
sizeof
(
u8
),
1
,
fp
);
if
(
rc
)
return
rc
;
rc
=
put_entry
(
&
cur
->
datum
.
u
.
xperms
->
driver
,
sizeof
(
u8
),
1
,
fp
);
if
(
rc
)
return
rc
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
cur
->
datum
.
u
.
xperms
->
perms
.
p
);
i
++
)
buf32
[
i
]
=
cpu_to_le32
(
cur
->
datum
.
u
.
xperms
->
perms
.
p
[
i
]);
rc
=
put_entry
(
buf32
,
sizeof
(
u32
),
ARRAY_SIZE
(
cur
->
datum
.
u
.
xperms
->
perms
.
p
),
fp
);
}
else
{
buf32
[
0
]
=
cpu_to_le32
(
cur
->
datum
.
u
.
data
);
rc
=
put_entry
(
buf32
,
sizeof
(
u32
),
1
,
fp
);
}
if
(
rc
)
return
rc
;
return
0
;
...
...
@@ -588,9 +660,13 @@ void avtab_cache_init(void)
avtab_node_cachep
=
kmem_cache_create
(
"avtab_node"
,
sizeof
(
struct
avtab_node
),
0
,
SLAB_PANIC
,
NULL
);
avtab_xperms_cachep
=
kmem_cache_create
(
"avtab_extended_perms"
,
sizeof
(
struct
avtab_extended_perms
),
0
,
SLAB_PANIC
,
NULL
);
}
void
avtab_cache_destroy
(
void
)
{
kmem_cache_destroy
(
avtab_node_cachep
);
kmem_cache_destroy
(
avtab_xperms_cachep
);
}
security/selinux/ss/avtab.h
View file @
3e5f206c
...
...
@@ -23,6 +23,7 @@
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
#include "security.h"
#include <linux/flex_array.h>
struct
avtab_key
{
...
...
@@ -37,13 +38,43 @@ struct avtab_key {
#define AVTAB_MEMBER 0x0020
#define AVTAB_CHANGE 0x0040
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
/* extended permissions */
#define AVTAB_XPERMS_ALLOWED 0x0100
#define AVTAB_XPERMS_AUDITALLOW 0x0200
#define AVTAB_XPERMS_DONTAUDIT 0x0400
#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \
AVTAB_XPERMS_AUDITALLOW | \
AVTAB_XPERMS_DONTAUDIT)
#define AVTAB_ENABLED_OLD 0x80000000
/* reserved for used in cond_avtab */
#define AVTAB_ENABLED 0x8000
/* reserved for used in cond_avtab */
u16
specified
;
/* what field is specified */
};
/*
* For operations that require more than the 32 permissions provided by the avc
* extended permissions may be used to provide 256 bits of permissions.
*/
struct
avtab_extended_perms
{
/* These are not flags. All 256 values may be used */
#define AVTAB_XPERMS_IOCTLFUNCTION 0x01
#define AVTAB_XPERMS_IOCTLDRIVER 0x02
/* extension of the avtab_key specified */
u8
specified
;
/* ioctl, netfilter, ... */
/*
* if 256 bits is not adequate as is often the case with ioctls, then
* multiple extended perms may be used and the driver field
* specifies which permissions are included.
*/
u8
driver
;
/* 256 bits of permissions */
struct
extended_perms_data
perms
;
};
struct
avtab_datum
{
union
{
u32
data
;
/* access vector or type value */
struct
avtab_extended_perms
*
xperms
;
}
u
;
};
struct
avtab_node
{
...
...
security/selinux/ss/conditional.c
View file @
3e5f206c
...
...
@@ -15,6 +15,7 @@
#include "security.h"
#include "conditional.h"
#include "services.h"
/*
* cond_evaluate_expr evaluates a conditional expr
...
...
@@ -612,21 +613,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
return
0
;
}
void
cond_compute_xperms
(
struct
avtab
*
ctab
,
struct
avtab_key
*
key
,
struct
extended_perms_decision
*
xpermd
)
{
struct
avtab_node
*
node
;
if
(
!
ctab
||
!
key
||
!
xpermd
)
return
;
for
(
node
=
avtab_search_node
(
ctab
,
key
);
node
;
node
=
avtab_search_node_next
(
node
,
key
->
specified
))
{
if
(
node
->
key
.
specified
&
AVTAB_ENABLED
)
services_compute_xperms_decision
(
xpermd
,
node
);
}
return
;
}
/* Determine whether additional permissions are granted by the conditional
* av table, and if so, add them to the result
*/
void
cond_compute_av
(
struct
avtab
*
ctab
,
struct
avtab_key
*
key
,
struct
av_decision
*
avd
)
void
cond_compute_av
(
struct
avtab
*
ctab
,
struct
avtab_key
*
key
,
struct
av_decision
*
avd
,
struct
extended_perms
*
xperms
)
{
struct
avtab_node
*
node
;
if
(
!
ctab
||
!
key
||
!
avd
)
if
(
!
ctab
||
!
key
||
!
avd
||
!
xperms
)
return
;
for
(
node
=
avtab_search_node
(
ctab
,
key
);
node
;
node
=
avtab_search_node_next
(
node
,
key
->
specified
))
{
if
((
u16
)(
AVTAB_ALLOWED
|
AVTAB_ENABLED
)
==
(
node
->
key
.
specified
&
(
AVTAB_ALLOWED
|
AVTAB_ENABLED
)))
avd
->
allowed
|=
node
->
datum
.
data
;
avd
->
allowed
|=
node
->
datum
.
u
.
data
;
if
((
u16
)(
AVTAB_AUDITDENY
|
AVTAB_ENABLED
)
==
(
node
->
key
.
specified
&
(
AVTAB_AUDITDENY
|
AVTAB_ENABLED
)))
/* Since a '0' in an auditdeny mask represents a
...
...
@@ -634,10 +653,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi
* the '&' operand to ensure that all '0's in the mask
* are retained (much unlike the allow and auditallow cases).
*/
avd
->
auditdeny
&=
node
->
datum
.
data
;
avd
->
auditdeny
&=
node
->
datum
.
u
.
data
;
if
((
u16
)(
AVTAB_AUDITALLOW
|
AVTAB_ENABLED
)
==
(
node
->
key
.
specified
&
(
AVTAB_AUDITALLOW
|
AVTAB_ENABLED
)))
avd
->
auditallow
|=
node
->
datum
.
data
;
avd
->
auditallow
|=
node
->
datum
.
u
.
data
;
if
((
node
->
key
.
specified
&
AVTAB_ENABLED
)
&&
(
node
->
key
.
specified
&
AVTAB_XPERMS
))
services_compute_xperms_drivers
(
xperms
,
node
);
}
return
;
}
security/selinux/ss/conditional.h
View file @
3e5f206c
...
...
@@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp);
int
cond_write_bool
(
void
*
key
,
void
*
datum
,
void
*
ptr
);
int
cond_write_list
(
struct
policydb
*
p
,
struct
cond_node
*
list
,
void
*
fp
);
void
cond_compute_av
(
struct
avtab
*
ctab
,
struct
avtab_key
*
key
,
struct
av_decision
*
avd
);
void
cond_compute_av
(
struct
avtab
*
ctab
,
struct
avtab_key
*
key
,
struct
av_decision
*
avd
,
struct
extended_perms
*
xperms
);
void
cond_compute_xperms
(
struct
avtab
*
ctab
,
struct
avtab_key
*
key
,
struct
extended_perms_decision
*
xpermd
);
int
evaluate_cond_node
(
struct
policydb
*
p
,
struct
cond_node
*
node
);
#endif
/* _CONDITIONAL_H_ */
security/selinux/ss/policydb.c
View file @
3e5f206c
...
...
@@ -148,6 +148,11 @@ static struct policydb_compat_info policydb_compat[] = {
.
sym_num
=
SYM_NUM
,
.
ocon_num
=
OCON_NUM
,
},
{
.
version
=
POLICYDB_VERSION_XPERMS_IOCTL
,
.
sym_num
=
SYM_NUM
,
.
ocon_num
=
OCON_NUM
,
},
};
static
struct
policydb_compat_info
*
policydb_lookup_compat
(
int
version
)
...
...
security/selinux/ss/services.c
View file @
3e5f206c
...
...
@@ -95,7 +95,8 @@ static int context_struct_to_string(struct context *context, char **scontext,
static
void
context_struct_compute_av
(
struct
context
*
scontext
,
struct
context
*
tcontext
,
u16
tclass
,
struct
av_decision
*
avd
);
struct
av_decision
*
avd
,
struct
extended_perms
*
xperms
);
struct
selinux_mapping
{
u16
value
;
/* policy value */
...
...
@@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext,
context_struct_compute_av
(
&
lo_scontext
,
tcontext
,
tclass
,
&
lo_avd
);
&
lo_avd
,
NULL
);
if
((
lo_avd
.
allowed
&
avd
->
allowed
)
==
avd
->
allowed
)
return
;
/* no masked permission */
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
...
...
@@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext,
context_struct_compute_av
(
scontext
,
&
lo_tcontext
,
tclass
,
&
lo_avd
);
&
lo_avd
,
NULL
);
if
((
lo_avd
.
allowed
&
avd
->
allowed
)
==
avd
->
allowed
)
return
;
/* no masked permission */
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
...
...
@@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext,
context_struct_compute_av
(
&
lo_scontext
,
&
lo_tcontext
,
tclass
,
&
lo_avd
);
&
lo_avd
,
NULL
);
if
((
lo_avd
.
allowed
&
avd
->
allowed
)
==
avd
->
allowed
)
return
;
/* no masked permission */
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
...
...
@@ -613,13 +617,39 @@ static void type_attribute_bounds_av(struct context *scontext,
}
/*
* Compute access vectors based on a context structure pair for
* the permissions in a particular class.
* flag which drivers have permissions
* only looking for ioctl based extended permssions
*/
void
services_compute_xperms_drivers
(
struct
extended_perms
*
xperms
,
struct
avtab_node
*
node
)
{
unsigned
int
i
;
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLDRIVER
)
{
/* if one or more driver has all permissions allowed */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
xperms
->
drivers
.
p
);
i
++
)
xperms
->
drivers
.
p
[
i
]
|=
node
->
datum
.
u
.
xperms
->
perms
.
p
[
i
];
}
else
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLFUNCTION
)
{
/* if allowing permissions within a driver */
security_xperm_set
(
xperms
->
drivers
.
p
,
node
->
datum
.
u
.
xperms
->
driver
);
}
/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
if
(
node
->
key
.
specified
&
AVTAB_XPERMS_ALLOWED
)
xperms
->
len
=
1
;
}
/*
* Compute access vectors and extended permissions based on a context
* structure pair for the permissions in a particular class.
*/
static
void
context_struct_compute_av
(
struct
context
*
scontext
,
struct
context
*
tcontext
,
u16
tclass
,
struct
av_decision
*
avd
)
struct
av_decision
*
avd
,
struct
extended_perms
*
xperms
)
{
struct
constraint_node
*
constraint
;
struct
role_allow
*
ra
;
...
...
@@ -633,6 +663,10 @@ static void context_struct_compute_av(struct context *scontext,
avd
->
allowed
=
0
;
avd
->
auditallow
=
0
;
avd
->
auditdeny
=
0xffffffff
;
if
(
xperms
)
{
memset
(
&
xperms
->
drivers
,
0
,
sizeof
(
xperms
->
drivers
));
xperms
->
len
=
0
;
}
if
(
unlikely
(
!
tclass
||
tclass
>
policydb
.
p_classes
.
nprim
))
{
if
(
printk_ratelimit
())
...
...
@@ -647,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext,
* this permission check, then use it.
*/
avkey
.
target_class
=
tclass
;
avkey
.
specified
=
AVTAB_AV
;
avkey
.
specified
=
AVTAB_AV
|
AVTAB_XPERMS
;
sattr
=
flex_array_get
(
policydb
.
type_attr_map_array
,
scontext
->
type
-
1
);
BUG_ON
(
!
sattr
);
tattr
=
flex_array_get
(
policydb
.
type_attr_map_array
,
tcontext
->
type
-
1
);
...
...
@@ -660,15 +694,18 @@ static void context_struct_compute_av(struct context *scontext,
node
;
node
=
avtab_search_node_next
(
node
,
avkey
.
specified
))
{
if
(
node
->
key
.
specified
==
AVTAB_ALLOWED
)
avd
->
allowed
|=
node
->
datum
.
data
;
avd
->
allowed
|=
node
->
datum
.
u
.
data
;
else
if
(
node
->
key
.
specified
==
AVTAB_AUDITALLOW
)
avd
->
auditallow
|=
node
->
datum
.
data
;
avd
->
auditallow
|=
node
->
datum
.
u
.
data
;
else
if
(
node
->
key
.
specified
==
AVTAB_AUDITDENY
)
avd
->
auditdeny
&=
node
->
datum
.
data
;
avd
->
auditdeny
&=
node
->
datum
.
u
.
data
;
else
if
(
xperms
&&
(
node
->
key
.
specified
&
AVTAB_XPERMS
))
services_compute_xperms_drivers
(
xperms
,
node
);
}
/* Check conditional av table for additional permissions */
cond_compute_av
(
&
policydb
.
te_cond_avtab
,
&
avkey
,
avd
);
cond_compute_av
(
&
policydb
.
te_cond_avtab
,
&
avkey
,
avd
,
xperms
);
}
}
...
...
@@ -899,6 +936,139 @@ static void avd_init(struct av_decision *avd)
avd
->
flags
=
0
;
}
void
services_compute_xperms_decision
(
struct
extended_perms_decision
*
xpermd
,
struct
avtab_node
*
node
)
{
unsigned
int
i
;
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLFUNCTION
)
{
if
(
xpermd
->
driver
!=
node
->
datum
.
u
.
xperms
->
driver
)
return
;
}
else
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLDRIVER
)
{
if
(
!
security_xperm_test
(
node
->
datum
.
u
.
xperms
->
perms
.
p
,
xpermd
->
driver
))
return
;
}
else
{
BUG
();
}
if
(
node
->
key
.
specified
==
AVTAB_XPERMS_ALLOWED
)
{
xpermd
->
used
|=
XPERMS_ALLOWED
;
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLDRIVER
)
{
memset
(
xpermd
->
allowed
->
p
,
0xff
,
sizeof
(
xpermd
->
allowed
->
p
));
}
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLFUNCTION
)
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
xpermd
->
allowed
->
p
);
i
++
)
xpermd
->
allowed
->
p
[
i
]
|=
node
->
datum
.
u
.
xperms
->
perms
.
p
[
i
];
}
}
else
if
(
node
->
key
.
specified
==
AVTAB_XPERMS_AUDITALLOW
)
{
xpermd
->
used
|=
XPERMS_AUDITALLOW
;
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLDRIVER
)
{
memset
(
xpermd
->
auditallow
->
p
,
0xff
,
sizeof
(
xpermd
->
auditallow
->
p
));
}
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLFUNCTION
)
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
xpermd
->
auditallow
->
p
);
i
++
)
xpermd
->
auditallow
->
p
[
i
]
|=
node
->
datum
.
u
.
xperms
->
perms
.
p
[
i
];
}
}
else
if
(
node
->
key
.
specified
==
AVTAB_XPERMS_DONTAUDIT
)
{
xpermd
->
used
|=
XPERMS_DONTAUDIT
;
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLDRIVER
)
{
memset
(
xpermd
->
dontaudit
->
p
,
0xff
,
sizeof
(
xpermd
->
dontaudit
->
p
));
}
if
(
node
->
datum
.
u
.
xperms
->
specified
==
AVTAB_XPERMS_IOCTLFUNCTION
)
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
xpermd
->
dontaudit
->
p
);
i
++
)
xpermd
->
dontaudit
->
p
[
i
]
|=
node
->
datum
.
u
.
xperms
->
perms
.
p
[
i
];
}
}
else
{
BUG
();
}
}
void
security_compute_xperms_decision
(
u32
ssid
,
u32
tsid
,
u16
orig_tclass
,
u8
driver
,
struct
extended_perms_decision
*
xpermd
)
{
u16
tclass
;
struct
context
*
scontext
,
*
tcontext
;
struct
avtab_key
avkey
;
struct
avtab_node
*
node
;
struct
ebitmap
*
sattr
,
*
tattr
;
struct
ebitmap_node
*
snode
,
*
tnode
;
unsigned
int
i
,
j
;
xpermd
->
driver
=
driver
;
xpermd
->
used
=
0
;
memset
(
xpermd
->
allowed
->
p
,
0
,
sizeof
(
xpermd
->
allowed
->
p
));
memset
(
xpermd
->
auditallow
->
p
,
0
,
sizeof
(
xpermd
->
auditallow
->
p
));
memset
(
xpermd
->
dontaudit
->
p
,
0
,
sizeof
(
xpermd
->
dontaudit
->
p
));
read_lock
(
&
policy_rwlock
);
if
(
!
ss_initialized
)
goto
allow
;
scontext
=
sidtab_search
(
&
sidtab
,
ssid
);
if
(
!
scontext
)
{
printk
(
KERN_ERR
"SELinux: %s: unrecognized SID %d
\n
"
,
__func__
,
ssid
);
goto
out
;
}
tcontext
=
sidtab_search
(
&
sidtab
,
tsid
);
if
(
!
tcontext
)
{
printk
(
KERN_ERR
"SELinux: %s: unrecognized SID %d
\n
"
,
__func__
,
tsid
);
goto
out
;
}
tclass
=
unmap_class
(
orig_tclass
);
if
(
unlikely
(
orig_tclass
&&
!
tclass
))
{
if
(
policydb
.
allow_unknown
)
goto
allow
;
goto
out
;
}
if
(
unlikely
(
!
tclass
||
tclass
>
policydb
.
p_classes
.
nprim
))
{
pr_warn_ratelimited
(
"SELinux: Invalid class %hu
\n
"
,
tclass
);
goto
out
;
}
avkey
.
target_class
=
tclass
;
avkey
.
specified
=
AVTAB_XPERMS
;
sattr
=
flex_array_get
(
policydb
.
type_attr_map_array
,
scontext
->
type
-
1
);
BUG_ON
(
!
sattr
);
tattr
=
flex_array_get
(
policydb
.
type_attr_map_array
,
tcontext
->
type
-
1
);
BUG_ON
(
!
tattr
);
ebitmap_for_each_positive_bit
(
sattr
,
snode
,
i
)
{
ebitmap_for_each_positive_bit
(
tattr
,
tnode
,
j
)
{
avkey
.
source_type
=
i
+
1
;
avkey
.
target_type
=
j
+
1
;
for
(
node
=
avtab_search_node
(
&
policydb
.
te_avtab
,
&
avkey
);
node
;
node
=
avtab_search_node_next
(
node
,
avkey
.
specified
))
services_compute_xperms_decision
(
xpermd
,
node
);
cond_compute_xperms
(
&
policydb
.
te_cond_avtab
,
&
avkey
,
xpermd
);
}
}
out:
read_unlock
(
&
policy_rwlock
);
return
;
allow:
memset
(
xpermd
->
allowed
->
p
,
0xff
,
sizeof
(
xpermd
->
allowed
->
p
));
goto
out
;
}
/**
* security_compute_av - Compute access vector decisions.
...
...
@@ -906,6 +1076,7 @@ static void avd_init(struct av_decision *avd)
* @tsid: target security identifier
* @tclass: target security class
* @avd: access vector decisions
* @xperms: extended permissions
*
* Compute a set of access vector decisions based on the
* SID pair (@ssid, @tsid) for the permissions in @tclass.
...
...
@@ -913,13 +1084,15 @@ static void avd_init(struct av_decision *avd)
void
security_compute_av
(
u32
ssid
,
u32
tsid
,
u16
orig_tclass
,
struct
av_decision
*
avd
)
struct
av_decision
*
avd
,
struct
extended_perms
*
xperms
)
{
u16
tclass
;
struct
context
*
scontext
=
NULL
,
*
tcontext
=
NULL
;
read_lock
(
&
policy_rwlock
);
avd_init
(
avd
);
xperms
->
len
=
0
;
if
(
!
ss_initialized
)
goto
allow
;
...
...
@@ -947,7 +1120,7 @@ void security_compute_av(u32 ssid,
goto
allow
;
goto
out
;
}
context_struct_compute_av
(
scontext
,
tcontext
,
tclass
,
avd
);
context_struct_compute_av
(
scontext
,
tcontext
,
tclass
,
avd
,
xperms
);
map_decision
(
orig_tclass
,
avd
,
policydb
.
allow_unknown
);
out:
read_unlock
(
&
policy_rwlock
);
...
...
@@ -993,7 +1166,7 @@ void security_compute_av_user(u32 ssid,
goto
out
;
}
context_struct_compute_av
(
scontext
,
tcontext
,
tclass
,
avd
);
context_struct_compute_av
(
scontext
,
tcontext
,
tclass
,
avd
,
NULL
);
out:
read_unlock
(
&
policy_rwlock
);
return
;
...
...
@@ -1515,7 +1688,7 @@ static int security_compute_sid(u32 ssid,
if
(
avdatum
)
{
/* Use the type from the type transition/member/change rule. */
newcontext
.
type
=
avdatum
->
data
;
newcontext
.
type
=
avdatum
->
u
.
data
;
}
/* if we have a objname this is a file trans check so check those rules */
...
...
security/selinux/ss/services.h
View file @
3e5f206c
...
...
@@ -11,5 +11,11 @@
extern
struct
policydb
policydb
;
void
services_compute_xperms_drivers
(
struct
extended_perms
*
xperms
,
struct
avtab_node
*
node
);
void
services_compute_xperms_decision
(
struct
extended_perms_decision
*
xpermd
,
struct
avtab_node
*
node
);
#endif
/* _SS_SERVICES_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment