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
5ab16579
Commit
5ab16579
authored
Aug 11, 2015
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'smack-for-4.3' of
https://github.com/cschaufler/smack-next
into next
parents
459c15e5
41a2d575
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
833 additions
and
209 deletions
+833
-209
Documentation/security/Smack.txt
Documentation/security/Smack.txt
+26
-1
security/smack/smack.h
security/smack/smack.h
+57
-9
security/smack/smack_access.c
security/smack/smack_access.c
+6
-0
security/smack/smack_lsm.c
security/smack/smack_lsm.c
+390
-117
security/smack/smackfs.c
security/smack/smackfs.c
+354
-82
No files found.
Documentation/security/Smack.txt
View file @
5ab16579
...
...
@@ -28,6 +28,10 @@ Smack kernels use the CIPSO IP option. Some network
configurations are intolerant of IP options and can impede
access to systems that use them as Smack does.
Smack is used in the Tizen operating system. Please
go to http://wiki.tizen.org for information about how
Smack is used in Tizen.
The current git repository for Smack user space is:
git://github.com/smack-team/smack.git
...
...
@@ -108,6 +112,8 @@ in the smackfs filesystem. This pseudo-filesystem is mounted
on /sys/fs/smackfs.
access
Provided for backward compatibility. The access2 interface
is preferred and should be used instead.
This interface reports whether a subject with the specified
Smack label has a particular access to an object with a
specified Smack label. Write a fixed format access rule to
...
...
@@ -136,6 +142,8 @@ change-rule
those in the fourth string. If there is no such rule it will be
created using the access specified in the third and the fourth strings.
cipso
Provided for backward compatibility. The cipso2 interface
is preferred and should be used instead.
This interface allows a specific CIPSO header to be assigned
to a Smack label. The format accepted on write is:
"%24s%4d%4d"["%4d"]...
...
...
@@ -157,7 +165,19 @@ direct
doi
This contains the CIPSO domain of interpretation used in
network packets.
ipv6host
This interface allows specific IPv6 internet addresses to be
treated as single label hosts. Packets are sent to single
label hosts only from processes that have Smack write access
to the host label. All packets received from single label hosts
are given the specified label. The format accepted on write is:
"%h:%h:%h:%h:%h:%h:%h:%h label" or
"%h:%h:%h:%h:%h:%h:%h:%h/%d label".
The "::" address shortcut is not supported.
If label is "-DELETE" a matched entry will be deleted.
load
Provided for backward compatibility. The load2 interface
is preferred and should be used instead.
This interface allows access control rules in addition to
the system defined rules to be specified. The format accepted
on write is:
...
...
@@ -181,6 +201,8 @@ load2
permissions that are not allowed. The string "r-x--" would
specify read and execute access.
load-self
Provided for backward compatibility. The load-self2 interface
is preferred and should be used instead.
This interface allows process specific access rules to be
defined. These rules are only consulted if access would
otherwise be permitted, and are intended to provide additional
...
...
@@ -205,6 +227,8 @@ netlabel
received from single label hosts are given the specified
label. The format accepted on write is:
"%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label".
If the label specified is "-CIPSO" the address is treated
as a host that supports CIPSO headers.
onlycap
This contains labels processes must have for CAP_MAC_ADMIN
and CAP_MAC_OVERRIDE to be effective. If this file is empty
...
...
@@ -232,7 +256,8 @@ unconfined
is dangerous and can ruin the proper labeling of your system.
It should never be used in production.
You can add access rules in /etc/smack/accesses. They take the form:
If you are using the smackload utility
you can add access rules in /etc/smack/accesses. They take the form:
subjectlabel objectlabel access
...
...
security/smack/smack.h
View file @
5ab16579
...
...
@@ -17,11 +17,26 @@
#include <linux/spinlock.h>
#include <linux/lsm_hooks.h>
#include <linux/in.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <linux/in6.h>
#endif
/* CONFIG_IPV6 */
#include <net/netlabel.h>
#include <linux/list.h>
#include <linux/rculist.h>
#include <linux/lsm_audit.h>
/*
* Use IPv6 port labeling if IPv6 is enabled and secmarks
* are not being used.
*/
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#define SMACK_IPV6_PORT_LABELING 1
#endif
#if IS_ENABLED(CONFIG_IPV6) && defined(CONFIG_SECURITY_SMACK_NETFILTER)
#define SMACK_IPV6_SECMARK_LABELING 1
#endif
/*
* Smack labels were limited to 23 characters for a long time.
*/
...
...
@@ -118,15 +133,30 @@ struct smack_rule {
};
/*
* An entry in the table identifying hosts.
* An entry in the table identifying
IPv4
hosts.
*/
struct
smk_net
lbl
addr
{
struct
smk_net
4
addr
{
struct
list_head
list
;
struct
sockaddr_in
smk_host
;
/* network address */
struct
in_addr
smk_host
;
/* network address */
struct
in_addr
smk_mask
;
/* network mask */
int
smk_masks
;
/* mask size */
struct
smack_known
*
smk_label
;
/* label */
};
#if IS_ENABLED(CONFIG_IPV6)
/*
* An entry in the table identifying IPv6 hosts.
*/
struct
smk_net6addr
{
struct
list_head
list
;
struct
in6_addr
smk_host
;
/* network address */
struct
in6_addr
smk_mask
;
/* network mask */
int
smk_masks
;
/* mask size */
struct
smack_known
*
smk_label
;
/* label */
};
#endif
/* CONFIG_IPV6 */
#ifdef SMACK_IPV6_PORT_LABELING
/*
* An entry in the table identifying ports.
*/
...
...
@@ -137,12 +167,31 @@ struct smk_port_label {
struct
smack_known
*
smk_in
;
/* inbound label */
struct
smack_known
*
smk_out
;
/* outgoing label */
};
#endif
/* SMACK_IPV6_PORT_LABELING */
struct
smack_onlycap
{
struct
list_head
list
;
struct
smack_known
*
smk_label
;
};
/* Super block security struct flags for mount options */
#define FSDEFAULT_MNT 0x01
#define FSFLOOR_MNT 0x02
#define FSHAT_MNT 0x04
#define FSROOT_MNT 0x08
#define FSTRANS_MNT 0x10
#define NUM_SMK_MNT_OPTS 5
enum
{
Opt_error
=
-
1
,
Opt_fsdefault
=
1
,
Opt_fsfloor
=
2
,
Opt_fshat
=
3
,
Opt_fsroot
=
4
,
Opt_fstransmute
=
5
,
};
/*
* Mount options
*/
...
...
@@ -152,6 +201,7 @@ struct smack_onlycap {
#define SMK_FSROOT "smackfsroot="
#define SMK_FSTRANS "smackfstransmute="
#define SMACK_DELETE_OPTION "-DELETE"
#define SMACK_CIPSO_OPTION "-CIPSO"
/*
...
...
@@ -234,10 +284,6 @@ struct smk_audit_info {
struct
smack_audit_data
sad
;
#endif
};
/*
* These functions are in smack_lsm.c
*/
struct
inode_smack
*
new_inode_smack
(
struct
smack_known
*
);
/*
* These functions are in smack_access.c
...
...
@@ -267,7 +313,6 @@ extern struct smack_known *smack_syslog_label;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
extern
struct
smack_known
*
smack_unconfined
;
#endif
extern
struct
smack_known
smack_cipso_option
;
extern
int
smack_ptrace_rule
;
extern
struct
smack_known
smack_known_floor
;
...
...
@@ -279,7 +324,10 @@ extern struct smack_known smack_known_web;
extern
struct
mutex
smack_known_lock
;
extern
struct
list_head
smack_known_list
;
extern
struct
list_head
smk_netlbladdr_list
;
extern
struct
list_head
smk_net4addr_list
;
#if IS_ENABLED(CONFIG_IPV6)
extern
struct
list_head
smk_net6addr_list
;
#endif
/* CONFIG_IPV6 */
extern
struct
mutex
smack_onlycap_lock
;
extern
struct
list_head
smack_onlycap_list
;
...
...
security/smack/smack_access.c
View file @
5ab16579
...
...
@@ -639,6 +639,12 @@ int smack_privileged(int cap)
struct
smack_known
*
skp
=
smk_of_current
();
struct
smack_onlycap
*
sop
;
/*
* All kernel tasks are privileged
*/
if
(
unlikely
(
current
->
flags
&
PF_KTHREAD
))
return
1
;
if
(
!
capable
(
cap
))
return
0
;
...
...
security/smack/smack_lsm.c
View file @
5ab16579
...
...
@@ -41,6 +41,7 @@
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/binfmts.h>
#include <linux/parser.h>
#include "smack.h"
#define TRANS_TRUE "TRUE"
...
...
@@ -50,9 +51,9 @@
#define SMK_RECEIVING 1
#define SMK_SENDING 2
#if
IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#if
def SMACK_IPV6_PORT_LABELING
LIST_HEAD
(
smk_ipv6_port_list
);
#endif
/* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
#endif
static
struct
kmem_cache
*
smack_inode_cache
;
int
smack_enabled
;
...
...
@@ -64,6 +65,15 @@ static char *smk_bu_mess[] = {
"Unconfined Object"
,
/* SMACK_UNCONFINED_OBJECT */
};
static
const
match_table_t
tokens
=
{
{
Opt_fsdefault
,
SMK_FSDEFAULT
"%s"
},
{
Opt_fsfloor
,
SMK_FSFLOOR
"%s"
},
{
Opt_fshat
,
SMK_FSHAT
"%s"
},
{
Opt_fsroot
,
SMK_FSROOT
"%s"
},
{
Opt_fstransmute
,
SMK_FSTRANS
"%s"
},
{
Opt_error
,
NULL
},
};
static
void
smk_bu_mode
(
int
mode
,
char
*
s
)
{
int
i
=
0
;
...
...
@@ -281,7 +291,7 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
*
* Returns the new blob or NULL if there's no memory available
*/
struct
inode_smack
*
new_inode_smack
(
struct
smack_known
*
skp
)
st
atic
st
ruct
inode_smack
*
new_inode_smack
(
struct
smack_known
*
skp
)
{
struct
inode_smack
*
isp
;
...
...
@@ -577,76 +587,193 @@ static int smack_sb_copy_data(char *orig, char *smackopts)
}
/**
* smack_sb_kern_mount - Smack specific mount processing
* smack_parse_opts_str - parse Smack specific mount options
* @options: mount options string
* @opts: where to store converted mount opts
*
* Returns 0 on success or -ENOMEM on error.
*
* converts Smack specific mount options to generic security option format
*/
static
int
smack_parse_opts_str
(
char
*
options
,
struct
security_mnt_opts
*
opts
)
{
char
*
p
;
char
*
fsdefault
=
NULL
,
*
fsfloor
=
NULL
;
char
*
fshat
=
NULL
,
*
fsroot
=
NULL
,
*
fstransmute
=
NULL
;
int
rc
=
-
ENOMEM
,
num_mnt_opts
=
0
;
opts
->
num_mnt_opts
=
0
;
if
(
!
options
)
return
0
;
while
((
p
=
strsep
(
&
options
,
","
))
!=
NULL
)
{
int
token
;
substring_t
args
[
MAX_OPT_ARGS
];
if
(
!*
p
)
continue
;
token
=
match_token
(
p
,
tokens
,
args
);
switch
(
token
)
{
case
Opt_fsdefault
:
if
(
fsdefault
)
goto
out_opt_err
;
fsdefault
=
match_strdup
(
&
args
[
0
]);
if
(
!
fsdefault
)
goto
out_err
;
break
;
case
Opt_fsfloor
:
if
(
fsfloor
)
goto
out_opt_err
;
fsfloor
=
match_strdup
(
&
args
[
0
]);
if
(
!
fsfloor
)
goto
out_err
;
break
;
case
Opt_fshat
:
if
(
fshat
)
goto
out_opt_err
;
fshat
=
match_strdup
(
&
args
[
0
]);
if
(
!
fshat
)
goto
out_err
;
break
;
case
Opt_fsroot
:
if
(
fsroot
)
goto
out_opt_err
;
fsroot
=
match_strdup
(
&
args
[
0
]);
if
(
!
fsroot
)
goto
out_err
;
break
;
case
Opt_fstransmute
:
if
(
fstransmute
)
goto
out_opt_err
;
fstransmute
=
match_strdup
(
&
args
[
0
]);
if
(
!
fstransmute
)
goto
out_err
;
break
;
default:
rc
=
-
EINVAL
;
pr_warn
(
"Smack: unknown mount option
\n
"
);
goto
out_err
;
}
}
opts
->
mnt_opts
=
kcalloc
(
NUM_SMK_MNT_OPTS
,
sizeof
(
char
*
),
GFP_ATOMIC
);
if
(
!
opts
->
mnt_opts
)
goto
out_err
;
opts
->
mnt_opts_flags
=
kcalloc
(
NUM_SMK_MNT_OPTS
,
sizeof
(
int
),
GFP_ATOMIC
);
if
(
!
opts
->
mnt_opts_flags
)
{
kfree
(
opts
->
mnt_opts
);
goto
out_err
;
}
if
(
fsdefault
)
{
opts
->
mnt_opts
[
num_mnt_opts
]
=
fsdefault
;
opts
->
mnt_opts_flags
[
num_mnt_opts
++
]
=
FSDEFAULT_MNT
;
}
if
(
fsfloor
)
{
opts
->
mnt_opts
[
num_mnt_opts
]
=
fsfloor
;
opts
->
mnt_opts_flags
[
num_mnt_opts
++
]
=
FSFLOOR_MNT
;
}
if
(
fshat
)
{
opts
->
mnt_opts
[
num_mnt_opts
]
=
fshat
;
opts
->
mnt_opts_flags
[
num_mnt_opts
++
]
=
FSHAT_MNT
;
}
if
(
fsroot
)
{
opts
->
mnt_opts
[
num_mnt_opts
]
=
fsroot
;
opts
->
mnt_opts_flags
[
num_mnt_opts
++
]
=
FSROOT_MNT
;
}
if
(
fstransmute
)
{
opts
->
mnt_opts
[
num_mnt_opts
]
=
fstransmute
;
opts
->
mnt_opts_flags
[
num_mnt_opts
++
]
=
FSTRANS_MNT
;
}
opts
->
num_mnt_opts
=
num_mnt_opts
;
return
0
;
out_opt_err:
rc
=
-
EINVAL
;
pr_warn
(
"Smack: duplicate mount options
\n
"
);
out_err:
kfree
(
fsdefault
);
kfree
(
fsfloor
);
kfree
(
fshat
);
kfree
(
fsroot
);
kfree
(
fstransmute
);
return
rc
;
}
/**
* smack_set_mnt_opts - set Smack specific mount options
* @sb: the file system superblock
* @flags: the mount flags
* @data: the smack mount options
* @opts: Smack mount options
* @kern_flags: mount option from kernel space or user space
* @set_kern_flags: where to store converted mount opts
*
* Returns 0 on success, an error code on failure
*
* Allow filesystems with binary mount data to explicitly set Smack mount
* labels.
*/
static
int
smack_sb_kern_mount
(
struct
super_block
*
sb
,
int
flags
,
void
*
data
)
static
int
smack_set_mnt_opts
(
struct
super_block
*
sb
,
struct
security_mnt_opts
*
opts
,
unsigned
long
kern_flags
,
unsigned
long
*
set_kern_flags
)
{
struct
dentry
*
root
=
sb
->
s_root
;
struct
inode
*
inode
=
d_backing_inode
(
root
);
struct
superblock_smack
*
sp
=
sb
->
s_security
;
struct
inode_smack
*
isp
;
struct
smack_known
*
skp
;
char
*
op
;
char
*
commap
;
int
i
;
int
num_opts
=
opts
->
num_mnt_opts
;
int
transmute
=
0
;
int
specified
=
0
;
if
(
sp
->
smk_initialized
)
return
0
;
sp
->
smk_initialized
=
1
;
for
(
op
=
data
;
op
!=
NULL
;
op
=
commap
)
{
commap
=
strchr
(
op
,
','
);
if
(
commap
!=
NULL
)
*
commap
++
=
'\0'
;
if
(
strncmp
(
op
,
SMK_FSHAT
,
strlen
(
SMK_FSHAT
))
==
0
)
{
op
+=
strlen
(
SMK_FSHAT
);
skp
=
smk_import_entry
(
op
,
0
);
for
(
i
=
0
;
i
<
num_opts
;
i
++
)
{
switch
(
opts
->
mnt_opts_flags
[
i
])
{
case
FSDEFAULT_MNT
:
skp
=
smk_import_entry
(
opts
->
mnt_opts
[
i
],
0
);
if
(
IS_ERR
(
skp
))
return
PTR_ERR
(
skp
);
sp
->
smk_hat
=
skp
;
specified
=
1
;
}
else
if
(
strncmp
(
op
,
SMK_FSFLOOR
,
strlen
(
SMK_FSFLOOR
))
==
0
)
{
op
+=
strlen
(
SMK_FSFLOOR
);
skp
=
smk_import_entry
(
op
,
0
);
sp
->
smk_default
=
skp
;
break
;
case
FSFLOOR_MNT
:
skp
=
smk_import_entry
(
opts
->
mnt_opts
[
i
],
0
);
if
(
IS_ERR
(
skp
))
return
PTR_ERR
(
skp
);
sp
->
smk_floor
=
skp
;
specified
=
1
;
}
else
if
(
strncmp
(
op
,
SMK_FSDEFAULT
,
strlen
(
SMK_FSDEFAULT
))
==
0
)
{
op
+=
strlen
(
SMK_FSDEFAULT
);
skp
=
smk_import_entry
(
op
,
0
);
break
;
case
FSHAT_MNT
:
skp
=
smk_import_entry
(
opts
->
mnt_opts
[
i
],
0
);
if
(
IS_ERR
(
skp
))
return
PTR_ERR
(
skp
);
sp
->
smk_default
=
skp
;
specified
=
1
;
}
else
if
(
strncmp
(
op
,
SMK_FSROOT
,
strlen
(
SMK_FSROOT
))
==
0
)
{
op
+=
strlen
(
SMK_FSROOT
);
skp
=
smk_import_entry
(
op
,
0
);
sp
->
smk_hat
=
skp
;
break
;
case
FSROOT_MNT
:
skp
=
smk_import_entry
(
opts
->
mnt_opts
[
i
],
0
);
if
(
IS_ERR
(
skp
))
return
PTR_ERR
(
skp
);
sp
->
smk_root
=
skp
;
specified
=
1
;
}
else
if
(
strncmp
(
op
,
SMK_FSTRANS
,
strlen
(
SMK_FSTRANS
))
==
0
)
{
op
+=
strlen
(
SMK_FSTRANS
);
skp
=
smk_import_entry
(
op
,
0
);
break
;
case
FSTRANS_MNT
:
skp
=
smk_import_entry
(
opts
->
mnt_opts
[
i
],
0
);
if
(
IS_ERR
(
skp
))
return
PTR_ERR
(
skp
);
sp
->
smk_root
=
skp
;
transmute
=
1
;
specified
=
1
;
break
;
default:
break
;
}
}
...
...
@@ -654,7 +781,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
/*
* Unprivileged mounts don't get to specify Smack values.
*/
if
(
specified
)
if
(
num_opts
)
return
-
EPERM
;
/*
* Unprivileged mounts get root and default from the caller.
...
...
@@ -663,6 +790,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
sp
->
smk_root
=
skp
;
sp
->
smk_default
=
skp
;
}
/*
* Initialize the root inode.
*/
...
...
@@ -681,6 +809,37 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
return
0
;
}
/**
* smack_sb_kern_mount - Smack specific mount processing
* @sb: the file system superblock
* @flags: the mount flags
* @data: the smack mount options
*
* Returns 0 on success, an error code on failure
*/
static
int
smack_sb_kern_mount
(
struct
super_block
*
sb
,
int
flags
,
void
*
data
)
{
int
rc
=
0
;
char
*
options
=
data
;
struct
security_mnt_opts
opts
;
security_init_mnt_opts
(
&
opts
);
if
(
!
options
)
goto
out
;
rc
=
smack_parse_opts_str
(
options
,
&
opts
);
if
(
rc
)
goto
out_err
;
out:
rc
=
smack_set_mnt_opts
(
sb
,
&
opts
,
0
,
NULL
);
out_err:
security_free_mnt_opts
(
&
opts
);
return
rc
;
}
/**
* smack_sb_statfs - Smack check on statfs
* @dentry: identifies the file system in question
...
...
@@ -2113,7 +2272,7 @@ static void smack_sk_free_security(struct sock *sk)
}
/**
* smack_host_label - check host based restrictions
* smack_
ipv4
host_label - check host based restrictions
* @sip: the object end
*
* looks for host based access restrictions
...
...
@@ -2124,30 +2283,96 @@ static void smack_sk_free_security(struct sock *sk)
*
* Returns the label of the far end or NULL if it's not special.
*/
static
struct
smack_known
*
smack_host_label
(
struct
sockaddr_in
*
sip
)
static
struct
smack_known
*
smack_
ipv4
host_label
(
struct
sockaddr_in
*
sip
)
{
struct
smk_net
lbl
addr
*
snp
;
struct
smk_net
4
addr
*
snp
;
struct
in_addr
*
siap
=
&
sip
->
sin_addr
;
if
(
siap
->
s_addr
==
0
)
return
NULL
;
list_for_each_entry_rcu
(
snp
,
&
smk_netlbladdr_list
,
list
)
list_for_each_entry_rcu
(
snp
,
&
smk_net4addr_list
,
list
)
/*
* we break after finding the first match because
* the list is sorted from longest to shortest mask
* so we have found the most specific match
*/
if
(
snp
->
smk_host
.
s_addr
==
(
siap
->
s_addr
&
snp
->
smk_mask
.
s_addr
))
return
snp
->
smk_label
;
return
NULL
;
}
#if IS_ENABLED(CONFIG_IPV6)
/*
* smk_ipv6_localhost - Check for local ipv6 host address
* @sip: the address
*
* Returns boolean true if this is the localhost address
*/
static
bool
smk_ipv6_localhost
(
struct
sockaddr_in6
*
sip
)
{
__be16
*
be16p
=
(
__be16
*
)
&
sip
->
sin6_addr
;
__be32
*
be32p
=
(
__be32
*
)
&
sip
->
sin6_addr
;
if
(
be32p
[
0
]
==
0
&&
be32p
[
1
]
==
0
&&
be32p
[
2
]
==
0
&&
be16p
[
6
]
==
0
&&
ntohs
(
be16p
[
7
])
==
1
)
return
true
;
return
false
;
}
/**
* smack_ipv6host_label - check host based restrictions
* @sip: the object end
*
* looks for host based access restrictions
*
* This version will only be appropriate for really small sets of single label
* hosts. The caller is responsible for ensuring that the RCU read lock is
* taken before calling this function.
*
* Returns the label of the far end or NULL if it's not special.
*/
static
struct
smack_known
*
smack_ipv6host_label
(
struct
sockaddr_in6
*
sip
)
{
struct
smk_net6addr
*
snp
;
struct
in6_addr
*
sap
=
&
sip
->
sin6_addr
;
int
i
;
int
found
=
0
;
/*
* It's local. Don't look for a host label.
*/
if
(
smk_ipv6_localhost
(
sip
))
return
NULL
;
list_for_each_entry_rcu
(
snp
,
&
smk_net6addr_list
,
list
)
{
/*
* we break after finding the first match because
* the list is sorted from longest to shortest mask
* so we have found the most specific match
*/
if
((
&
snp
->
smk_host
.
sin_addr
)
->
s_addr
==
(
siap
->
s_addr
&
(
&
snp
->
smk_mask
)
->
s_addr
))
{
/* we have found the special CIPSO option */
if
(
snp
->
smk_label
==
&
smack_cipso_option
)
return
NULL
;
return
snp
->
smk_label
;
for
(
found
=
1
,
i
=
0
;
i
<
8
;
i
++
)
{
/*
* If the label is NULL the entry has
* been renounced. Ignore it.
*/
if
(
snp
->
smk_label
==
NULL
)
continue
;
if
((
sap
->
s6_addr16
[
i
]
&
snp
->
smk_mask
.
s6_addr16
[
i
])
!=
snp
->
smk_host
.
s6_addr16
[
i
])
{
found
=
0
;
break
;
}
}
if
(
found
)
return
snp
->
smk_label
;
}
return
NULL
;
}
#endif
/* CONFIG_IPV6 */
/**
* smack_netlabel - Set the secattr on a socket
...
...
@@ -2211,7 +2436,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
struct
smk_audit_info
ad
;
rcu_read_lock
();
hkp
=
smack_host_label
(
sap
);
hkp
=
smack_
ipv4
host_label
(
sap
);
if
(
hkp
!=
NULL
)
{
#ifdef CONFIG_AUDIT
struct
lsm_network_audit
net
;
...
...
@@ -2236,7 +2461,42 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
return
smack_netlabel
(
sk
,
sk_lbl
);
}
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#if IS_ENABLED(CONFIG_IPV6)
/**
* smk_ipv6_check - check Smack access
* @subject: subject Smack label
* @object: object Smack label
* @address: address
* @act: the action being taken
*
* Check an IPv6 access
*/
static
int
smk_ipv6_check
(
struct
smack_known
*
subject
,
struct
smack_known
*
object
,
struct
sockaddr_in6
*
address
,
int
act
)
{
#ifdef CONFIG_AUDIT
struct
lsm_network_audit
net
;
#endif
struct
smk_audit_info
ad
;
int
rc
;
#ifdef CONFIG_AUDIT
smk_ad_init_net
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_NET
,
&
net
);
ad
.
a
.
u
.
net
->
family
=
PF_INET6
;
ad
.
a
.
u
.
net
->
dport
=
ntohs
(
address
->
sin6_port
);
if
(
act
==
SMK_RECEIVING
)
ad
.
a
.
u
.
net
->
v6info
.
saddr
=
address
->
sin6_addr
;
else
ad
.
a
.
u
.
net
->
v6info
.
daddr
=
address
->
sin6_addr
;
#endif
rc
=
smk_access
(
subject
,
object
,
MAY_WRITE
,
&
ad
);
rc
=
smk_bu_note
(
"IPv6 check"
,
subject
,
object
,
MAY_WRITE
,
rc
);
return
rc
;
}
#endif
/* CONFIG_IPV6 */
#ifdef SMACK_IPV6_PORT_LABELING
/**
* smk_ipv6_port_label - Smack port access table management
* @sock: socket
...
...
@@ -2320,48 +2580,43 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
static
int
smk_ipv6_port_check
(
struct
sock
*
sk
,
struct
sockaddr_in6
*
address
,
int
act
)
{
__be16
*
bep
;
__be32
*
be32p
;
struct
smk_port_label
*
spp
;
struct
socket_smack
*
ssp
=
sk
->
sk_security
;
struct
smack_known
*
skp
;
unsigned
short
port
=
0
;
struct
smack_known
*
skp
=
NULL
;
unsigned
short
port
;
struct
smack_known
*
object
;
struct
smk_audit_info
ad
;
int
rc
;
#ifdef CONFIG_AUDIT
struct
lsm_network_audit
net
;
#endif
if
(
act
==
SMK_RECEIVING
)
{
skp
=
smack_
net_ambient
;
skp
=
smack_
ipv6host_label
(
address
)
;
object
=
ssp
->
smk_in
;
}
else
{
skp
=
ssp
->
smk_out
;
object
=
smack_
net_ambient
;
object
=
smack_
ipv6host_label
(
address
)
;
}
/*
*
Get the IP address and port from the address
.
*
The other end is a single label host
.
*/
port
=
ntohs
(
address
->
sin6_port
);
bep
=
(
__be16
*
)(
&
address
->
sin6_addr
);
be32p
=
(
__be32
*
)(
&
address
->
sin6_addr
);
if
(
skp
!=
NULL
&&
object
!=
NULL
)
return
smk_ipv6_check
(
skp
,
object
,
address
,
act
);
if
(
skp
==
NULL
)
skp
=
smack_net_ambient
;
if
(
object
==
NULL
)
object
=
smack_net_ambient
;
/*
* It's remote, so port lookup does no good.
*/
if
(
be32p
[
0
]
||
be32p
[
1
]
||
be32p
[
2
]
||
bep
[
6
]
||
ntohs
(
bep
[
7
])
!=
1
)
goto
auditout
;
if
(
!
smk_ipv6_localhost
(
address
)
)
return
smk_ipv6_check
(
skp
,
object
,
address
,
act
)
;
/*
* It's local so the send check has to have passed.
*/
if
(
act
==
SMK_RECEIVING
)
{
skp
=
&
smack_known_web
;
goto
auditout
;
}
if
(
act
==
SMK_RECEIVING
)
return
0
;
port
=
ntohs
(
address
->
sin6_port
);
list_for_each_entry
(
spp
,
&
smk_ipv6_port_list
,
list
)
{
if
(
spp
->
smk_port
!=
port
)
continue
;
...
...
@@ -2371,22 +2626,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
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
=
address
->
sin6_addr
;
else
ad
.
a
.
u
.
net
->
v6info
.
daddr
=
address
->
sin6_addr
;
#endif
rc
=
smk_access
(
skp
,
object
,
MAY_WRITE
,
&
ad
);
rc
=
smk_bu_note
(
"IPv6 port check"
,
skp
,
object
,
MAY_WRITE
,
rc
);
return
rc
;
return
smk_ipv6_check
(
skp
,
object
,
address
,
act
);
}
#endif
/*
CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER
*/
#endif
/*
SMACK_IPV6_PORT_LABELING
*/
/**
* smack_inode_setsecurity - set smack xattrs
...
...
@@ -2447,10 +2689,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
}
else
return
-
EOPNOTSUPP
;
#if
IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#if
def SMACK_IPV6_PORT_LABELING
if
(
sock
->
sk
->
sk_family
==
PF_INET6
)
smk_ipv6_port_label
(
sock
,
NULL
);
#endif
/* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
#endif
return
0
;
}
...
...
@@ -2492,7 +2734,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
return
smack_netlabel
(
sock
->
sk
,
SMACK_CIPSO_SOCKET
);
}
#if
ndef CONFIG_SECURITY_SMACK_NETFILTER
#if
def SMACK_IPV6_PORT_LABELING
/**
* smack_socket_bind - record port binding information.
* @sock: the socket
...
...
@@ -2506,14 +2748,11 @@ static int smack_socket_post_create(struct socket *sock, int family,
static
int
smack_socket_bind
(
struct
socket
*
sock
,
struct
sockaddr
*
address
,
int
addrlen
)
{
#if IS_ENABLED(CONFIG_IPV6)
if
(
sock
->
sk
!=
NULL
&&
sock
->
sk
->
sk_family
==
PF_INET6
)
smk_ipv6_port_label
(
sock
,
address
);
#endif
return
0
;
}
#endif
/*
!CONFIG_SECURITY_SMACK_NETFILTER
*/
#endif
/*
SMACK_IPV6_PORT_LABELING
*/
/**
* smack_socket_connect - connect access check
...
...
@@ -2529,6 +2768,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
int
addrlen
)
{
int
rc
=
0
;
#if IS_ENABLED(CONFIG_IPV6)
struct
sockaddr_in6
*
sip
=
(
struct
sockaddr_in6
*
)
sap
;
#endif
#ifdef SMACK_IPV6_SECMARK_LABELING
struct
smack_known
*
rsp
;
struct
socket_smack
*
ssp
=
sock
->
sk
->
sk_security
;
#endif
if
(
sock
->
sk
==
NULL
)
return
0
;
...
...
@@ -2542,10 +2788,15 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
case
PF_INET6
:
if
(
addrlen
<
sizeof
(
struct
sockaddr_in6
))
return
-
EINVAL
;
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
rc
=
smk_ipv6_port_check
(
sock
->
sk
,
(
struct
sockaddr_in6
*
)
sap
,
#ifdef SMACK_IPV6_SECMARK_LABELING
rsp
=
smack_ipv6host_label
(
sip
);
if
(
rsp
!=
NULL
)
rc
=
smk_ipv6_check
(
ssp
->
smk_out
,
rsp
,
sip
,
SMK_CONNECTING
);
#endif
/* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
#endif
#ifdef SMACK_IPV6_PORT_LABELING
rc
=
smk_ipv6_port_check
(
sock
->
sk
,
sip
,
SMK_CONNECTING
);
#endif
break
;
}
return
rc
;
...
...
@@ -3431,9 +3682,13 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int
size
)
{
struct
sockaddr_in
*
sip
=
(
struct
sockaddr_in
*
)
msg
->
msg_name
;
#if IS_ENABLED(CONFIG_IPV6)
&& !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#if IS_ENABLED(CONFIG_IPV6)
struct
sockaddr_in6
*
sap
=
(
struct
sockaddr_in6
*
)
msg
->
msg_name
;
#endif
/* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
#endif
#ifdef SMACK_IPV6_SECMARK_LABELING
struct
socket_smack
*
ssp
=
sock
->
sk
->
sk_security
;
struct
smack_known
*
rsp
;
#endif
int
rc
=
0
;
/*
...
...
@@ -3447,9 +3702,15 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
rc
=
smack_netlabel_send
(
sock
->
sk
,
sip
);
break
;
case
AF_INET6
:
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#ifdef SMACK_IPV6_SECMARK_LABELING
rsp
=
smack_ipv6host_label
(
sap
);
if
(
rsp
!=
NULL
)
rc
=
smk_ipv6_check
(
ssp
->
smk_out
,
rsp
,
sap
,
SMK_CONNECTING
);
#endif
#ifdef SMACK_IPV6_PORT_LABELING
rc
=
smk_ipv6_port_check
(
sock
->
sk
,
sap
,
SMK_SENDING
);
#endif
/* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
#endif
break
;
}
return
rc
;
...
...
@@ -3663,10 +3924,12 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
proto
=
smk_skb_to_addr_ipv6
(
skb
,
&
sadd
);
if
(
proto
!=
IPPROTO_UDP
&&
proto
!=
IPPROTO_TCP
)
break
;
#ifdef
CONFIG_SECURITY_SMACK_NETFILTER
#ifdef
SMACK_IPV6_SECMARK_LABELING
if
(
skb
&&
skb
->
secmark
!=
0
)
skp
=
smack_from_secid
(
skb
->
secmark
);
else
skp
=
smack_ipv6host_label
(
&
sadd
);
if
(
skp
==
NULL
)
skp
=
smack_net_ambient
;
#ifdef CONFIG_AUDIT
smk_ad_init_net
(
&
ad
,
__func__
,
LSM_AUDIT_DATA_NET
,
&
net
);
...
...
@@ -3677,9 +3940,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
rc
=
smk_access
(
skp
,
ssp
->
smk_in
,
MAY_WRITE
,
&
ad
);
rc
=
smk_bu_note
(
"IPv6 delivery"
,
skp
,
ssp
->
smk_in
,
MAY_WRITE
,
rc
);
#else
/* CONFIG_SECURITY_SMACK_NETFILTER */
#endif
/* SMACK_IPV6_SECMARK_LABELING */
#ifdef SMACK_IPV6_PORT_LABELING
rc
=
smk_ipv6_port_check
(
sk
,
&
sadd
,
SMK_RECEIVING
);
#endif
/*
CONFIG_SECURITY_SMACK_NETFILTER
*/
#endif
/*
SMACK_IPV6_PORT_LABELING
*/
break
;
#endif
/* CONFIG_IPV6 */
}
...
...
@@ -3777,13 +4041,11 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
}
netlbl_secattr_destroy
(
&
secattr
);
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
PF_INET6
:
#ifdef
CONFIG_SECURITY_SMACK_NETFILTER
#ifdef
SMACK_IPV6_SECMARK_LABELING
s
=
skb
->
secmark
;
#endif
/* CONFIG_SECURITY_SMACK_NETFILTER */
#endif
break
;
#endif
/* CONFIG_IPV6 */
}
*
secid
=
s
;
if
(
s
==
0
)
...
...
@@ -3906,7 +4168,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
hdr
=
ip_hdr
(
skb
);
addr
.
sin_addr
.
s_addr
=
hdr
->
saddr
;
rcu_read_lock
();
hskp
=
smack_host_label
(
&
addr
);
hskp
=
smack_
ipv4
host_label
(
&
addr
);
rcu_read_unlock
();
if
(
hskp
==
NULL
)
...
...
@@ -4254,7 +4516,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
return
0
;
}
struct
security_hook_list
smack_hooks
[]
=
{
st
atic
st
ruct
security_hook_list
smack_hooks
[]
=
{
LSM_HOOK_INIT
(
ptrace_access_check
,
smack_ptrace_access_check
),
LSM_HOOK_INIT
(
ptrace_traceme
,
smack_ptrace_traceme
),
LSM_HOOK_INIT
(
syslog
,
smack_syslog
),
...
...
@@ -4264,6 +4526,8 @@ struct security_hook_list smack_hooks[] = {
LSM_HOOK_INIT
(
sb_copy_data
,
smack_sb_copy_data
),
LSM_HOOK_INIT
(
sb_kern_mount
,
smack_sb_kern_mount
),
LSM_HOOK_INIT
(
sb_statfs
,
smack_sb_statfs
),
LSM_HOOK_INIT
(
sb_set_mnt_opts
,
smack_set_mnt_opts
),
LSM_HOOK_INIT
(
sb_parse_opts_str
,
smack_parse_opts_str
),
LSM_HOOK_INIT
(
bprm_set_creds
,
smack_bprm_set_creds
),
LSM_HOOK_INIT
(
bprm_committing_creds
,
smack_bprm_committing_creds
),
...
...
@@ -4356,9 +4620,9 @@ struct security_hook_list smack_hooks[] = {
LSM_HOOK_INIT
(
unix_may_send
,
smack_unix_may_send
),
LSM_HOOK_INIT
(
socket_post_create
,
smack_socket_post_create
),
#if
ndef CONFIG_SECURITY_SMACK_NETFILTER
#if
def SMACK_IPV6_PORT_LABELING
LSM_HOOK_INIT
(
socket_bind
,
smack_socket_bind
),
#endif
/* CONFIG_SECURITY_SMACK_NETFILTER */
#endif
LSM_HOOK_INIT
(
socket_connect
,
smack_socket_connect
),
LSM_HOOK_INIT
(
socket_sendmsg
,
smack_socket_sendmsg
),
LSM_HOOK_INIT
(
socket_sock_rcv_skb
,
smack_socket_sock_rcv_skb
),
...
...
@@ -4453,7 +4717,16 @@ static __init int smack_init(void)
return
-
ENOMEM
;
}
printk
(
KERN_INFO
"Smack: Initializing.
\n
"
);
pr_info
(
"Smack: Initializing.
\n
"
);
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
pr_info
(
"Smack: Netfilter enabled.
\n
"
);
#endif
#ifdef SMACK_IPV6_PORT_LABELING
pr_info
(
"Smack: IPv6 port labeling enabled.
\n
"
);
#endif
#ifdef SMACK_IPV6_SECMARK_LABELING
pr_info
(
"Smack: IPv6 Netfilter enabled.
\n
"
);
#endif
/*
* Set the security state for the initial task.
...
...
security/smack/smackfs.c
View file @
5ab16579
...
...
@@ -29,6 +29,7 @@
#include <linux/magic.h>
#include "smack.h"
#define BEBITS (sizeof(__be32) * 8)
/*
* smackfs pseudo filesystem.
*/
...
...
@@ -40,7 +41,7 @@ enum smk_inos {
SMK_DOI
=
5
,
/* CIPSO DOI */
SMK_DIRECT
=
6
,
/* CIPSO level indicating direct label */
SMK_AMBIENT
=
7
,
/* internet ambient label */
SMK_NET
LBL
ADDR
=
8
,
/* single label hosts */
SMK_NET
4
ADDR
=
8
,
/* single label hosts */
SMK_ONLYCAP
=
9
,
/* the only "capable" label */
SMK_LOGGING
=
10
,
/* logging */
SMK_LOAD_SELF
=
11
,
/* task specific rules */
...
...
@@ -57,6 +58,9 @@ enum smk_inos {
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
SMK_UNCONFINED
=
22
,
/* define an unconfined label */
#endif
#if IS_ENABLED(CONFIG_IPV6)
SMK_NET6ADDR
=
23
,
/* single label IPv6 hosts */
#endif
/* CONFIG_IPV6 */
};
/*
...
...
@@ -64,7 +68,10 @@ enum smk_inos {
*/
static
DEFINE_MUTEX
(
smack_cipso_lock
);
static
DEFINE_MUTEX
(
smack_ambient_lock
);
static
DEFINE_MUTEX
(
smk_netlbladdr_lock
);
static
DEFINE_MUTEX
(
smk_net4addr_lock
);
#if IS_ENABLED(CONFIG_IPV6)
static
DEFINE_MUTEX
(
smk_net6addr_lock
);
#endif
/* CONFIG_IPV6 */
/*
* This is the "ambient" label for network traffic.
...
...
@@ -118,7 +125,10 @@ int smack_ptrace_rule = SMACK_PTRACE_DEFAULT;
* can write to the specified label.
*/
LIST_HEAD
(
smk_netlbladdr_list
);
LIST_HEAD
(
smk_net4addr_list
);
#if IS_ENABLED(CONFIG_IPV6)
LIST_HEAD
(
smk_net6addr_list
);
#endif
/* CONFIG_IPV6 */
/*
* Rule lists are maintained for each label.
...
...
@@ -129,7 +139,7 @@ struct smack_master_list {
struct
smack_rule
*
smk_rule
;
};
LIST_HEAD
(
smack_rule_list
);
static
LIST_HEAD
(
smack_rule_list
);
struct
smack_parsed_rule
{
struct
smack_known
*
smk_subject
;
...
...
@@ -140,11 +150,6 @@ struct smack_parsed_rule {
static
int
smk_cipso_doi_value
=
SMACK_CIPSO_DOI_DEFAULT
;
struct
smack_known
smack_cipso_option
=
{
.
smk_known
=
SMACK_CIPSO_OPTION
,
.
smk_secid
=
0
,
};
/*
* Values for parsing cipso rules
* SMK_DIGITLEN: Length of a digit field in a rule.
...
...
@@ -1047,92 +1052,90 @@ static const struct file_operations smk_cipso2_ops = {
* Seq_file read operations for /smack/netlabel
*/
static
void
*
net
lbl
addr_seq_start
(
struct
seq_file
*
s
,
loff_t
*
pos
)
static
void
*
net
4
addr_seq_start
(
struct
seq_file
*
s
,
loff_t
*
pos
)
{
return
smk_seq_start
(
s
,
pos
,
&
smk_net
lbl
addr_list
);
return
smk_seq_start
(
s
,
pos
,
&
smk_net
4
addr_list
);
}
static
void
*
net
lbl
addr_seq_next
(
struct
seq_file
*
s
,
void
*
v
,
loff_t
*
pos
)
static
void
*
net
4
addr_seq_next
(
struct
seq_file
*
s
,
void
*
v
,
loff_t
*
pos
)
{
return
smk_seq_next
(
s
,
v
,
pos
,
&
smk_net
lbl
addr_list
);
return
smk_seq_next
(
s
,
v
,
pos
,
&
smk_net
4
addr_list
);
}
#define BEBITS (sizeof(__be32) * 8)
/*
* Print host/label pairs
*/
static
int
net
lbl
addr_seq_show
(
struct
seq_file
*
s
,
void
*
v
)
static
int
net
4
addr_seq_show
(
struct
seq_file
*
s
,
void
*
v
)
{
struct
list_head
*
list
=
v
;
struct
smk_netlbladdr
*
skp
=
list_entry_rcu
(
list
,
struct
smk_netlbladdr
,
list
);
unsigned
char
*
hp
=
(
char
*
)
&
skp
->
smk_host
.
sin_addr
.
s_addr
;
int
maskn
;
u32
temp_mask
=
be32_to_cpu
(
skp
->
smk_mask
.
s_addr
);
for
(
maskn
=
0
;
temp_mask
;
temp_mask
<<=
1
,
maskn
++
);
struct
smk_net4addr
*
skp
=
list_entry_rcu
(
list
,
struct
smk_net4addr
,
list
);
char
*
kp
=
SMACK_CIPSO_OPTION
;
seq_printf
(
s
,
"%u.%u.%u.%u/%d %s
\n
"
,
hp
[
0
],
hp
[
1
],
hp
[
2
],
hp
[
3
],
maskn
,
skp
->
smk_label
->
smk_known
);
if
(
skp
->
smk_label
!=
NULL
)
kp
=
skp
->
smk_label
->
smk_known
;
seq_printf
(
s
,
"%pI4/%d %s
\n
"
,
&
skp
->
smk_host
.
s_addr
,
skp
->
smk_masks
,
kp
);
return
0
;
}
static
const
struct
seq_operations
net
lbl
addr_seq_ops
=
{
.
start
=
net
lbl
addr_seq_start
,
.
next
=
net
lbl
addr_seq_next
,
.
show
=
net
lbl
addr_seq_show
,
static
const
struct
seq_operations
net
4
addr_seq_ops
=
{
.
start
=
net
4
addr_seq_start
,
.
next
=
net
4
addr_seq_next
,
.
show
=
net
4
addr_seq_show
,
.
stop
=
smk_seq_stop
,
};
/**
* smk_open_net
lbl
addr - open() for /smack/netlabel
* smk_open_net
4
addr - open() for /smack/netlabel
* @inode: inode structure representing file
* @file: "netlabel" file pointer
*
* Connect our net
lbl
addr_seq_* operations with /smack/netlabel
* Connect our net
4
addr_seq_* operations with /smack/netlabel
* file_operations
*/
static
int
smk_open_net
lbl
addr
(
struct
inode
*
inode
,
struct
file
*
file
)
static
int
smk_open_net
4
addr
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
seq_open
(
file
,
&
net
lbl
addr_seq_ops
);
return
seq_open
(
file
,
&
net
4
addr_seq_ops
);
}
/**
* smk_net
lbl
addr_insert
* smk_net
4
addr_insert
* @new : netlabel to insert
*
* This helper insert netlabel in the smack_net
lbl
addrs list
* This helper insert netlabel in the smack_net
4
addrs list
* sorted by netmask length (longest to smallest)
* locked by &smk_net
lbladdr_lock in smk_write_netlbl
addr
* locked by &smk_net
4addr_lock in smk_write_net4
addr
*
*/
static
void
smk_net
lbladdr_insert
(
struct
smk_netlbl
addr
*
new
)
static
void
smk_net
4addr_insert
(
struct
smk_net4
addr
*
new
)
{
struct
smk_netlbladdr
*
m
,
*
m_next
;
struct
smk_net4addr
*
m
;
struct
smk_net4addr
*
m_next
;
if
(
list_empty
(
&
smk_net
lbl
addr_list
))
{
list_add_rcu
(
&
new
->
list
,
&
smk_net
lbl
addr_list
);
if
(
list_empty
(
&
smk_net
4
addr_list
))
{
list_add_rcu
(
&
new
->
list
,
&
smk_net
4
addr_list
);
return
;
}
m
=
list_entry_rcu
(
smk_net
lbl
addr_list
.
next
,
struct
smk_net
lbl
addr
,
list
);
m
=
list_entry_rcu
(
smk_net
4
addr_list
.
next
,
struct
smk_net
4
addr
,
list
);
/* the comparison '>' is a bit hacky, but works */
if
(
new
->
smk_mask
.
s_addr
>
m
->
smk_mask
.
s_addr
)
{
list_add_rcu
(
&
new
->
list
,
&
smk_net
lbl
addr_list
);
if
(
new
->
smk_mask
s
>
m
->
smk_masks
)
{
list_add_rcu
(
&
new
->
list
,
&
smk_net
4
addr_list
);
return
;
}
list_for_each_entry_rcu
(
m
,
&
smk_net
lbl
addr_list
,
list
)
{
if
(
list_is_last
(
&
m
->
list
,
&
smk_net
lbl
addr_list
))
{
list_for_each_entry_rcu
(
m
,
&
smk_net
4
addr_list
,
list
)
{
if
(
list_is_last
(
&
m
->
list
,
&
smk_net
4
addr_list
))
{
list_add_rcu
(
&
new
->
list
,
&
m
->
list
);
return
;
}
m_next
=
list_entry_rcu
(
m
->
list
.
next
,
struct
smk_net
lbl
addr
,
list
);
if
(
new
->
smk_mask
.
s_addr
>
m_next
->
smk_mask
.
s_addr
)
{
struct
smk_net
4
addr
,
list
);
if
(
new
->
smk_mask
s
>
m_next
->
smk_masks
)
{
list_add_rcu
(
&
new
->
list
,
&
m
->
list
);
return
;
}
...
...
@@ -1141,28 +1144,29 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
/**
* smk_write_net
lbl
addr - write() for /smack/netlabel
* smk_write_net
4
addr - write() for /smack/netlabel
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start
*
* Accepts only one net
lbl
addr per write call.
* Accepts only one net
4
addr per write call.
* Returns number of bytes written or error code, as appropriate
*/
static
ssize_t
smk_write_net
lbl
addr
(
struct
file
*
file
,
const
char
__user
*
buf
,
static
ssize_t
smk_write_net
4
addr
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
smk_net
lbl
addr
*
snp
;
struct
smk_net
4
addr
*
snp
;
struct
sockaddr_in
newname
;
char
*
smack
;
struct
smack_known
*
skp
;
struct
smack_known
*
skp
=
NULL
;
char
*
data
;
char
*
host
=
(
char
*
)
&
newname
.
sin_addr
.
s_addr
;
int
rc
;
struct
netlbl_audit
audit_info
;
struct
in_addr
mask
;
unsigned
int
m
;
unsigned
int
masks
;
int
found
;
u32
mask_bits
=
(
1
<<
31
);
__be32
nsa
;
...
...
@@ -1200,7 +1204,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
data
[
count
]
=
'\0'
;
rc
=
sscanf
(
data
,
"%hhd.%hhd.%hhd.%hhd/%u %s"
,
&
host
[
0
],
&
host
[
1
],
&
host
[
2
],
&
host
[
3
],
&
m
,
smack
);
&
host
[
0
],
&
host
[
1
],
&
host
[
2
],
&
host
[
3
],
&
m
asks
,
smack
);
if
(
rc
!=
6
)
{
rc
=
sscanf
(
data
,
"%hhd.%hhd.%hhd.%hhd %s"
,
&
host
[
0
],
&
host
[
1
],
&
host
[
2
],
&
host
[
3
],
smack
);
...
...
@@ -1209,8 +1213,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
goto
free_out
;
}
m
=
BEBITS
;
masks
=
32
;
}
if
(
m
>
BEBITS
)
{
if
(
m
asks
>
BEBITS
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
...
...
@@ -1225,16 +1230,16 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
goto
free_out
;
}
}
else
{
/*
check known options */
if
(
strcmp
(
smack
,
smack_cipso_option
.
smk_known
)
==
0
)
skp
=
&
smack_cipso_option
;
else
{
/*
* Only the -CIPSO option is supported for IPv4
*/
if
(
strcmp
(
smack
,
SMACK_CIPSO_OPTION
)
!=
0
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
}
for
(
temp_mask
=
0
;
m
>
0
;
m
--
)
{
for
(
m
=
masks
,
temp_mask
=
0
;
m
>
0
;
m
--
)
{
temp_mask
|=
mask_bits
;
mask_bits
>>=
1
;
}
...
...
@@ -1245,14 +1250,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
* Only allow one writer at a time. Writes should be
* quite rare and small in any case.
*/
mutex_lock
(
&
smk_net
lbl
addr_lock
);
mutex_lock
(
&
smk_net
4
addr_lock
);
nsa
=
newname
.
sin_addr
.
s_addr
;
/* try to find if the prefix is already in the list */
found
=
0
;
list_for_each_entry_rcu
(
snp
,
&
smk_netlbladdr_list
,
list
)
{
if
(
snp
->
smk_host
.
sin_addr
.
s_addr
==
nsa
&&
snp
->
smk_mask
.
s_addr
==
mask
.
s_addr
)
{
list_for_each_entry_rcu
(
snp
,
&
smk_net4addr_list
,
list
)
{
if
(
snp
->
smk_host
.
s_addr
==
nsa
&&
snp
->
smk_masks
==
masks
)
{
found
=
1
;
break
;
}
...
...
@@ -1265,17 +1269,20 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
rc
=
-
ENOMEM
;
else
{
rc
=
0
;
snp
->
smk_host
.
s
in_addr
.
s
_addr
=
newname
.
sin_addr
.
s_addr
;
snp
->
smk_host
.
s_addr
=
newname
.
sin_addr
.
s_addr
;
snp
->
smk_mask
.
s_addr
=
mask
.
s_addr
;
snp
->
smk_label
=
skp
;
smk_netlbladdr_insert
(
snp
);
snp
->
smk_masks
=
masks
;
smk_net4addr_insert
(
snp
);
}
}
else
{
/* we delete the unlabeled entry, only if the previous label
* wasn't the special CIPSO option */
if
(
snp
->
smk_label
!=
&
smack_cipso_option
)
/*
* Delete the unlabeled entry, only if the previous label
* wasn't the special CIPSO option
*/
if
(
snp
->
smk_label
!=
NULL
)
rc
=
netlbl_cfg_unlbl_static_del
(
&
init_net
,
NULL
,
&
snp
->
smk_host
.
sin_addr
,
&
snp
->
smk_mask
,
&
snp
->
smk_host
,
&
snp
->
smk_mask
,
PF_INET
,
&
audit_info
);
else
rc
=
0
;
...
...
@@ -1287,15 +1294,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
* this host so that incoming packets get labeled.
* but only if we didn't get the special CIPSO option
*/
if
(
rc
==
0
&&
skp
!=
&
smack_cipso_option
)
if
(
rc
==
0
&&
skp
!=
NULL
)
rc
=
netlbl_cfg_unlbl_static_add
(
&
init_net
,
NULL
,
&
snp
->
smk_host
.
sin_addr
,
&
snp
->
smk_mask
,
PF_INET
,
&
snp
->
smk_host
,
&
snp
->
smk_mask
,
PF_INET
,
snp
->
smk_label
->
smk_secid
,
&
audit_info
);
if
(
rc
==
0
)
rc
=
count
;
mutex_unlock
(
&
smk_net
lbl
addr_lock
);
mutex_unlock
(
&
smk_net
4
addr_lock
);
free_out:
kfree
(
smack
);
...
...
@@ -1305,14 +1312,279 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
return
rc
;
}
static
const
struct
file_operations
smk_net
lbl
addr_ops
=
{
.
open
=
smk_open_net
lbl
addr
,
static
const
struct
file_operations
smk_net
4
addr_ops
=
{
.
open
=
smk_open_net
4
addr
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
write
=
smk_write_net
lbl
addr
,
.
write
=
smk_write_net
4
addr
,
.
release
=
seq_release
,
};
#if IS_ENABLED(CONFIG_IPV6)
/*
* Seq_file read operations for /smack/netlabel6
*/
static
void
*
net6addr_seq_start
(
struct
seq_file
*
s
,
loff_t
*
pos
)
{
return
smk_seq_start
(
s
,
pos
,
&
smk_net6addr_list
);
}
static
void
*
net6addr_seq_next
(
struct
seq_file
*
s
,
void
*
v
,
loff_t
*
pos
)
{
return
smk_seq_next
(
s
,
v
,
pos
,
&
smk_net6addr_list
);
}
/*
* Print host/label pairs
*/
static
int
net6addr_seq_show
(
struct
seq_file
*
s
,
void
*
v
)
{
struct
list_head
*
list
=
v
;
struct
smk_net6addr
*
skp
=
list_entry
(
list
,
struct
smk_net6addr
,
list
);
if
(
skp
->
smk_label
!=
NULL
)
seq_printf
(
s
,
"%pI6/%d %s
\n
"
,
&
skp
->
smk_host
,
skp
->
smk_masks
,
skp
->
smk_label
->
smk_known
);
return
0
;
}
static
const
struct
seq_operations
net6addr_seq_ops
=
{
.
start
=
net6addr_seq_start
,
.
next
=
net6addr_seq_next
,
.
show
=
net6addr_seq_show
,
.
stop
=
smk_seq_stop
,
};
/**
* smk_open_net6addr - open() for /smack/netlabel
* @inode: inode structure representing file
* @file: "netlabel" file pointer
*
* Connect our net6addr_seq_* operations with /smack/netlabel
* file_operations
*/
static
int
smk_open_net6addr
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
seq_open
(
file
,
&
net6addr_seq_ops
);
}
/**
* smk_net6addr_insert
* @new : entry to insert
*
* This inserts an entry in the smack_net6addrs list
* sorted by netmask length (longest to smallest)
* locked by &smk_net6addr_lock in smk_write_net6addr
*
*/
static
void
smk_net6addr_insert
(
struct
smk_net6addr
*
new
)
{
struct
smk_net6addr
*
m_next
;
struct
smk_net6addr
*
m
;
if
(
list_empty
(
&
smk_net6addr_list
))
{
list_add_rcu
(
&
new
->
list
,
&
smk_net6addr_list
);
return
;
}
m
=
list_entry_rcu
(
smk_net6addr_list
.
next
,
struct
smk_net6addr
,
list
);
if
(
new
->
smk_masks
>
m
->
smk_masks
)
{
list_add_rcu
(
&
new
->
list
,
&
smk_net6addr_list
);
return
;
}
list_for_each_entry_rcu
(
m
,
&
smk_net6addr_list
,
list
)
{
if
(
list_is_last
(
&
m
->
list
,
&
smk_net6addr_list
))
{
list_add_rcu
(
&
new
->
list
,
&
m
->
list
);
return
;
}
m_next
=
list_entry_rcu
(
m
->
list
.
next
,
struct
smk_net6addr
,
list
);
if
(
new
->
smk_masks
>
m_next
->
smk_masks
)
{
list_add_rcu
(
&
new
->
list
,
&
m
->
list
);
return
;
}
}
}
/**
* smk_write_net6addr - write() for /smack/netlabel
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start
*
* Accepts only one net6addr per write call.
* Returns number of bytes written or error code, as appropriate
*/
static
ssize_t
smk_write_net6addr
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
smk_net6addr
*
snp
;
struct
in6_addr
newname
;
struct
in6_addr
fullmask
;
struct
smack_known
*
skp
=
NULL
;
char
*
smack
;
char
*
data
;
int
rc
=
0
;
int
found
=
0
;
int
i
;
unsigned
int
scanned
[
8
];
unsigned
int
m
;
unsigned
int
mask
=
128
;
/*
* Must have privilege.
* No partial writes.
* Enough data must be present.
* "<addr/mask, as a:b:c:d:e:f:g:h/e><space><label>"
* "<addr, as a:b:c:d:e:f:g:h><space><label>"
*/
if
(
!
smack_privileged
(
CAP_MAC_ADMIN
))
return
-
EPERM
;
if
(
*
ppos
!=
0
)
return
-
EINVAL
;
if
(
count
<
SMK_NETLBLADDRMIN
)
return
-
EINVAL
;
data
=
kzalloc
(
count
+
1
,
GFP_KERNEL
);
if
(
data
==
NULL
)
return
-
ENOMEM
;
if
(
copy_from_user
(
data
,
buf
,
count
)
!=
0
)
{
rc
=
-
EFAULT
;
goto
free_data_out
;
}
smack
=
kzalloc
(
count
+
1
,
GFP_KERNEL
);
if
(
smack
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
free_data_out
;
}
data
[
count
]
=
'\0'
;
i
=
sscanf
(
data
,
"%x:%x:%x:%x:%x:%x:%x:%x/%u %s"
,
&
scanned
[
0
],
&
scanned
[
1
],
&
scanned
[
2
],
&
scanned
[
3
],
&
scanned
[
4
],
&
scanned
[
5
],
&
scanned
[
6
],
&
scanned
[
7
],
&
mask
,
smack
);
if
(
i
!=
10
)
{
i
=
sscanf
(
data
,
"%x:%x:%x:%x:%x:%x:%x:%x %s"
,
&
scanned
[
0
],
&
scanned
[
1
],
&
scanned
[
2
],
&
scanned
[
3
],
&
scanned
[
4
],
&
scanned
[
5
],
&
scanned
[
6
],
&
scanned
[
7
],
smack
);
if
(
i
!=
9
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
}
if
(
mask
>
128
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
scanned
[
i
]
>
0xffff
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
newname
.
s6_addr16
[
i
]
=
htons
(
scanned
[
i
]);
}
/*
* If smack begins with '-', it is an option, don't import it
*/
if
(
smack
[
0
]
!=
'-'
)
{
skp
=
smk_import_entry
(
smack
,
0
);
if
(
skp
==
NULL
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
}
else
{
/*
* Only -DELETE is supported for IPv6
*/
if
(
strcmp
(
smack
,
SMACK_DELETE_OPTION
)
!=
0
)
{
rc
=
-
EINVAL
;
goto
free_out
;
}
}
for
(
i
=
0
,
m
=
mask
;
i
<
8
;
i
++
)
{
if
(
m
>=
16
)
{
fullmask
.
s6_addr16
[
i
]
=
0xffff
;
m
-=
16
;
}
else
if
(
m
>
0
)
{
fullmask
.
s6_addr16
[
i
]
=
(
1
<<
m
)
-
1
;
m
=
0
;
}
else
fullmask
.
s6_addr16
[
i
]
=
0
;
newname
.
s6_addr16
[
i
]
&=
fullmask
.
s6_addr16
[
i
];
}
/*
* Only allow one writer at a time. Writes should be
* quite rare and small in any case.
*/
mutex_lock
(
&
smk_net6addr_lock
);
/*
* Try to find the prefix in the list
*/
list_for_each_entry_rcu
(
snp
,
&
smk_net6addr_list
,
list
)
{
if
(
mask
!=
snp
->
smk_masks
)
continue
;
for
(
found
=
1
,
i
=
0
;
i
<
8
;
i
++
)
{
if
(
newname
.
s6_addr16
[
i
]
!=
snp
->
smk_host
.
s6_addr16
[
i
])
{
found
=
0
;
break
;
}
}
if
(
found
==
1
)
break
;
}
if
(
found
==
0
)
{
snp
=
kzalloc
(
sizeof
(
*
snp
),
GFP_KERNEL
);
if
(
snp
==
NULL
)
rc
=
-
ENOMEM
;
else
{
snp
->
smk_host
=
newname
;
snp
->
smk_mask
=
fullmask
;
snp
->
smk_masks
=
mask
;
snp
->
smk_label
=
skp
;
smk_net6addr_insert
(
snp
);
}
}
else
{
snp
->
smk_label
=
skp
;
}
if
(
rc
==
0
)
rc
=
count
;
mutex_unlock
(
&
smk_net6addr_lock
);
free_out:
kfree
(
smack
);
free_data_out:
kfree
(
data
);
return
rc
;
}
static
const
struct
file_operations
smk_net6addr_ops
=
{
.
open
=
smk_open_net6addr
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
write
=
smk_write_net6addr
,
.
release
=
seq_release
,
};
#endif
/* CONFIG_IPV6 */
/**
* smk_read_doi - read() for /smack/doi
* @filp: file pointer, not actually used
...
...
@@ -2320,11 +2592,7 @@ static const struct file_operations smk_revoke_subj_ops = {
*/
static
int
smk_init_sysfs
(
void
)
{
int
err
;
err
=
sysfs_create_mount_point
(
fs_kobj
,
"smackfs"
);
if
(
err
)
return
err
;
return
0
;
return
sysfs_create_mount_point
(
fs_kobj
,
"smackfs"
);
}
/**
...
...
@@ -2519,8 +2787,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
"direct"
,
&
smk_direct_ops
,
S_IRUGO
|
S_IWUSR
},
[
SMK_AMBIENT
]
=
{
"ambient"
,
&
smk_ambient_ops
,
S_IRUGO
|
S_IWUSR
},
[
SMK_NET
LBL
ADDR
]
=
{
"netlabel"
,
&
smk_net
lbl
addr_ops
,
S_IRUGO
|
S_IWUSR
},
[
SMK_NET
4
ADDR
]
=
{
"netlabel"
,
&
smk_net
4
addr_ops
,
S_IRUGO
|
S_IWUSR
},
[
SMK_ONLYCAP
]
=
{
"onlycap"
,
&
smk_onlycap_ops
,
S_IRUGO
|
S_IWUSR
},
[
SMK_LOGGING
]
=
{
...
...
@@ -2552,6 +2820,10 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
[
SMK_UNCONFINED
]
=
{
"unconfined"
,
&
smk_unconfined_ops
,
S_IRUGO
|
S_IWUSR
},
#endif
#if IS_ENABLED(CONFIG_IPV6)
[
SMK_NET6ADDR
]
=
{
"ipv6host"
,
&
smk_net6addr_ops
,
S_IRUGO
|
S_IWUSR
},
#endif
/* CONFIG_IPV6 */
/* last one */
{
""
}
};
...
...
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