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
nexedi
linux
Commits
1ca00728
Commit
1ca00728
authored
Jun 11, 2013
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'smack-for-3.11' of
git://git.gitorious.org/smack-next/kernel
into ra-next
parents
e2fa3d79
0fcfee61
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
610 additions
and
280 deletions
+610
-280
security/smack/smack.h
security/smack/smack.h
+62
-48
security/smack/smack_access.c
security/smack/smack_access.c
+23
-20
security/smack/smack_lsm.c
security/smack/smack_lsm.c
+498
-186
security/smack/smackfs.c
security/smack/smackfs.c
+27
-26
No files found.
security/smack/smack.h
View file @
1ca00728
...
...
@@ -28,6 +28,38 @@
#define SMK_LABELLEN 24
#define SMK_LONGLABEL 256
/*
* This is the repository for labels seen so that it is
* not necessary to keep allocating tiny chuncks of memory
* and so that they can be shared.
*
* Labels are never modified in place. Anytime a label
* is imported (e.g. xattrset on a file) the list is checked
* for it and it is added if it doesn't exist. The address
* is passed out in either case. Entries are added, but
* never deleted.
*
* Since labels are hanging around anyway it doesn't
* hurt to maintain a secid for those awkward situations
* where kernel components that ought to use LSM independent
* interfaces don't. The secid should go away when all of
* these components have been repaired.
*
* The cipso value associated with the label gets stored here, too.
*
* Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every
* time.
*/
struct
smack_known
{
struct
list_head
list
;
char
*
smk_known
;
u32
smk_secid
;
struct
netlbl_lsm_secattr
smk_netlabel
;
/* on wire labels */
struct
list_head
smk_rules
;
/* access rules */
struct
mutex
smk_rules_lock
;
/* lock for rules */
};
/*
* Maximum number of bytes for the levels in a CIPSO IP option.
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
...
...
@@ -46,25 +78,25 @@ struct superblock_smack {
};
struct
socket_smack
{
char
*
smk_out
;
/* outbound label */
char
*
smk_in
;
/* inbound label */
char
*
smk_packet
;
/* TCP peer label */
struct
smack_known
*
smk_out
;
/* outbound label */
char
*
smk_in
;
/* inbound label */
char
*
smk_packet
;
/* TCP peer label */
};
/*
* Inode smack data
*/
struct
inode_smack
{
char
*
smk_inode
;
/* label of the fso */
char
*
smk_task
;
/* label of the task */
char
*
smk_mmap
;
/* label of the mmap domain */
struct
mutex
smk_lock
;
/* initialization lock */
int
smk_flags
;
/* smack inode flags */
char
*
smk_inode
;
/* label of the fso */
struct
smack_known
*
smk_task
;
/* label of the task */
struct
smack_known
*
smk_mmap
;
/* label of the mmap domain */
struct
mutex
smk_lock
;
/* initialization lock */
int
smk_flags
;
/* smack inode flags */
};
struct
task_smack
{
char
*
smk_task
;
/* label for access control */
char
*
smk_forked
;
/* label when forked */
struct
smack_known
*
smk_task
;
/* label for access control */
struct
smack_known
*
smk_forked
;
/* label when forked */
struct
list_head
smk_rules
;
/* per task access rules */
struct
mutex
smk_rules_lock
;
/* lock for the rules */
};
...
...
@@ -78,7 +110,7 @@ struct task_smack {
*/
struct
smack_rule
{
struct
list_head
list
;
char
*
smk_subject
;
struct
smack_known
*
smk_subject
;
char
*
smk_object
;
int
smk_access
;
};
...
...
@@ -94,35 +126,14 @@ struct smk_netlbladdr {
};
/*
* This is the repository for labels seen so that it is
* not necessary to keep allocating tiny chuncks of memory
* and so that they can be shared.
*
* Labels are never modified in place. Anytime a label
* is imported (e.g. xattrset on a file) the list is checked
* for it and it is added if it doesn't exist. The address
* is passed out in either case. Entries are added, but
* never deleted.
*
* Since labels are hanging around anyway it doesn't
* hurt to maintain a secid for those awkward situations
* where kernel components that ought to use LSM independent
* interfaces don't. The secid should go away when all of
* these components have been repaired.
*
* The cipso value associated with the label gets stored here, too.
*
* Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every
* time.
* An entry in the table identifying ports.
*/
struct
smack_known
{
struct
list_head
list
;
char
*
smk_known
;
u32
smk_secid
;
struct
netlbl_lsm_secattr
smk_netlabel
;
/* on wire labels */
struct
list_head
smk_rules
;
/* access rules */
struct
mutex
smk_rules_lock
;
/* lock for rules */
struct
smk_port_label
{
struct
list_head
list
;
struct
sock
*
smk_sock
;
/* socket initialized on */
unsigned
short
smk_port
;
/* the port number */
char
*
smk_in
;
/* incoming label */
struct
smack_known
*
smk_out
;
/* outgoing label */
};
/*
...
...
@@ -132,6 +143,7 @@ struct smack_known {
#define SMK_FSFLOOR "smackfsfloor="
#define SMK_FSHAT "smackfshat="
#define SMK_FSROOT "smackfsroot="
#define SMK_FSTRANS "smackfstransmute="
#define SMACK_CIPSO_OPTION "-CIPSO"
...
...
@@ -203,9 +215,9 @@ struct inode_smack *new_inode_smack(char *);
* These functions are in smack_access.c
*/
int
smk_access_entry
(
char
*
,
char
*
,
struct
list_head
*
);
int
smk_access
(
char
*
,
char
*
,
int
,
struct
smk_audit_info
*
);
int
smk_access
(
struct
smack_known
*
,
char
*
,
int
,
struct
smk_audit_info
*
);
int
smk_curacc
(
char
*
,
u32
,
struct
smk_audit_info
*
);
char
*
smack_from_secid
(
const
u32
);
struct
smack_known
*
smack_from_secid
(
const
u32
);
char
*
smk_parse_smack
(
const
char
*
string
,
int
len
);
int
smk_netlbl_mls
(
int
,
char
*
,
struct
netlbl_lsm_secattr
*
,
int
);
char
*
smk_import
(
const
char
*
,
int
);
...
...
@@ -218,7 +230,7 @@ u32 smack_to_secid(const char *);
*/
extern
int
smack_cipso_direct
;
extern
int
smack_cipso_mapped
;
extern
char
*
smack_net_ambient
;
extern
struct
smack_known
*
smack_net_ambient
;
extern
char
*
smack_onlycap
;
extern
const
char
*
smack_cipso_option
;
...
...
@@ -254,17 +266,17 @@ static inline char *smk_of_inode(const struct inode *isp)
}
/*
* Present a pointer to the smack label in an task blob.
* Present a pointer to the smack label
entry
in an task blob.
*/
static
inline
char
*
smk_of_task
(
const
struct
task_smack
*
tsp
)
static
inline
struct
smack_known
*
smk_of_task
(
const
struct
task_smack
*
tsp
)
{
return
tsp
->
smk_task
;
}
/*
* Present a pointer to the forked smack label in an task blob.
* Present a pointer to the forked smack label
entry
in an task blob.
*/
static
inline
char
*
smk_of_forked
(
const
struct
task_smack
*
tsp
)
static
inline
struct
smack_known
*
smk_of_forked
(
const
struct
task_smack
*
tsp
)
{
return
tsp
->
smk_forked
;
}
...
...
@@ -272,7 +284,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp)
/*
* Present a pointer to the smack label in the current task blob.
*/
static
inline
char
*
smk_of_current
(
void
)
static
inline
struct
smack_known
*
smk_of_current
(
void
)
{
return
smk_of_task
(
current_security
());
}
...
...
@@ -283,9 +295,11 @@ static inline char *smk_of_current(void)
*/
static
inline
int
smack_privileged
(
int
cap
)
{
struct
smack_known
*
skp
=
smk_of_current
();
if
(
!
capable
(
cap
))
return
0
;
if
(
smack_onlycap
==
NULL
||
smack_onlycap
==
s
mk_of_current
()
)
if
(
smack_onlycap
==
NULL
||
smack_onlycap
==
s
kp
->
smk_known
)
return
1
;
return
0
;
}
...
...
security/smack/smack_access.c
View file @
1ca00728
...
...
@@ -93,7 +93,7 @@ int smk_access_entry(char *subject_label, char *object_label,
list_for_each_entry_rcu
(
srp
,
rule_list
,
list
)
{
if
(
srp
->
smk_object
==
object_label
&&
srp
->
smk_subject
==
subject_label
)
{
srp
->
smk_subject
->
smk_known
==
subject_label
)
{
may
=
srp
->
smk_access
;
break
;
}
...
...
@@ -104,7 +104,7 @@ int smk_access_entry(char *subject_label, char *object_label,
/**
* smk_access - determine if a subject has a specific access to an object
* @subject_
label: a pointer to the subject's Smack label
* @subject_
known: a pointer to the subject's Smack label entry
* @object_label: a pointer to the object's Smack label
* @request: the access requested, in "MAY" format
* @a : a pointer to the audit data
...
...
@@ -115,10 +115,9 @@ int smk_access_entry(char *subject_label, char *object_label,
*
* Smack labels are shared on smack_list
*/
int
smk_access
(
char
*
subject_label
,
char
*
object_label
,
int
request
,
struct
smk_audit_info
*
a
)
int
smk_access
(
struct
smack_known
*
subject_known
,
char
*
object_label
,
int
request
,
struct
smk_audit_info
*
a
)
{
struct
smack_known
*
skp
;
int
may
=
MAY_NOT
;
int
rc
=
0
;
...
...
@@ -127,7 +126,7 @@ int smk_access(char *subject_label, char *object_label, int request,
*
* A star subject can't access any object.
*/
if
(
subject_
label
==
smack_known_star
.
smk_known
)
{
if
(
subject_
known
==
&
smack_known_star
)
{
rc
=
-
EACCES
;
goto
out_audit
;
}
...
...
@@ -137,7 +136,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* An internet subject can access any object.
*/
if
(
object_label
==
smack_known_web
.
smk_known
||
subject_
label
==
smack_known_web
.
smk_known
)
subject_
known
==
&
smack_known_web
)
goto
out_audit
;
/*
* A star object can be accessed by any subject.
...
...
@@ -148,7 +147,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* An object can be accessed in any way by a subject
* with the same label.
*/
if
(
subject_
label
==
object_label
)
if
(
subject_
known
->
smk_known
==
object_label
)
goto
out_audit
;
/*
* A hat subject can read any object.
...
...
@@ -157,7 +156,7 @@ int smk_access(char *subject_label, char *object_label, int request,
if
((
request
&
MAY_ANYREAD
)
==
request
)
{
if
(
object_label
==
smack_known_floor
.
smk_known
)
goto
out_audit
;
if
(
subject_
label
==
smack_known_hat
.
smk_known
)
if
(
subject_
known
==
&
smack_known_hat
)
goto
out_audit
;
}
/*
...
...
@@ -167,9 +166,9 @@ int smk_access(char *subject_label, char *object_label, int request,
* good. A negative response from smk_access_entry()
* indicates there is no entry for this pair.
*/
skp
=
smk_find_entry
(
subject_label
);
rcu_read_lock
();
may
=
smk_access_entry
(
subject_label
,
object_label
,
&
skp
->
smk_rules
);
may
=
smk_access_entry
(
subject_known
->
smk_known
,
object_label
,
&
subject_known
->
smk_rules
);
rcu_read_unlock
();
if
(
may
>
0
&&
(
request
&
may
)
==
request
)
...
...
@@ -179,7 +178,8 @@ int smk_access(char *subject_label, char *object_label, int request,
out_audit:
#ifdef CONFIG_AUDIT
if
(
a
)
smack_log
(
subject_label
,
object_label
,
request
,
rc
,
a
);
smack_log
(
subject_known
->
smk_known
,
object_label
,
request
,
rc
,
a
);
#endif
return
rc
;
}
...
...
@@ -198,20 +198,21 @@ int smk_access(char *subject_label, char *object_label, int request,
int
smk_curacc
(
char
*
obj_label
,
u32
mode
,
struct
smk_audit_info
*
a
)
{
struct
task_smack
*
tsp
=
current_security
();
char
*
s
p
=
smk_of_task
(
tsp
);
struct
smack_known
*
sk
p
=
smk_of_task
(
tsp
);
int
may
;
int
rc
;
/*
* Check the global rule list
*/
rc
=
smk_access
(
sp
,
obj_label
,
mode
,
NULL
);
rc
=
smk_access
(
s
k
p
,
obj_label
,
mode
,
NULL
);
if
(
rc
==
0
)
{
/*
* If there is an entry in the task's rule list
* it can further restrict access.
*/
may
=
smk_access_entry
(
sp
,
obj_label
,
&
tsp
->
smk_rules
);
may
=
smk_access_entry
(
skp
->
smk_known
,
obj_label
,
&
tsp
->
smk_rules
);
if
(
may
<
0
)
goto
out_audit
;
if
((
mode
&
may
)
==
mode
)
...
...
@@ -228,7 +229,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
out_audit:
#ifdef CONFIG_AUDIT
if
(
a
)
smack_log
(
s
p
,
obj_label
,
mode
,
rc
,
a
);
smack_log
(
s
kp
->
smk_known
,
obj_label
,
mode
,
rc
,
a
);
#endif
return
rc
;
}
...
...
@@ -402,6 +403,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
sap
->
flags
|=
NETLBL_SECATTR_MLS_CAT
;
sap
->
attr
.
mls
.
lvl
=
level
;
sap
->
attr
.
mls
.
cat
=
netlbl_secattr_catmap_alloc
(
GFP_ATOMIC
);
if
(
!
sap
->
attr
.
mls
.
cat
)
return
-
ENOMEM
;
sap
->
attr
.
mls
.
cat
->
startbit
=
0
;
for
(
cat
=
1
,
cp
=
catset
,
byte
=
0
;
byte
<
len
;
cp
++
,
byte
++
)
...
...
@@ -513,10 +516,10 @@ char *smk_import(const char *string, int len)
* smack_from_secid - find the Smack label associated with a secid
* @secid: an integer that might be associated with a Smack label
*
* Returns a pointer to the appropriate Smack label if there is one,
* Returns a pointer to the appropriate Smack label
entry
if there is one,
* otherwise a pointer to the invalid Smack label.
*/
char
*
smack_from_secid
(
const
u32
secid
)
struct
smack_known
*
smack_from_secid
(
const
u32
secid
)
{
struct
smack_known
*
skp
;
...
...
@@ -524,7 +527,7 @@ char *smack_from_secid(const u32 secid)
list_for_each_entry_rcu
(
skp
,
&
smack_known_list
,
list
)
{
if
(
skp
->
smk_secid
==
secid
)
{
rcu_read_unlock
();
return
skp
->
smk_known
;
return
skp
;
}
}
...
...
@@ -533,7 +536,7 @@ char *smack_from_secid(const u32 secid)
* of a secid that is not on the list.
*/
rcu_read_unlock
();
return
smack_known_invalid
.
smk_known
;
return
&
smack_known_invalid
;
}
/**
...
...
security/smack/smack_lsm.c
View file @
1ca00728
...
...
@@ -27,10 +27,13 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/dccp.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/pipe_fs_i.h>
#include <net/cipso_ipv4.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/audit.h>
#include <linux/magic.h>
#include <linux/dcache.h>
...
...
@@ -45,6 +48,12 @@
#define TRANS_TRUE "TRUE"
#define TRANS_TRUE_SIZE 4
#define SMK_CONNECTING 0
#define SMK_RECEIVING 1
#define SMK_SENDING 2
LIST_HEAD
(
smk_ipv6_port_list
);
/**
* smk_fetch - Fetch the smack label from a file.
* @ip: a pointer to the inode
...
...
@@ -53,11 +62,12 @@
* Returns a pointer to the master list entry for the Smack label
* or NULL if there was no label to fetch.
*/
static
char
*
smk_fetch
(
const
char
*
name
,
struct
inode
*
ip
,
struct
dentry
*
dp
)
static
struct
smack_known
*
smk_fetch
(
const
char
*
name
,
struct
inode
*
ip
,
struct
dentry
*
dp
)
{
int
rc
;
char
*
buffer
;
char
*
result
=
NULL
;
struct
smack_known
*
skp
=
NULL
;
if
(
ip
->
i_op
->
getxattr
==
NULL
)
return
NULL
;
...
...
@@ -68,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
rc
=
ip
->
i_op
->
getxattr
(
dp
,
name
,
buffer
,
SMK_LONGLABEL
);
if
(
rc
>
0
)
result
=
smk_import
(
buffer
,
rc
);
skp
=
smk_import_entry
(
buffer
,
rc
);
kfree
(
buffer
);
return
result
;
return
skp
;
}
/**
...
...
@@ -102,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack)
*
* Returns the new blob or NULL if there's no memory available
*/
static
struct
task_smack
*
new_task_smack
(
char
*
task
,
char
*
forked
,
gfp_t
gfp
)
static
struct
task_smack
*
new_task_smack
(
struct
smack_known
*
task
,
struct
smack_known
*
forked
,
gfp_t
gfp
)
{
struct
task_smack
*
tsp
;
...
...
@@ -164,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
int
rc
;
struct
smk_audit_info
ad
;
char
*
ts
p
;
struct
smack_known
*
sk
p
;
rc
=
cap_ptrace_access_check
(
ctp
,
mode
);
if
(
rc
!=
0
)
return
rc
;
ts
p
=
smk_of_task
(
task_security
(
ctp
));
sk
p
=
smk_of_task
(
task_security
(
ctp
));
smk_ad_init
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_TASK
);
smk_ad_setfield_u_tsk
(
&
ad
,
ctp
);
rc
=
smk_curacc
(
tsp
,
MAY_READWRITE
,
&
ad
);
rc
=
smk_curacc
(
skp
->
smk_known
,
MAY_READWRITE
,
&
ad
);
return
rc
;
}
...
...
@@ -190,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
{
int
rc
;
struct
smk_audit_info
ad
;
char
*
ts
p
;
struct
smack_known
*
sk
p
;
rc
=
cap_ptrace_traceme
(
ptp
);
if
(
rc
!=
0
)
return
rc
;
ts
p
=
smk_of_task
(
task_security
(
ptp
));
sk
p
=
smk_of_task
(
task_security
(
ptp
));
smk_ad_init
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_TASK
);
smk_ad_setfield_u_tsk
(
&
ad
,
ptp
);
rc
=
smk_curacc
(
tsp
,
MAY_READWRITE
,
&
ad
);
rc
=
smk_curacc
(
skp
->
smk_known
,
MAY_READWRITE
,
&
ad
);
return
rc
;
}
...
...
@@ -215,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
static
int
smack_syslog
(
int
typefrom_file
)
{
int
rc
=
0
;
char
*
s
p
=
smk_of_current
();
struct
smack_known
*
sk
p
=
smk_of_current
();
if
(
smack_privileged
(
CAP_MAC_OVERRIDE
))
return
0
;
if
(
s
p
!=
smack_known_floor
.
smk_known
)
if
(
s
kp
!=
&
smack_known_floor
)
rc
=
-
EACCES
;
return
rc
;
...
...
@@ -250,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb)
sbsp
->
smk_default
=
smack_known_floor
.
smk_known
;
sbsp
->
smk_floor
=
smack_known_floor
.
smk_known
;
sbsp
->
smk_hat
=
smack_known_hat
.
smk_known
;
sbsp
->
smk_initialized
=
0
;
/*
* smk_initialized will be zero from kzalloc.
*/
sb
->
s_security
=
sbsp
;
return
0
;
...
...
@@ -295,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts)
dp
=
smackopts
;
else
if
(
strstr
(
cp
,
SMK_FSROOT
)
==
cp
)
dp
=
smackopts
;
else
if
(
strstr
(
cp
,
SMK_FSTRANS
)
==
cp
)
dp
=
smackopts
;
else
dp
=
otheropts
;
...
...
@@ -330,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
char
*
op
;
char
*
commap
;
char
*
nsp
;
int
transmute
=
0
;
if
(
sp
->
smk_initialized
!=
0
)
if
(
sp
->
smk_initialized
)
return
0
;
sp
->
smk_initialized
=
1
;
...
...
@@ -362,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
nsp
=
smk_import
(
op
,
0
);
if
(
nsp
!=
NULL
)
sp
->
smk_root
=
nsp
;
}
else
if
(
strncmp
(
op
,
SMK_FSTRANS
,
strlen
(
SMK_FSTRANS
))
==
0
)
{
op
+=
strlen
(
SMK_FSTRANS
);
nsp
=
smk_import
(
op
,
0
);
if
(
nsp
!=
NULL
)
{
sp
->
smk_root
=
nsp
;
transmute
=
1
;
}
}
}
...
...
@@ -369,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
* Initialize the root inode.
*/
isp
=
inode
->
i_security
;
if
(
i
sp
==
NULL
)
if
(
i
node
->
i_security
==
NULL
)
{
inode
->
i_security
=
new_inode_smack
(
sp
->
smk_root
);
else
isp
=
inode
->
i_security
;
}
else
isp
->
smk_inode
=
sp
->
smk_root
;
if
(
transmute
)
isp
->
smk_flags
|=
SMK_INODE_TRANSMUTE
;
return
0
;
}
...
...
@@ -524,7 +550,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm)
*/
static
int
smack_inode_alloc_security
(
struct
inode
*
inode
)
{
inode
->
i_security
=
new_inode_smack
(
smk_of_current
());
struct
smack_known
*
skp
=
smk_of_current
();
inode
->
i_security
=
new_inode_smack
(
skp
->
smk_known
);
if
(
inode
->
i_security
==
NULL
)
return
-
ENOMEM
;
return
0
;
...
...
@@ -557,9 +585,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const
struct
qstr
*
qstr
,
char
**
name
,
void
**
value
,
size_t
*
len
)
{
struct
smack_known
*
skp
;
struct
inode_smack
*
issp
=
inode
->
i_security
;
char
*
cs
p
=
smk_of_current
();
struct
smack_known
*
sk
p
=
smk_of_current
();
char
*
isp
=
smk_of_inode
(
inode
);
char
*
dsp
=
smk_of_inode
(
dir
);
int
may
;
...
...
@@ -571,9 +598,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
}
if
(
value
)
{
skp
=
smk_find_entry
(
csp
);
rcu_read_lock
();
may
=
smk_access_entry
(
csp
,
dsp
,
&
skp
->
smk_rules
);
may
=
smk_access_entry
(
skp
->
smk_known
,
dsp
,
&
skp
->
smk_rules
);
rcu_read_unlock
();
/*
...
...
@@ -862,29 +888,31 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
static
void
smack_inode_post_setxattr
(
struct
dentry
*
dentry
,
const
char
*
name
,
const
void
*
value
,
size_t
size
,
int
flags
)
{
char
*
ns
p
;
struct
smack_known
*
sk
p
;
struct
inode_smack
*
isp
=
dentry
->
d_inode
->
i_security
;
if
(
strcmp
(
name
,
XATTR_NAME_SMACKTRANSMUTE
)
==
0
)
{
isp
->
smk_flags
|=
SMK_INODE_TRANSMUTE
;
return
;
}
skp
=
smk_import_entry
(
value
,
size
);
if
(
strcmp
(
name
,
XATTR_NAME_SMACK
)
==
0
)
{
nsp
=
smk_import
(
value
,
size
);
if
(
nsp
!=
NULL
)
isp
->
smk_inode
=
nsp
;
if
(
skp
!=
NULL
)
isp
->
smk_inode
=
skp
->
smk_known
;
else
isp
->
smk_inode
=
smack_known_invalid
.
smk_known
;
}
else
if
(
strcmp
(
name
,
XATTR_NAME_SMACKEXEC
)
==
0
)
{
nsp
=
smk_import
(
value
,
size
);
if
(
nsp
!=
NULL
)
isp
->
smk_task
=
nsp
;
if
(
skp
!=
NULL
)
isp
->
smk_task
=
skp
;
else
isp
->
smk_task
=
smack_known_invalid
.
smk_known
;
isp
->
smk_task
=
&
smack_known_invalid
;
}
else
if
(
strcmp
(
name
,
XATTR_NAME_SMACKMMAP
)
==
0
)
{
nsp
=
smk_import
(
value
,
size
);
if
(
nsp
!=
NULL
)
isp
->
smk_mmap
=
nsp
;
if
(
skp
!=
NULL
)
isp
->
smk_mmap
=
skp
;
else
isp
->
smk_mmap
=
smack_known_invalid
.
smk_known
;
}
else
if
(
strcmp
(
name
,
XATTR_NAME_SMACKTRANSMUTE
)
==
0
)
isp
->
smk_flags
|=
SMK_INODE_TRANSMUTE
;
isp
->
smk_mmap
=
&
smack_known_invalid
;
}
return
;
}
...
...
@@ -990,7 +1018,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
if
(
strcmp
(
name
,
XATTR_SMACK_IPIN
)
==
0
)
isp
=
ssp
->
smk_in
;
else
if
(
strcmp
(
name
,
XATTR_SMACK_IPOUT
)
==
0
)
isp
=
ssp
->
smk_out
;
isp
=
ssp
->
smk_out
->
smk_known
;
else
return
-
EOPNOTSUPP
;
...
...
@@ -1070,7 +1098,9 @@ static int smack_file_permission(struct file *file, int mask)
*/
static
int
smack_file_alloc_security
(
struct
file
*
file
)
{
file
->
f_security
=
smk_of_current
();
struct
smack_known
*
skp
=
smk_of_current
();
file
->
f_security
=
skp
->
smk_known
;
return
0
;
}
...
...
@@ -1181,10 +1211,9 @@ static int smack_mmap_file(struct file *file,
unsigned
long
flags
)
{
struct
smack_known
*
skp
;
struct
smack_known
*
mkp
;
struct
smack_rule
*
srp
;
struct
task_smack
*
tsp
;
char
*
sp
;
char
*
msmack
;
char
*
osmack
;
struct
inode_smack
*
isp
;
int
may
;
...
...
@@ -1198,11 +1227,10 @@ static int smack_mmap_file(struct file *file,
isp
=
file_inode
(
file
)
->
i_security
;
if
(
isp
->
smk_mmap
==
NULL
)
return
0
;
m
smack
=
isp
->
smk_mmap
;
m
kp
=
isp
->
smk_mmap
;
tsp
=
current_security
();
sp
=
smk_of_current
();
skp
=
smk_find_entry
(
sp
);
skp
=
smk_of_current
();
rc
=
0
;
rcu_read_lock
();
...
...
@@ -1216,13 +1244,13 @@ static int smack_mmap_file(struct file *file,
/*
* Matching labels always allows access.
*/
if
(
m
smack
==
osmack
)
if
(
m
kp
->
smk_known
==
osmack
)
continue
;
/*
* If there is a matching local rule take
* that into account as well.
*/
may
=
smk_access_entry
(
srp
->
smk_subject
,
osmack
,
may
=
smk_access_entry
(
srp
->
smk_subject
->
smk_known
,
osmack
,
&
tsp
->
smk_rules
);
if
(
may
==
-
ENOENT
)
may
=
srp
->
smk_access
;
...
...
@@ -1240,8 +1268,8 @@ static int smack_mmap_file(struct file *file,
* If there isn't one a SMACK64MMAP subject
* can't have as much access as current.
*/
skp
=
smk_find_entry
(
msmack
);
mmay
=
smk_access_entry
(
msmack
,
osmack
,
&
s
kp
->
smk_rules
);
mmay
=
smk_access_entry
(
mkp
->
smk_known
,
osmack
,
&
m
kp
->
smk_rules
);
if
(
mmay
==
-
ENOENT
)
{
rc
=
-
EACCES
;
break
;
...
...
@@ -1250,7 +1278,8 @@ static int smack_mmap_file(struct file *file,
* If there is a local entry it modifies the
* potential access, too.
*/
tmay
=
smk_access_entry
(
msmack
,
osmack
,
&
tsp
->
smk_rules
);
tmay
=
smk_access_entry
(
mkp
->
smk_known
,
osmack
,
&
tsp
->
smk_rules
);
if
(
tmay
!=
-
ENOENT
)
mmay
&=
tmay
;
...
...
@@ -1279,7 +1308,9 @@ static int smack_mmap_file(struct file *file,
*/
static
int
smack_file_set_fowner
(
struct
file
*
file
)
{
file
->
f_security
=
smk_of_current
();
struct
smack_known
*
skp
=
smk_of_current
();
file
->
f_security
=
skp
->
smk_known
;
return
0
;
}
...
...
@@ -1297,9 +1328,10 @@ static int smack_file_set_fowner(struct file *file)
static
int
smack_file_send_sigiotask
(
struct
task_struct
*
tsk
,
struct
fown_struct
*
fown
,
int
signum
)
{
struct
smack_known
*
skp
;
struct
smack_known
*
tkp
=
smk_of_task
(
tsk
->
cred
->
security
);
struct
file
*
file
;
int
rc
;
char
*
tsp
=
smk_of_task
(
tsk
->
cred
->
security
);
struct
smk_audit_info
ad
;
/*
...
...
@@ -1308,13 +1340,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
file
=
container_of
(
fown
,
struct
file
,
f_owner
);
/* we don't log here as rc can be overriden */
rc
=
smk_access
(
file
->
f_security
,
tsp
,
MAY_WRITE
,
NULL
);
skp
=
smk_find_entry
(
file
->
f_security
);
rc
=
smk_access
(
skp
,
tkp
->
smk_known
,
MAY_WRITE
,
NULL
);
if
(
rc
!=
0
&&
has_capability
(
tsk
,
CAP_MAC_OVERRIDE
))
rc
=
0
;
smk_ad_init
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_TASK
);
smk_ad_setfield_u_tsk
(
&
ad
,
tsk
);
smack_log
(
file
->
f_security
,
t
sp
,
MAY_WRITE
,
rc
,
&
ad
);
smack_log
(
file
->
f_security
,
t
kp
->
smk_known
,
MAY_WRITE
,
rc
,
&
ad
);
return
rc
;
}
...
...
@@ -1469,12 +1502,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
static
int
smack_kernel_act_as
(
struct
cred
*
new
,
u32
secid
)
{
struct
task_smack
*
new_tsp
=
new
->
security
;
char
*
smack
=
smack_from_secid
(
secid
);
struct
smack_known
*
skp
=
smack_from_secid
(
secid
);
if
(
s
mack
==
NULL
)
if
(
s
kp
==
NULL
)
return
-
EINVAL
;
new_tsp
->
smk_task
=
s
mack
;
new_tsp
->
smk_task
=
s
kp
;
return
0
;
}
...
...
@@ -1492,8 +1525,8 @@ static int smack_kernel_create_files_as(struct cred *new,
struct
inode_smack
*
isp
=
inode
->
i_security
;
struct
task_smack
*
tsp
=
new
->
security
;
tsp
->
smk_forked
=
isp
->
smk_inode
;
tsp
->
smk_task
=
isp
->
smk_inode
;
tsp
->
smk_forked
=
smk_find_entry
(
isp
->
smk_inode
)
;
tsp
->
smk_task
=
tsp
->
smk_forked
;
return
0
;
}
...
...
@@ -1509,10 +1542,11 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
const
char
*
caller
)
{
struct
smk_audit_info
ad
;
struct
smack_known
*
skp
=
smk_of_task
(
task_security
(
p
));
smk_ad_init
(
&
ad
,
caller
,
LSM_AUDIT_DATA_TASK
);
smk_ad_setfield_u_tsk
(
&
ad
,
p
);
return
smk_curacc
(
s
mk_of_task
(
task_security
(
p
))
,
access
,
&
ad
);
return
smk_curacc
(
s
kp
->
smk_known
,
access
,
&
ad
);
}
/**
...
...
@@ -1558,7 +1592,9 @@ static int smack_task_getsid(struct task_struct *p)
*/
static
void
smack_task_getsecid
(
struct
task_struct
*
p
,
u32
*
secid
)
{
*
secid
=
smack_to_secid
(
smk_of_task
(
task_security
(
p
)));
struct
smack_known
*
skp
=
smk_of_task
(
task_security
(
p
));
*
secid
=
skp
->
smk_secid
;
}
/**
...
...
@@ -1662,6 +1698,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
int
sig
,
u32
secid
)
{
struct
smk_audit_info
ad
;
struct
smack_known
*
skp
;
struct
smack_known
*
tkp
=
smk_of_task
(
task_security
(
p
));
smk_ad_init
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_TASK
);
smk_ad_setfield_u_tsk
(
&
ad
,
p
);
...
...
@@ -1670,15 +1708,14 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver.
*/
if
(
secid
==
0
)
return
smk_curacc
(
smk_of_task
(
task_security
(
p
)),
MAY_WRITE
,
&
ad
);
return
smk_curacc
(
tkp
->
smk_known
,
MAY_WRITE
,
&
ad
);
/*
* If the secid isn't 0 we're dealing with some USB IO
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
return
smk_access
(
smack_from_secid
(
secid
),
smk_of_task
(
task_security
(
p
))
,
MAY_WRITE
,
&
ad
);
skp
=
smack_from_secid
(
secid
);
return
smk_access
(
skp
,
tkp
->
smk_known
,
MAY_WRITE
,
&
ad
);
}
/**
...
...
@@ -1710,7 +1747,9 @@ static int smack_task_wait(struct task_struct *p)
static
void
smack_task_to_inode
(
struct
task_struct
*
p
,
struct
inode
*
inode
)
{
struct
inode_smack
*
isp
=
inode
->
i_security
;
isp
->
smk_inode
=
smk_of_task
(
task_security
(
p
));
struct
smack_known
*
skp
=
smk_of_task
(
task_security
(
p
));
isp
->
smk_inode
=
skp
->
smk_known
;
}
/*
...
...
@@ -1729,15 +1768,15 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
*/
static
int
smack_sk_alloc_security
(
struct
sock
*
sk
,
int
family
,
gfp_t
gfp_flags
)
{
char
*
cs
p
=
smk_of_current
();
struct
smack_known
*
sk
p
=
smk_of_current
();
struct
socket_smack
*
ssp
;
ssp
=
kzalloc
(
sizeof
(
struct
socket_smack
),
gfp_flags
);
if
(
ssp
==
NULL
)
return
-
ENOMEM
;
ssp
->
smk_in
=
csp
;
ssp
->
smk_out
=
cs
p
;
ssp
->
smk_in
=
skp
->
smk_known
;
ssp
->
smk_out
=
sk
p
;
ssp
->
smk_packet
=
NULL
;
sk
->
sk_security
=
ssp
;
...
...
@@ -1824,7 +1863,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
labeled
==
SMACK_UNLABELED_SOCKET
)
netlbl_sock_delattr
(
sk
);
else
{
skp
=
s
mk_find_entry
(
ssp
->
smk_out
)
;
skp
=
s
sp
->
smk_out
;
rc
=
netlbl_sock_setattr
(
sk
,
sk
->
sk_family
,
&
skp
->
smk_netlabel
);
}
...
...
@@ -1847,6 +1886,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
*/
static
int
smack_netlabel_send
(
struct
sock
*
sk
,
struct
sockaddr_in
*
sap
)
{
struct
smack_known
*
skp
;
int
rc
;
int
sk_lbl
;
char
*
hostsp
;
...
...
@@ -1865,7 +1905,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
ad
.
a
.
u
.
net
->
v4info
.
daddr
=
sap
->
sin_addr
.
s_addr
;
#endif
sk_lbl
=
SMACK_UNLABELED_SOCKET
;
rc
=
smk_access
(
ssp
->
smk_out
,
hostsp
,
MAY_WRITE
,
&
ad
);
skp
=
ssp
->
smk_out
;
rc
=
smk_access
(
skp
,
hostsp
,
MAY_WRITE
,
&
ad
);
}
else
{
sk_lbl
=
SMACK_CIPSO_SOCKET
;
rc
=
0
;
...
...
@@ -1877,6 +1918,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
return
smack_netlabel
(
sk
,
sk_lbl
);
}
/**
* smk_ipv6_port_label - Smack port access table management
* @sock: socket
* @address: address
*
* Create or update the port list entry
*/
static
void
smk_ipv6_port_label
(
struct
socket
*
sock
,
struct
sockaddr
*
address
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sockaddr_in6
*
addr6
;
struct
socket_smack
*
ssp
=
sock
->
sk
->
sk_security
;
struct
smk_port_label
*
spp
;
unsigned
short
port
=
0
;
if
(
address
==
NULL
)
{
/*
* This operation is changing the Smack information
* on the bound socket. Take the changes to the port
* as well.
*/
list_for_each_entry
(
spp
,
&
smk_ipv6_port_list
,
list
)
{
if
(
sk
!=
spp
->
smk_sock
)
continue
;
spp
->
smk_in
=
ssp
->
smk_in
;
spp
->
smk_out
=
ssp
->
smk_out
;
return
;
}
/*
* A NULL address is only used for updating existing
* bound entries. If there isn't one, it's OK.
*/
return
;
}
addr6
=
(
struct
sockaddr_in6
*
)
address
;
port
=
ntohs
(
addr6
->
sin6_port
);
/*
* This is a special case that is safely ignored.
*/
if
(
port
==
0
)
return
;
/*
* Look for an existing port list entry.
* This is an indication that a port is getting reused.
*/
list_for_each_entry
(
spp
,
&
smk_ipv6_port_list
,
list
)
{
if
(
spp
->
smk_port
!=
port
)
continue
;
spp
->
smk_port
=
port
;
spp
->
smk_sock
=
sk
;
spp
->
smk_in
=
ssp
->
smk_in
;
spp
->
smk_out
=
ssp
->
smk_out
;
return
;
}
/*
* A new port entry is required.
*/
spp
=
kzalloc
(
sizeof
(
*
spp
),
GFP_KERNEL
);
if
(
spp
==
NULL
)
return
;
spp
->
smk_port
=
port
;
spp
->
smk_sock
=
sk
;
spp
->
smk_in
=
ssp
->
smk_in
;
spp
->
smk_out
=
ssp
->
smk_out
;
list_add
(
&
spp
->
list
,
&
smk_ipv6_port_list
);
return
;
}
/**
* smk_ipv6_port_check - check Smack port access
* @sock: socket
* @address: address
*
* Create or update the port list entry
*/
static
int
smk_ipv6_port_check
(
struct
sock
*
sk
,
struct
sockaddr
*
address
,
int
act
)
{
__be16
*
bep
;
__be32
*
be32p
;
struct
sockaddr_in6
*
addr6
;
struct
smk_port_label
*
spp
;
struct
socket_smack
*
ssp
=
sk
->
sk_security
;
struct
smack_known
*
skp
;
unsigned
short
port
=
0
;
char
*
object
;
struct
smk_audit_info
ad
;
#ifdef CONFIG_AUDIT
struct
lsm_network_audit
net
;
#endif
if
(
act
==
SMK_RECEIVING
)
{
skp
=
smack_net_ambient
;
object
=
ssp
->
smk_in
;
}
else
{
skp
=
ssp
->
smk_out
;
object
=
smack_net_ambient
->
smk_known
;
}
/*
* Get the IP address and port from the address.
*/
addr6
=
(
struct
sockaddr_in6
*
)
address
;
port
=
ntohs
(
addr6
->
sin6_port
);
bep
=
(
__be16
*
)(
&
addr6
->
sin6_addr
);
be32p
=
(
__be32
*
)(
&
addr6
->
sin6_addr
);
/*
* It's remote, so port lookup does no good.
*/
if
(
be32p
[
0
]
||
be32p
[
1
]
||
be32p
[
2
]
||
bep
[
6
]
||
ntohs
(
bep
[
7
])
!=
1
)
goto
auditout
;
/*
* It's local so the send check has to have passed.
*/
if
(
act
==
SMK_RECEIVING
)
{
skp
=
&
smack_known_web
;
goto
auditout
;
}
list_for_each_entry
(
spp
,
&
smk_ipv6_port_list
,
list
)
{
if
(
spp
->
smk_port
!=
port
)
continue
;
object
=
spp
->
smk_in
;
if
(
act
==
SMK_CONNECTING
)
ssp
->
smk_packet
=
spp
->
smk_out
->
smk_known
;
break
;
}
auditout:
#ifdef CONFIG_AUDIT
smk_ad_init_net
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_NET
,
&
net
);
ad
.
a
.
u
.
net
->
family
=
sk
->
sk_family
;
ad
.
a
.
u
.
net
->
dport
=
port
;
if
(
act
==
SMK_RECEIVING
)
ad
.
a
.
u
.
net
->
v6info
.
saddr
=
addr6
->
sin6_addr
;
else
ad
.
a
.
u
.
net
->
v6info
.
daddr
=
addr6
->
sin6_addr
;
#endif
return
smk_access
(
skp
,
object
,
MAY_WRITE
,
&
ad
);
}
/**
* smack_inode_setsecurity - set smack xattrs
* @inode: the object
...
...
@@ -1892,7 +2082,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
static
int
smack_inode_setsecurity
(
struct
inode
*
inode
,
const
char
*
name
,
const
void
*
value
,
size_t
size
,
int
flags
)
{
char
*
s
p
;
struct
smack_known
*
sk
p
;
struct
inode_smack
*
nsp
=
inode
->
i_security
;
struct
socket_smack
*
ssp
;
struct
socket
*
sock
;
...
...
@@ -1901,12 +2091,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
if
(
value
==
NULL
||
size
>
SMK_LONGLABEL
||
size
==
0
)
return
-
EACCES
;
s
p
=
smk_import
(
value
,
size
);
if
(
sp
==
NULL
)
s
kp
=
smk_import_entry
(
value
,
size
);
if
(
s
k
p
==
NULL
)
return
-
EINVAL
;
if
(
strcmp
(
name
,
XATTR_SMACK_SUFFIX
)
==
0
)
{
nsp
->
smk_inode
=
s
p
;
nsp
->
smk_inode
=
s
kp
->
smk_known
;
nsp
->
smk_flags
|=
SMK_INODE_INSTANT
;
return
0
;
}
...
...
@@ -1923,10 +2113,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
ssp
=
sock
->
sk
->
sk_security
;
if
(
strcmp
(
name
,
XATTR_SMACK_IPIN
)
==
0
)
ssp
->
smk_in
=
s
p
;
ssp
->
smk_in
=
s
kp
->
smk_known
;
else
if
(
strcmp
(
name
,
XATTR_SMACK_IPOUT
)
==
0
)
{
ssp
->
smk_out
=
sp
;
if
(
sock
->
sk
->
sk_family
!=
PF_UNIX
)
{
ssp
->
smk_out
=
s
k
p
;
if
(
sock
->
sk
->
sk_family
==
PF_INET
)
{
rc
=
smack_netlabel
(
sock
->
sk
,
SMACK_CIPSO_SOCKET
);
if
(
rc
!=
0
)
printk
(
KERN_WARNING
...
...
@@ -1936,6 +2126,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
}
else
return
-
EOPNOTSUPP
;
if
(
sock
->
sk
->
sk_family
==
PF_INET6
)
smk_ipv6_port_label
(
sock
,
NULL
);
return
0
;
}
...
...
@@ -1962,6 +2155,25 @@ static int smack_socket_post_create(struct socket *sock, int family,
return
smack_netlabel
(
sock
->
sk
,
SMACK_CIPSO_SOCKET
);
}
/**
* smack_socket_bind - record port binding information.
* @sock: the socket
* @address: the port address
* @addrlen: size of the address
*
* Records the label bound to a port.
*
* Returns 0
*/
static
int
smack_socket_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
address
,
int
addrlen
)
{
if
(
sock
->
sk
!=
NULL
&&
sock
->
sk
->
sk_family
==
PF_INET6
)
smk_ipv6_port_label
(
sock
,
address
);
return
0
;
}
/**
* smack_socket_connect - connect access check
* @sock: the socket
...
...
@@ -1975,12 +2187,24 @@ static int smack_socket_post_create(struct socket *sock, int family,
static
int
smack_socket_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
sap
,
int
addrlen
)
{
if
(
sock
->
sk
==
NULL
||
sock
->
sk
->
sk_family
!=
PF_INET
)
int
rc
=
0
;
if
(
sock
->
sk
==
NULL
)
return
0
;
if
(
addrlen
<
sizeof
(
struct
sockaddr_in
))
return
-
EINVAL
;
return
smack_netlabel_send
(
sock
->
sk
,
(
struct
sockaddr_in
*
)
sap
);
switch
(
sock
->
sk
->
sk_family
)
{
case
PF_INET
:
if
(
addrlen
<
sizeof
(
struct
sockaddr_in
))
return
-
EINVAL
;
rc
=
smack_netlabel_send
(
sock
->
sk
,
(
struct
sockaddr_in
*
)
sap
);
break
;
case
PF_INET6
:
if
(
addrlen
<
sizeof
(
struct
sockaddr_in6
))
return
-
EINVAL
;
rc
=
smk_ipv6_port_check
(
sock
->
sk
,
sap
,
SMK_CONNECTING
);
break
;
}
return
rc
;
}
/**
...
...
@@ -2011,7 +2235,9 @@ static int smack_flags_to_may(int flags)
*/
static
int
smack_msg_msg_alloc_security
(
struct
msg_msg
*
msg
)
{
msg
->
security
=
smk_of_current
();
struct
smack_known
*
skp
=
smk_of_current
();
msg
->
security
=
skp
->
smk_known
;
return
0
;
}
...
...
@@ -2046,8 +2272,9 @@ static char *smack_of_shm(struct shmid_kernel *shp)
static
int
smack_shm_alloc_security
(
struct
shmid_kernel
*
shp
)
{
struct
kern_ipc_perm
*
isp
=
&
shp
->
shm_perm
;
struct
smack_known
*
skp
=
smk_of_current
();
isp
->
security
=
s
mk_of_current
()
;
isp
->
security
=
s
kp
->
smk_known
;
return
0
;
}
...
...
@@ -2169,8 +2396,9 @@ static char *smack_of_sem(struct sem_array *sma)
static
int
smack_sem_alloc_security
(
struct
sem_array
*
sma
)
{
struct
kern_ipc_perm
*
isp
=
&
sma
->
sem_perm
;
struct
smack_known
*
skp
=
smk_of_current
();
isp
->
security
=
s
mk_of_current
()
;
isp
->
security
=
s
kp
->
smk_known
;
return
0
;
}
...
...
@@ -2287,8 +2515,9 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
static
int
smack_msg_queue_alloc_security
(
struct
msg_queue
*
msq
)
{
struct
kern_ipc_perm
*
kisp
=
&
msq
->
q_perm
;
struct
smack_known
*
skp
=
smk_of_current
();
kisp
->
security
=
s
mk_of_current
()
;
kisp
->
security
=
s
kp
->
smk_known
;
return
0
;
}
...
...
@@ -2460,8 +2689,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
struct
super_block
*
sbp
;
struct
superblock_smack
*
sbsp
;
struct
inode_smack
*
isp
;
char
*
csp
=
smk_of_current
()
;
char
*
fetched
;
struct
smack_known
*
skp
;
struct
smack_known
*
ckp
=
smk_of_current
()
;
char
*
final
;
char
trattr
[
TRANS_TRUE_SIZE
];
int
transflag
=
0
;
...
...
@@ -2528,7 +2757,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Programs that change smack have to treat the
* pty with respect.
*/
final
=
c
sp
;
final
=
c
kp
->
smk_known
;
break
;
case
SOCKFS_MAGIC
:
/*
...
...
@@ -2583,9 +2812,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Get the dentry for xattr.
*/
dp
=
dget
(
opt_dentry
);
fetched
=
smk_fetch
(
XATTR_NAME_SMACK
,
inode
,
dp
);
if
(
fetched
!=
NULL
)
final
=
fetched
;
skp
=
smk_fetch
(
XATTR_NAME_SMACK
,
inode
,
dp
);
if
(
skp
!=
NULL
)
final
=
skp
->
smk_known
;
/*
* Transmuting directory
...
...
@@ -2625,7 +2854,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
}
if
(
final
==
NULL
)
isp
->
smk_inode
=
c
sp
;
isp
->
smk_inode
=
c
kp
->
smk_known
;
else
isp
->
smk_inode
=
final
;
...
...
@@ -2648,13 +2877,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
static
int
smack_getprocattr
(
struct
task_struct
*
p
,
char
*
name
,
char
**
value
)
{
struct
smack_known
*
skp
=
smk_of_task
(
task_security
(
p
));
char
*
cp
;
int
slen
;
if
(
strcmp
(
name
,
"current"
)
!=
0
)
return
-
EINVAL
;
cp
=
kstrdup
(
s
mk_of_task
(
task_security
(
p
))
,
GFP_KERNEL
);
cp
=
kstrdup
(
s
kp
->
smk_known
,
GFP_KERNEL
);
if
(
cp
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -2680,7 +2910,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
{
struct
task_smack
*
tsp
;
struct
cred
*
new
;
char
*
newsmack
;
struct
smack_known
*
skp
;
/*
* Changing another process' Smack value is too dangerous
...
...
@@ -2698,14 +2928,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if
(
strcmp
(
name
,
"current"
)
!=
0
)
return
-
EINVAL
;
newsmack
=
smk_import
(
value
,
size
);
if
(
newsmack
==
NULL
)
skp
=
smk_import_entry
(
value
,
size
);
if
(
skp
==
NULL
)
return
-
EINVAL
;
/*
* No process is ever allowed the web ("@") label.
*/
if
(
newsmack
==
smack_known_web
.
smk_known
)
if
(
skp
==
&
smack_known_web
)
return
-
EPERM
;
new
=
prepare_creds
();
...
...
@@ -2713,7 +2943,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
return
-
ENOMEM
;
tsp
=
new
->
security
;
tsp
->
smk_task
=
newsmack
;
tsp
->
smk_task
=
skp
;
commit_creds
(
new
);
return
size
;
...
...
@@ -2731,6 +2961,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
static
int
smack_unix_stream_connect
(
struct
sock
*
sock
,
struct
sock
*
other
,
struct
sock
*
newsk
)
{
struct
smack_known
*
skp
;
struct
socket_smack
*
ssp
=
sock
->
sk_security
;
struct
socket_smack
*
osp
=
other
->
sk_security
;
struct
socket_smack
*
nsp
=
newsk
->
sk_security
;
...
...
@@ -2744,15 +2975,17 @@ static int smack_unix_stream_connect(struct sock *sock,
smk_ad_setfield_u_net_sk
(
&
ad
,
other
);
#endif
if
(
!
smack_privileged
(
CAP_MAC_OVERRIDE
))
rc
=
smk_access
(
ssp
->
smk_out
,
osp
->
smk_in
,
MAY_WRITE
,
&
ad
);
if
(
!
smack_privileged
(
CAP_MAC_OVERRIDE
))
{
skp
=
ssp
->
smk_out
;
rc
=
smk_access
(
skp
,
osp
->
smk_in
,
MAY_WRITE
,
&
ad
);
}
/*
* Cross reference the peer labels for SO_PEERSEC.
*/
if
(
rc
==
0
)
{
nsp
->
smk_packet
=
ssp
->
smk_out
;
ssp
->
smk_packet
=
osp
->
smk_out
;
nsp
->
smk_packet
=
ssp
->
smk_out
->
smk_known
;
ssp
->
smk_packet
=
osp
->
smk_out
->
smk_known
;
}
return
rc
;
...
...
@@ -2770,8 +3003,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
{
struct
socket_smack
*
ssp
=
sock
->
sk
->
sk_security
;
struct
socket_smack
*
osp
=
other
->
sk
->
sk_security
;
struct
smack_known
*
skp
;
struct
smk_audit_info
ad
;
int
rc
=
0
;
#ifdef CONFIG_AUDIT
struct
lsm_network_audit
net
;
...
...
@@ -2780,10 +3013,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
smk_ad_setfield_u_net_sk
(
&
ad
,
other
->
sk
);
#endif
if
(
!
smack_privileged
(
CAP_MAC_OVERRIDE
))
r
c
=
smk_access
(
ssp
->
smk_out
,
osp
->
smk_in
,
MAY_WRITE
,
&
ad
)
;
if
(
smack_privileged
(
CAP_MAC_OVERRIDE
))
r
eturn
0
;
return
rc
;
skp
=
ssp
->
smk_out
;
return
smk_access
(
skp
,
osp
->
smk_in
,
MAY_WRITE
,
&
ad
);
}
/**
...
...
@@ -2792,22 +3026,32 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
* @msg: the message
* @size: the size of the message
*
* Return 0 if the current subject can write to the destination
*
host. This is only a question if the destination is a single
*
label hos
t.
* Return 0 if the current subject can write to the destination
host.
*
For IPv4 this is only a question if the destination is a single label host.
*
For IPv6 this is a check against the label of the por
t.
*/
static
int
smack_socket_sendmsg
(
struct
socket
*
sock
,
struct
msghdr
*
msg
,
int
size
)
{
struct
sockaddr_in
*
sip
=
(
struct
sockaddr_in
*
)
msg
->
msg_name
;
struct
sockaddr
*
sap
=
(
struct
sockaddr
*
)
msg
->
msg_name
;
int
rc
=
0
;
/*
* Perfectly reasonable for this to be NULL
*/
if
(
sip
==
NULL
||
sip
->
sin_family
!=
AF_INET
)
if
(
sip
==
NULL
)
return
0
;
return
smack_netlabel_send
(
sock
->
sk
,
sip
);
switch
(
sip
->
sin_family
)
{
case
AF_INET
:
rc
=
smack_netlabel_send
(
sock
->
sk
,
sip
);
break
;
case
AF_INET6
:
rc
=
smk_ipv6_port_check
(
sock
->
sk
,
sap
,
SMK_SENDING
);
break
;
}
return
rc
;
}
/**
...
...
@@ -2815,13 +3059,12 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
* @sap: netlabel secattr
* @ssp: socket security information
*
* Returns a pointer to a Smack label found on the label list.
* Returns a pointer to a Smack label
entry
found on the label list.
*/
static
char
*
smack_from_secattr
(
struct
netlbl_lsm_secattr
*
sap
,
struct
socket_smack
*
ssp
)
static
struct
smack_known
*
smack_from_secattr
(
struct
netlbl_lsm_secattr
*
sap
,
struct
socket_smack
*
ssp
)
{
struct
smack_known
*
kp
;
char
*
sp
;
struct
smack_known
*
skp
;
int
found
=
0
;
if
((
sap
->
flags
&
NETLBL_SECATTR_MLS_LVL
)
!=
0
)
{
...
...
@@ -2836,11 +3079,11 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
* ambient value.
*/
rcu_read_lock
();
list_for_each_entry
(
kp
,
&
smack_known_list
,
list
)
{
if
(
sap
->
attr
.
mls
.
lvl
!=
kp
->
smk_netlabel
.
attr
.
mls
.
lvl
)
list_for_each_entry
(
s
kp
,
&
smack_known_list
,
list
)
{
if
(
sap
->
attr
.
mls
.
lvl
!=
s
kp
->
smk_netlabel
.
attr
.
mls
.
lvl
)
continue
;
if
(
memcmp
(
sap
->
attr
.
mls
.
cat
,
kp
->
smk_netlabel
.
attr
.
mls
.
cat
,
s
kp
->
smk_netlabel
.
attr
.
mls
.
cat
,
SMK_CIPSOLEN
)
!=
0
)
continue
;
found
=
1
;
...
...
@@ -2849,17 +3092,17 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
rcu_read_unlock
();
if
(
found
)
return
kp
->
smk_known
;
return
skp
;
if
(
ssp
!=
NULL
&&
ssp
->
smk_in
==
smack_known_star
.
smk_known
)
return
smack_known_web
.
smk_known
;
return
smack_known_star
.
smk_known
;
return
&
smack_known_web
;
return
&
smack_known_star
;
}
if
((
sap
->
flags
&
NETLBL_SECATTR_SECID
)
!=
0
)
{
/*
* Looks like a fallback, which gives us a secid.
*/
sp
=
smack_from_secid
(
sap
->
attr
.
secid
);
s
k
p
=
smack_from_secid
(
sap
->
attr
.
secid
);
/*
* This has got to be a bug because it is
* impossible to specify a fallback without
...
...
@@ -2867,8 +3110,8 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
* it has a secid, and the only way to get a
* secid is from a fallback.
*/
BUG_ON
(
sp
==
NULL
);
return
sp
;
BUG_ON
(
s
k
p
==
NULL
);
return
s
k
p
;
}
/*
* Without guidance regarding the smack value
...
...
@@ -2878,6 +3121,54 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
return
smack_net_ambient
;
}
static
int
smk_skb_to_addr_ipv6
(
struct
sk_buff
*
skb
,
struct
sockaddr
*
sap
)
{
struct
sockaddr_in6
*
sip
=
(
struct
sockaddr_in6
*
)
sap
;
u8
nexthdr
;
int
offset
;
int
proto
=
-
EINVAL
;
struct
ipv6hdr
_ipv6h
;
struct
ipv6hdr
*
ip6
;
__be16
frag_off
;
struct
tcphdr
_tcph
,
*
th
;
struct
udphdr
_udph
,
*
uh
;
struct
dccp_hdr
_dccph
,
*
dh
;
sip
->
sin6_port
=
0
;
offset
=
skb_network_offset
(
skb
);
ip6
=
skb_header_pointer
(
skb
,
offset
,
sizeof
(
_ipv6h
),
&
_ipv6h
);
if
(
ip6
==
NULL
)
return
-
EINVAL
;
sip
->
sin6_addr
=
ip6
->
saddr
;
nexthdr
=
ip6
->
nexthdr
;
offset
+=
sizeof
(
_ipv6h
);
offset
=
ipv6_skip_exthdr
(
skb
,
offset
,
&
nexthdr
,
&
frag_off
);
if
(
offset
<
0
)
return
-
EINVAL
;
proto
=
nexthdr
;
switch
(
proto
)
{
case
IPPROTO_TCP
:
th
=
skb_header_pointer
(
skb
,
offset
,
sizeof
(
_tcph
),
&
_tcph
);
if
(
th
!=
NULL
)
sip
->
sin6_port
=
th
->
source
;
break
;
case
IPPROTO_UDP
:
uh
=
skb_header_pointer
(
skb
,
offset
,
sizeof
(
_udph
),
&
_udph
);
if
(
uh
!=
NULL
)
sip
->
sin6_port
=
uh
->
source
;
break
;
case
IPPROTO_DCCP
:
dh
=
skb_header_pointer
(
skb
,
offset
,
sizeof
(
_dccph
),
&
_dccph
);
if
(
dh
!=
NULL
)
sip
->
sin6_port
=
dh
->
dccph_sport
;
break
;
}
return
proto
;
}
/**
* smack_socket_sock_rcv_skb - Smack packet delivery access check
* @sk: socket
...
...
@@ -2889,43 +3180,52 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
struct
netlbl_lsm_secattr
secattr
;
struct
socket_smack
*
ssp
=
sk
->
sk_security
;
char
*
csp
;
int
rc
;
struct
smack_known
*
skp
;
struct
sockaddr
sadd
;
int
rc
=
0
;
struct
smk_audit_info
ad
;
#ifdef CONFIG_AUDIT
struct
lsm_network_audit
net
;
#endif
if
(
sk
->
sk_family
!=
PF_INET
&&
sk
->
sk_family
!=
PF_INET6
)
return
0
;
/*
* Translate what netlabel gave us.
*/
netlbl_secattr_init
(
&
secattr
);
switch
(
sk
->
sk_family
)
{
case
PF_INET
:
/*
* Translate what netlabel gave us.
*/
netlbl_secattr_init
(
&
secattr
);
rc
=
netlbl_skbuff_getattr
(
skb
,
sk
->
sk_family
,
&
secattr
);
if
(
rc
==
0
)
cs
p
=
smack_from_secattr
(
&
secattr
,
ssp
);
else
cs
p
=
smack_net_ambient
;
rc
=
netlbl_skbuff_getattr
(
skb
,
sk
->
sk_family
,
&
secattr
);
if
(
rc
==
0
)
sk
p
=
smack_from_secattr
(
&
secattr
,
ssp
);
else
sk
p
=
smack_net_ambient
;
netlbl_secattr_destroy
(
&
secattr
);
netlbl_secattr_destroy
(
&
secattr
);
#ifdef CONFIG_AUDIT
smk_ad_init_net
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_NET
,
&
net
);
ad
.
a
.
u
.
net
->
family
=
sk
->
sk_family
;
ad
.
a
.
u
.
net
->
netif
=
skb
->
skb_iif
;
ipv4_skb_to_auditdata
(
skb
,
&
ad
.
a
,
NULL
);
smk_ad_init_net
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_NET
,
&
net
);
ad
.
a
.
u
.
net
->
family
=
sk
->
sk_family
;
ad
.
a
.
u
.
net
->
netif
=
skb
->
skb_iif
;
ipv4_skb_to_auditdata
(
skb
,
&
ad
.
a
,
NULL
);
#endif
/*
* Receiving a packet requires that the other end
* be able to write here. Read access is not required.
* This is the simplist possible security model
* for networking.
*/
rc
=
smk_access
(
csp
,
ssp
->
smk_in
,
MAY_WRITE
,
&
ad
);
if
(
rc
!=
0
)
netlbl_skbuff_err
(
skb
,
rc
,
0
);
/*
* Receiving a packet requires that the other end
* be able to write here. Read access is not required.
* This is the simplist possible security model
* for networking.
*/
rc
=
smk_access
(
skp
,
ssp
->
smk_in
,
MAY_WRITE
,
&
ad
);
if
(
rc
!=
0
)
netlbl_skbuff_err
(
skb
,
rc
,
0
);
break
;
case
PF_INET6
:
rc
=
smk_skb_to_addr_ipv6
(
skb
,
&
sadd
);
if
(
rc
==
IPPROTO_UDP
||
rc
==
IPPROTO_TCP
)
rc
=
smk_ipv6_port_check
(
sk
,
&
sadd
,
SMK_RECEIVING
);
else
rc
=
0
;
break
;
}
return
rc
;
}
...
...
@@ -2979,7 +3279,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
{
struct
netlbl_lsm_secattr
secattr
;
struct
socket_smack
*
ssp
=
NULL
;
char
*
s
p
;
struct
smack_known
*
sk
p
;
int
family
=
PF_UNSPEC
;
u32
s
=
0
;
/* 0 is the invalid secid */
int
rc
;
...
...
@@ -2995,7 +3295,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
if
(
family
==
PF_UNIX
)
{
ssp
=
sock
->
sk
->
sk_security
;
s
=
s
mack_to_secid
(
ssp
->
smk_out
)
;
s
=
s
sp
->
smk_out
->
smk_secid
;
}
else
if
(
family
==
PF_INET
||
family
==
PF_INET6
)
{
/*
* Translate what netlabel gave us.
...
...
@@ -3005,8 +3305,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
netlbl_secattr_init
(
&
secattr
);
rc
=
netlbl_skbuff_getattr
(
skb
,
family
,
&
secattr
);
if
(
rc
==
0
)
{
sp
=
smack_from_secattr
(
&
secattr
,
ssp
);
s
=
s
mack_to_secid
(
sp
)
;
s
k
p
=
smack_from_secattr
(
&
secattr
,
ssp
);
s
=
s
kp
->
smk_secid
;
}
netlbl_secattr_destroy
(
&
secattr
);
}
...
...
@@ -3027,13 +3327,15 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
static
void
smack_sock_graft
(
struct
sock
*
sk
,
struct
socket
*
parent
)
{
struct
socket_smack
*
ssp
;
struct
smack_known
*
skp
=
smk_of_current
();
if
(
sk
==
NULL
||
(
sk
->
sk_family
!=
PF_INET
&&
sk
->
sk_family
!=
PF_INET6
))
return
;
ssp
=
sk
->
sk_security
;
ssp
->
smk_in
=
ssp
->
smk_out
=
smk_of_current
();
ssp
->
smk_in
=
skp
->
smk_known
;
ssp
->
smk_out
=
skp
;
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
}
...
...
@@ -3055,7 +3357,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct
netlbl_lsm_secattr
secattr
;
struct
sockaddr_in
addr
;
struct
iphdr
*
hdr
;
char
*
sp
;
char
*
hsp
;
int
rc
;
struct
smk_audit_info
ad
;
...
...
@@ -3063,16 +3364,24 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct
lsm_network_audit
net
;
#endif
/* handle mapped IPv4 packets arriving via IPv6 sockets */
if
(
family
==
PF_INET6
&&
skb
->
protocol
==
htons
(
ETH_P_IP
))
family
=
PF_INET
;
if
(
family
==
PF_INET6
)
{
/*
* Handle mapped IPv4 packets arriving
* via IPv6 sockets. Don't set up netlabel
* processing on IPv6.
*/
if
(
skb
->
protocol
==
htons
(
ETH_P_IP
))
family
=
PF_INET
;
else
return
0
;
}
netlbl_secattr_init
(
&
secattr
);
rc
=
netlbl_skbuff_getattr
(
skb
,
family
,
&
secattr
);
if
(
rc
==
0
)
sp
=
smack_from_secattr
(
&
secattr
,
ssp
);
s
k
p
=
smack_from_secattr
(
&
secattr
,
ssp
);
else
s
p
=
smack_known_huh
.
smk_known
;
s
kp
=
&
smack_known_huh
;
netlbl_secattr_destroy
(
&
secattr
);
#ifdef CONFIG_AUDIT
...
...
@@ -3085,7 +3394,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Receiving a packet requires that the other end be able to write
* here. Read access is not required.
*/
rc
=
smk_access
(
sp
,
ssp
->
smk_in
,
MAY_WRITE
,
&
ad
);
rc
=
smk_access
(
s
k
p
,
ssp
->
smk_in
,
MAY_WRITE
,
&
ad
);
if
(
rc
!=
0
)
return
rc
;
...
...
@@ -3093,7 +3402,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Save the peer's label in the request_sock so we can later setup
* smk_packet in the child socket so that SO_PEERCRED can report it.
*/
req
->
peer_secid
=
s
mack_to_secid
(
sp
)
;
req
->
peer_secid
=
s
kp
->
smk_secid
;
/*
* We need to decide if we want to label the incoming connection here
...
...
@@ -3106,10 +3415,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
hsp
=
smack_host_label
(
&
addr
);
rcu_read_unlock
();
if
(
hsp
==
NULL
)
{
skp
=
smk_find_entry
(
sp
);
if
(
hsp
==
NULL
)
rc
=
netlbl_req_setattr
(
req
,
&
skp
->
smk_netlabel
);
}
else
else
netlbl_req_delattr
(
req
);
return
rc
;
...
...
@@ -3126,10 +3434,12 @@ static void smack_inet_csk_clone(struct sock *sk,
const
struct
request_sock
*
req
)
{
struct
socket_smack
*
ssp
=
sk
->
sk_security
;
struct
smack_known
*
skp
;
if
(
req
->
peer_secid
!=
0
)
ssp
->
smk_packet
=
smack_from_secid
(
req
->
peer_secid
);
else
if
(
req
->
peer_secid
!=
0
)
{
skp
=
smack_from_secid
(
req
->
peer_secid
);
ssp
->
smk_packet
=
skp
->
smk_known
;
}
else
ssp
->
smk_packet
=
NULL
;
}
...
...
@@ -3155,7 +3465,9 @@ static void smack_inet_csk_clone(struct sock *sk,
static
int
smack_key_alloc
(
struct
key
*
key
,
const
struct
cred
*
cred
,
unsigned
long
flags
)
{
key
->
security
=
smk_of_task
(
cred
->
security
);
struct
smack_known
*
skp
=
smk_of_task
(
cred
->
security
);
key
->
security
=
skp
->
smk_known
;
return
0
;
}
...
...
@@ -3184,7 +3496,7 @@ static int smack_key_permission(key_ref_t key_ref,
{
struct
key
*
keyp
;
struct
smk_audit_info
ad
;
char
*
ts
p
=
smk_of_task
(
cred
->
security
);
struct
smack_known
*
tk
p
=
smk_of_task
(
cred
->
security
);
keyp
=
key_ref_to_ptr
(
key_ref
);
if
(
keyp
==
NULL
)
...
...
@@ -3198,15 +3510,14 @@ static int smack_key_permission(key_ref_t key_ref,
/*
* This should not occur
*/
if
(
t
s
p
==
NULL
)
if
(
t
k
p
==
NULL
)
return
-
EACCES
;
#ifdef CONFIG_AUDIT
smk_ad_init
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_KEY
);
ad
.
a
.
u
.
key_struct
.
key
=
keyp
->
serial
;
ad
.
a
.
u
.
key_struct
.
key_desc
=
keyp
->
description
;
#endif
return
smk_access
(
tsp
,
keyp
->
security
,
MAY_READWRITE
,
&
ad
);
return
smk_access
(
tkp
,
keyp
->
security
,
MAY_READWRITE
,
&
ad
);
}
#endif
/* CONFIG_KEYS */
...
...
@@ -3288,7 +3599,7 @@ static int smack_audit_rule_known(struct audit_krule *krule)
static
int
smack_audit_rule_match
(
u32
secid
,
u32
field
,
u32
op
,
void
*
vrule
,
struct
audit_context
*
actx
)
{
char
*
smack
;
struct
smack_known
*
skp
;
char
*
rule
=
vrule
;
if
(
!
rule
)
{
...
...
@@ -3300,7 +3611,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
if
(
field
!=
AUDIT_SUBJ_USER
&&
field
!=
AUDIT_OBJ_USER
)
return
0
;
s
mack
=
smack_from_secid
(
secid
);
s
kp
=
smack_from_secid
(
secid
);
/*
* No need to do string comparisons. If a match occurs,
...
...
@@ -3308,9 +3619,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
* label.
*/
if
(
op
==
Audit_equal
)
return
(
rule
==
s
mack
);
return
(
rule
==
s
kp
->
smk_known
);
if
(
op
==
Audit_not_equal
)
return
(
rule
!=
s
mack
);
return
(
rule
!=
s
kp
->
smk_known
);
return
0
;
}
...
...
@@ -3338,11 +3649,11 @@ static void smack_audit_rule_free(void *vrule)
*/
static
int
smack_secid_to_secctx
(
u32
secid
,
char
**
secdata
,
u32
*
seclen
)
{
char
*
s
p
=
smack_from_secid
(
secid
);
struct
smack_known
*
sk
p
=
smack_from_secid
(
secid
);
if
(
secdata
)
*
secdata
=
s
p
;
*
seclen
=
strlen
(
s
p
);
*
secdata
=
s
kp
->
smk_known
;
*
seclen
=
strlen
(
s
kp
->
smk_known
);
return
0
;
}
...
...
@@ -3498,6 +3809,7 @@ struct security_operations smack_ops = {
.
unix_may_send
=
smack_unix_may_send
,
.
socket_post_create
=
smack_socket_post_create
,
.
socket_bind
=
smack_socket_bind
,
.
socket_connect
=
smack_socket_connect
,
.
socket_sendmsg
=
smack_socket_sendmsg
,
.
socket_sock_rcv_skb
=
smack_socket_sock_rcv_skb
,
...
...
@@ -3577,8 +3889,8 @@ static __init int smack_init(void)
if
(
!
security_module_enable
(
&
smack_ops
))
return
0
;
tsp
=
new_task_smack
(
smack_known_floor
.
smk_known
,
smack_known_floor
.
smk_known
,
GFP_KERNEL
);
tsp
=
new_task_smack
(
&
smack_known_floor
,
&
smack_known_floor
,
GFP_KERNEL
);
if
(
tsp
==
NULL
)
return
-
ENOMEM
;
...
...
security/smack/smackfs.c
View file @
1ca00728
...
...
@@ -66,7 +66,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock);
* If it isn't somehow marked, use this.
* It can be reset via smackfs/ambient
*/
char
*
smack_net_ambient
;
struct
smack_known
*
smack_net_ambient
;
/*
* This is the level in a CIPSO header that indicates a
...
...
@@ -112,7 +112,7 @@ struct smack_master_list {
LIST_HEAD
(
smack_rule_list
);
struct
smack_parsed_rule
{
char
*
smk_subject
;
struct
smack_known
*
smk_subject
;
char
*
smk_object
;
int
smk_access1
;
int
smk_access2
;
...
...
@@ -163,9 +163,11 @@ static inline void smack_catset_bit(unsigned int cat, char *catsetp)
*/
static
void
smk_netlabel_audit_set
(
struct
netlbl_audit
*
nap
)
{
struct
smack_known
*
skp
=
smk_of_current
();
nap
->
loginuid
=
audit_get_loginuid
(
current
);
nap
->
sessionid
=
audit_get_sessionid
(
current
);
nap
->
secid
=
s
mack_to_secid
(
smk_of_current
())
;
nap
->
secid
=
s
kp
->
smk_secid
;
}
/*
...
...
@@ -306,7 +308,7 @@ static int smk_fill_rule(const char *subject, const char *object,
struct
smack_known
*
skp
;
if
(
import
)
{
rule
->
smk_subject
=
smk_import
(
subject
,
len
);
rule
->
smk_subject
=
smk_import
_entry
(
subject
,
len
);
if
(
rule
->
smk_subject
==
NULL
)
return
-
1
;
...
...
@@ -321,7 +323,7 @@ static int smk_fill_rule(const char *subject, const char *object,
kfree
(
cp
);
if
(
skp
==
NULL
)
return
-
1
;
rule
->
smk_subject
=
skp
->
smk_known
;
rule
->
smk_subject
=
skp
;
cp
=
smk_parse_smack
(
object
,
len
);
if
(
cp
==
NULL
)
...
...
@@ -445,7 +447,6 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
struct
list_head
*
rule_list
,
struct
mutex
*
rule_lock
,
int
format
)
{
struct
smack_known
*
skp
;
struct
smack_parsed_rule
*
rule
;
char
*
data
;
int
datalen
;
...
...
@@ -505,12 +506,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
goto
out_free_rule
;
}
if
(
rule_list
==
NULL
)
{
load
=
1
;
skp
=
smk_find_entry
(
rule
->
smk_subject
);
rule_list
=
&
skp
->
smk_rules
;
rule_lock
=
&
skp
->
smk_rules_lock
;
rule_list
=
&
rule
->
smk_subject
->
smk_rules
;
rule_lock
=
&
rule
->
smk_subject
->
smk_rules_lock
;
}
rc
=
smk_set_access
(
rule
,
rule_list
,
rule_lock
,
load
);
...
...
@@ -579,13 +578,14 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
* because you should expect to be able to write
* anything you read back.
*/
if
(
strlen
(
srp
->
smk_subject
)
>=
max
||
strlen
(
srp
->
smk_object
)
>=
max
)
if
(
strlen
(
srp
->
smk_subject
->
smk_known
)
>=
max
||
strlen
(
srp
->
smk_object
)
>=
max
)
return
;
if
(
srp
->
smk_access
==
0
)
return
;
seq_printf
(
s
,
"%s %s"
,
srp
->
smk_subject
,
srp
->
smk_object
);
seq_printf
(
s
,
"%s %s"
,
srp
->
smk_subject
->
smk_known
,
srp
->
smk_object
);
seq_putc
(
s
,
' '
);
...
...
@@ -738,9 +738,9 @@ static void smk_unlbl_ambient(char *oldambient)
__func__
,
__LINE__
,
rc
);
}
if
(
smack_net_ambient
==
NULL
)
smack_net_ambient
=
smack_known_floor
.
smk_known
;
smack_net_ambient
=
&
smack_known_floor
;
rc
=
netlbl_cfg_unlbl_map_add
(
smack_net_ambient
,
PF_INET
,
rc
=
netlbl_cfg_unlbl_map_add
(
smack_net_ambient
->
smk_known
,
PF_INET
,
NULL
,
NULL
,
&
nai
);
if
(
rc
!=
0
)
printk
(
KERN_WARNING
"%s:%d add rc = %d
\n
"
,
...
...
@@ -881,7 +881,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
if
(
format
==
SMK_FIXED24_FMT
)
rule
+=
SMK_LABELLEN
;
else
rule
+=
strlen
(
skp
->
smk_known
);
rule
+=
strlen
(
skp
->
smk_known
)
+
1
;
ret
=
sscanf
(
rule
,
"%d"
,
&
maplevel
);
if
(
ret
!=
1
||
maplevel
>
SMACK_CIPSO_MAXLEVEL
)
...
...
@@ -1535,11 +1535,12 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
*/
mutex_lock
(
&
smack_ambient_lock
);
asize
=
strlen
(
smack_net_ambient
)
+
1
;
asize
=
strlen
(
smack_net_ambient
->
smk_known
)
+
1
;
if
(
cn
>=
asize
)
rc
=
simple_read_from_buffer
(
buf
,
cn
,
ppos
,
smack_net_ambient
,
asize
);
smack_net_ambient
->
smk_known
,
asize
);
else
rc
=
-
EINVAL
;
...
...
@@ -1560,8 +1561,8 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
static
ssize_t
smk_write_ambient
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
smack_known
*
skp
;
char
*
oldambient
;
char
*
smack
=
NULL
;
char
*
data
;
int
rc
=
count
;
...
...
@@ -1577,16 +1578,16 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
goto
out
;
}
s
mack
=
smk_import
(
data
,
count
);
if
(
s
mack
==
NULL
)
{
s
kp
=
smk_import_entry
(
data
,
count
);
if
(
s
kp
==
NULL
)
{
rc
=
-
EINVAL
;
goto
out
;
}
mutex_lock
(
&
smack_ambient_lock
);
oldambient
=
smack_net_ambient
;
smack_net_ambient
=
s
mack
;
oldambient
=
smack_net_ambient
->
smk_known
;
smack_net_ambient
=
s
kp
;
smk_unlbl_ambient
(
oldambient
);
mutex_unlock
(
&
smack_ambient_lock
);
...
...
@@ -1645,7 +1646,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t
count
,
loff_t
*
ppos
)
{
char
*
data
;
char
*
s
p
=
smk_of_task
(
current
->
cred
->
security
);
struct
smack_known
*
sk
p
=
smk_of_task
(
current
->
cred
->
security
);
int
rc
=
count
;
if
(
!
smack_privileged
(
CAP_MAC_ADMIN
))
...
...
@@ -1656,7 +1657,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
* explicitly for clarity. The smk_access() implementation
* would use smk_access(smack_onlycap, MAY_WRITE)
*/
if
(
smack_onlycap
!=
NULL
&&
smack_onlycap
!=
s
p
)
if
(
smack_onlycap
!=
NULL
&&
smack_onlycap
!=
s
kp
->
smk_known
)
return
-
EPERM
;
data
=
kzalloc
(
count
,
GFP_KERNEL
);
...
...
@@ -1866,8 +1867,8 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
if
(
res
)
return
-
EINVAL
;
res
=
smk_access
(
rule
.
smk_subject
,
rule
.
smk_object
,
rule
.
smk_access1
,
NULL
);
res
=
smk_access
(
rule
.
smk_subject
,
rule
.
smk_object
,
rule
.
smk_access1
,
NULL
);
data
[
0
]
=
res
==
0
?
'1'
:
'0'
;
data
[
1
]
=
'\0'
;
...
...
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