Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: smack: Add a new '-CIPSO' option to the network address label configuration netlabel: Cleanup the Smack/NetLabel code to fix incoming TCP connections lsm: Remove the socket_post_accept() hook selinux: Remove the "compat_net" compatibility code netlabel: Label incoming TCP connections correctly in SELinux lsm: Relocate the IPv4 security_inet_conn_request() hooks TOMOYO: Fix a typo. smack: convert smack to standard linux lists
This commit is contained in:
commit
7541bba880
|
@ -184,14 +184,16 @@ length. Single character labels using special characters, that being anything
|
||||||
other than a letter or digit, are reserved for use by the Smack development
|
other than a letter or digit, are reserved for use by the Smack development
|
||||||
team. Smack labels are unstructured, case sensitive, and the only operation
|
team. Smack labels are unstructured, case sensitive, and the only operation
|
||||||
ever performed on them is comparison for equality. Smack labels cannot
|
ever performed on them is comparison for equality. Smack labels cannot
|
||||||
contain unprintable characters or the "/" (slash) character.
|
contain unprintable characters or the "/" (slash) character. Smack labels
|
||||||
|
cannot begin with a '-', which is reserved for special options.
|
||||||
|
|
||||||
There are some predefined labels:
|
There are some predefined labels:
|
||||||
|
|
||||||
_ Pronounced "floor", a single underscore character.
|
_ Pronounced "floor", a single underscore character.
|
||||||
^ Pronounced "hat", a single circumflex character.
|
^ Pronounced "hat", a single circumflex character.
|
||||||
* Pronounced "star", a single asterisk character.
|
* Pronounced "star", a single asterisk character.
|
||||||
? Pronounced "huh", a single question mark character.
|
? Pronounced "huh", a single question mark character.
|
||||||
|
@ Pronounced "Internet", a single at sign character.
|
||||||
|
|
||||||
Every task on a Smack system is assigned a label. System tasks, such as
|
Every task on a Smack system is assigned a label. System tasks, such as
|
||||||
init(8) and systems daemons, are run with the floor ("_") label. User tasks
|
init(8) and systems daemons, are run with the floor ("_") label. User tasks
|
||||||
|
@ -412,6 +414,36 @@ sockets.
|
||||||
A privileged program may set this to match the label of another
|
A privileged program may set this to match the label of another
|
||||||
task with which it hopes to communicate.
|
task with which it hopes to communicate.
|
||||||
|
|
||||||
|
Smack Netlabel Exceptions
|
||||||
|
|
||||||
|
You will often find that your labeled application has to talk to the outside,
|
||||||
|
unlabeled world. To do this there's a special file /smack/netlabel where you can
|
||||||
|
add some exceptions in the form of :
|
||||||
|
@IP1 LABEL1 or
|
||||||
|
@IP2/MASK LABEL2
|
||||||
|
|
||||||
|
It means that your application will have unlabeled access to @IP1 if it has
|
||||||
|
write access on LABEL1, and access to the subnet @IP2/MASK if it has write
|
||||||
|
access on LABEL2.
|
||||||
|
|
||||||
|
Entries in the /smack/netlabel file are matched by longest mask first, like in
|
||||||
|
classless IPv4 routing.
|
||||||
|
|
||||||
|
A special label '@' and an option '-CIPSO' can be used there :
|
||||||
|
@ means Internet, any application with any label has access to it
|
||||||
|
-CIPSO means standard CIPSO networking
|
||||||
|
|
||||||
|
If you don't know what CIPSO is and don't plan to use it, you can just do :
|
||||||
|
echo 127.0.0.1 -CIPSO > /smack/netlabel
|
||||||
|
echo 0.0.0.0/0 @ > /smack/netlabel
|
||||||
|
|
||||||
|
If you use CIPSO on your 192.168.0.0/16 local network and need also unlabeled
|
||||||
|
Internet access, you can have :
|
||||||
|
echo 127.0.0.1 -CIPSO > /smack/netlabel
|
||||||
|
echo 192.168.0.0/16 -CIPSO > /smack/netlabel
|
||||||
|
echo 0.0.0.0/0 @ > /smack/netlabel
|
||||||
|
|
||||||
|
|
||||||
Writing Applications for Smack
|
Writing Applications for Smack
|
||||||
|
|
||||||
There are three sorts of applications that will run on a Smack system. How an
|
There are three sorts of applications that will run on a Smack system. How an
|
||||||
|
|
|
@ -356,17 +356,6 @@ Who: Hans de Goede <hdegoede@redhat.com>
|
||||||
|
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
What: SELinux "compat_net" functionality
|
|
||||||
When: 2.6.30 at the earliest
|
|
||||||
Why: In 2.6.18 the Secmark concept was introduced to replace the "compat_net"
|
|
||||||
network access control functionality of SELinux. Secmark offers both
|
|
||||||
better performance and greater flexibility than the "compat_net"
|
|
||||||
mechanism. Now that the major Linux distributions have moved to
|
|
||||||
Secmark, it is time to deprecate the older mechanism and start the
|
|
||||||
process of removing the old code.
|
|
||||||
Who: Paul Moore <paul.moore@hp.com>
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
What: sysfs ui for changing p4-clockmod parameters
|
What: sysfs ui for changing p4-clockmod parameters
|
||||||
When: September 2009
|
When: September 2009
|
||||||
Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
|
Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
|
||||||
|
|
|
@ -2030,15 +2030,6 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||||
If enabled at boot time, /selinux/disable can be used
|
If enabled at boot time, /selinux/disable can be used
|
||||||
later to disable prior to initial policy load.
|
later to disable prior to initial policy load.
|
||||||
|
|
||||||
selinux_compat_net =
|
|
||||||
[SELINUX] Set initial selinux_compat_net flag value.
|
|
||||||
Format: { "0" | "1" }
|
|
||||||
0 -- use new secmark-based packet controls
|
|
||||||
1 -- use legacy packet controls
|
|
||||||
Default value is 0 (preferred).
|
|
||||||
Value can be changed at runtime via
|
|
||||||
/selinux/compat_net.
|
|
||||||
|
|
||||||
serialnumber [BUGS=X86-32]
|
serialnumber [BUGS=X86-32]
|
||||||
|
|
||||||
shapers= [NET]
|
shapers= [NET]
|
||||||
|
|
|
@ -880,11 +880,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||||
* @sock contains the listening socket structure.
|
* @sock contains the listening socket structure.
|
||||||
* @newsock contains the newly created server socket for connection.
|
* @newsock contains the newly created server socket for connection.
|
||||||
* Return 0 if permission is granted.
|
* Return 0 if permission is granted.
|
||||||
* @socket_post_accept:
|
|
||||||
* This hook allows a security module to copy security
|
|
||||||
* information into the newly created socket's inode.
|
|
||||||
* @sock contains the listening socket structure.
|
|
||||||
* @newsock contains the newly created server socket for connection.
|
|
||||||
* @socket_sendmsg:
|
* @socket_sendmsg:
|
||||||
* Check permission before transmitting a message to another socket.
|
* Check permission before transmitting a message to another socket.
|
||||||
* @sock contains the socket structure.
|
* @sock contains the socket structure.
|
||||||
|
@ -1554,8 +1549,6 @@ struct security_operations {
|
||||||
struct sockaddr *address, int addrlen);
|
struct sockaddr *address, int addrlen);
|
||||||
int (*socket_listen) (struct socket *sock, int backlog);
|
int (*socket_listen) (struct socket *sock, int backlog);
|
||||||
int (*socket_accept) (struct socket *sock, struct socket *newsock);
|
int (*socket_accept) (struct socket *sock, struct socket *newsock);
|
||||||
void (*socket_post_accept) (struct socket *sock,
|
|
||||||
struct socket *newsock);
|
|
||||||
int (*socket_sendmsg) (struct socket *sock,
|
int (*socket_sendmsg) (struct socket *sock,
|
||||||
struct msghdr *msg, int size);
|
struct msghdr *msg, int size);
|
||||||
int (*socket_recvmsg) (struct socket *sock,
|
int (*socket_recvmsg) (struct socket *sock,
|
||||||
|
@ -2537,7 +2530,6 @@ int security_socket_bind(struct socket *sock, struct sockaddr *address, int addr
|
||||||
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
|
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
|
||||||
int security_socket_listen(struct socket *sock, int backlog);
|
int security_socket_listen(struct socket *sock, int backlog);
|
||||||
int security_socket_accept(struct socket *sock, struct socket *newsock);
|
int security_socket_accept(struct socket *sock, struct socket *newsock);
|
||||||
void security_socket_post_accept(struct socket *sock, struct socket *newsock);
|
|
||||||
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
|
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
|
||||||
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
|
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||||
int size, int flags);
|
int size, int flags);
|
||||||
|
@ -2616,11 +2608,6 @@ static inline int security_socket_accept(struct socket *sock,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void security_socket_post_accept(struct socket *sock,
|
|
||||||
struct socket *newsock)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int security_socket_sendmsg(struct socket *sock,
|
static inline int security_socket_sendmsg(struct socket *sock,
|
||||||
struct msghdr *msg, int size)
|
struct msghdr *msg, int size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <linux/net.h>
|
#include <linux/net.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <net/netlabel.h>
|
#include <net/netlabel.h>
|
||||||
|
#include <net/request_sock.h>
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
/* known doi values */
|
/* known doi values */
|
||||||
|
@ -215,6 +216,10 @@ int cipso_v4_sock_setattr(struct sock *sk,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
void cipso_v4_sock_delattr(struct sock *sk);
|
void cipso_v4_sock_delattr(struct sock *sk);
|
||||||
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
|
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
|
||||||
|
int cipso_v4_req_setattr(struct request_sock *req,
|
||||||
|
const struct cipso_v4_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
void cipso_v4_req_delattr(struct request_sock *req);
|
||||||
int cipso_v4_skbuff_setattr(struct sk_buff *skb,
|
int cipso_v4_skbuff_setattr(struct sk_buff *skb,
|
||||||
const struct cipso_v4_doi *doi_def,
|
const struct cipso_v4_doi *doi_def,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
@ -247,6 +252,18 @@ static inline int cipso_v4_sock_getattr(struct sock *sk,
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int cipso_v4_req_setattr(struct request_sock *req,
|
||||||
|
const struct cipso_v4_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cipso_v4_req_delattr(struct request_sock *req)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
|
static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
|
||||||
const struct cipso_v4_doi *doi_def,
|
const struct cipso_v4_doi *doi_def,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
|
#include <net/request_sock.h>
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
struct cipso_v4_doi;
|
struct cipso_v4_doi;
|
||||||
|
@ -406,6 +407,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
|
||||||
*/
|
*/
|
||||||
int netlbl_enabled(void);
|
int netlbl_enabled(void);
|
||||||
int netlbl_sock_setattr(struct sock *sk,
|
int netlbl_sock_setattr(struct sock *sk,
|
||||||
|
u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
void netlbl_sock_delattr(struct sock *sk);
|
void netlbl_sock_delattr(struct sock *sk);
|
||||||
int netlbl_sock_getattr(struct sock *sk,
|
int netlbl_sock_getattr(struct sock *sk,
|
||||||
|
@ -413,6 +415,9 @@ int netlbl_sock_getattr(struct sock *sk,
|
||||||
int netlbl_conn_setattr(struct sock *sk,
|
int netlbl_conn_setattr(struct sock *sk,
|
||||||
struct sockaddr *addr,
|
struct sockaddr *addr,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
int netlbl_req_setattr(struct request_sock *req,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
void netlbl_req_delattr(struct request_sock *req);
|
||||||
int netlbl_skbuff_setattr(struct sk_buff *skb,
|
int netlbl_skbuff_setattr(struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
@ -519,7 +524,8 @@ static inline int netlbl_enabled(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static inline int netlbl_sock_setattr(struct sock *sk,
|
static inline int netlbl_sock_setattr(struct sock *sk,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
u16 family,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
@ -537,6 +543,15 @@ static inline int netlbl_conn_setattr(struct sock *sk,
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
static inline int netlbl_req_setattr(struct request_sock *req,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
static inline void netlbl_req_delattr(struct request_sock *req)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
|
static inline int netlbl_skbuff_setattr(struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
|
|
@ -1942,23 +1942,85 @@ socket_setattr_failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cipso_v4_sock_delattr - Delete the CIPSO option from a socket
|
* cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
|
||||||
* @sk: the socket
|
* @req: the connection request socket
|
||||||
|
* @doi_def: the CIPSO DOI to use
|
||||||
|
* @secattr: the specific security attributes of the socket
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Removes the CIPSO option from a socket, if present.
|
* Set the CIPSO option on the given socket using the DOI definition and
|
||||||
|
* security attributes passed to the function. Returns zero on success and
|
||||||
|
* negative values on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void cipso_v4_sock_delattr(struct sock *sk)
|
int cipso_v4_req_setattr(struct request_sock *req,
|
||||||
|
const struct cipso_v4_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
u8 hdr_delta;
|
int ret_val = -EPERM;
|
||||||
struct ip_options *opt;
|
unsigned char *buf = NULL;
|
||||||
struct inet_sock *sk_inet;
|
u32 buf_len;
|
||||||
|
u32 opt_len;
|
||||||
|
struct ip_options *opt = NULL;
|
||||||
|
struct inet_request_sock *req_inet;
|
||||||
|
|
||||||
sk_inet = inet_sk(sk);
|
/* We allocate the maximum CIPSO option size here so we are probably
|
||||||
opt = sk_inet->opt;
|
* being a little wasteful, but it makes our life _much_ easier later
|
||||||
if (opt == NULL || opt->cipso == 0)
|
* on and after all we are only talking about 40 bytes. */
|
||||||
return;
|
buf_len = CIPSO_V4_OPT_LEN_MAX;
|
||||||
|
buf = kmalloc(buf_len, GFP_ATOMIC);
|
||||||
|
if (buf == NULL) {
|
||||||
|
ret_val = -ENOMEM;
|
||||||
|
goto req_setattr_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
|
||||||
|
if (ret_val < 0)
|
||||||
|
goto req_setattr_failure;
|
||||||
|
buf_len = ret_val;
|
||||||
|
|
||||||
|
/* We can't use ip_options_get() directly because it makes a call to
|
||||||
|
* ip_options_get_alloc() which allocates memory with GFP_KERNEL and
|
||||||
|
* we won't always have CAP_NET_RAW even though we _always_ want to
|
||||||
|
* set the IPOPT_CIPSO option. */
|
||||||
|
opt_len = (buf_len + 3) & ~3;
|
||||||
|
opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
|
||||||
|
if (opt == NULL) {
|
||||||
|
ret_val = -ENOMEM;
|
||||||
|
goto req_setattr_failure;
|
||||||
|
}
|
||||||
|
memcpy(opt->__data, buf, buf_len);
|
||||||
|
opt->optlen = opt_len;
|
||||||
|
opt->cipso = sizeof(struct iphdr);
|
||||||
|
kfree(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
req_inet = inet_rsk(req);
|
||||||
|
opt = xchg(&req_inet->opt, opt);
|
||||||
|
kfree(opt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
req_setattr_failure:
|
||||||
|
kfree(buf);
|
||||||
|
kfree(opt);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cipso_v4_delopt - Delete the CIPSO option from a set of IP options
|
||||||
|
* @opt_ptr: IP option pointer
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Deletes the CIPSO IP option from a set of IP options and makes the necessary
|
||||||
|
* adjustments to the IP option structure. Returns zero on success, negative
|
||||||
|
* values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int cipso_v4_delopt(struct ip_options **opt_ptr)
|
||||||
|
{
|
||||||
|
int hdr_delta = 0;
|
||||||
|
struct ip_options *opt = *opt_ptr;
|
||||||
|
|
||||||
if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
|
if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
|
||||||
u8 cipso_len;
|
u8 cipso_len;
|
||||||
|
@ -2003,11 +2065,34 @@ void cipso_v4_sock_delattr(struct sock *sk)
|
||||||
} else {
|
} else {
|
||||||
/* only the cipso option was present on the socket so we can
|
/* only the cipso option was present on the socket so we can
|
||||||
* remove the entire option struct */
|
* remove the entire option struct */
|
||||||
sk_inet->opt = NULL;
|
*opt_ptr = NULL;
|
||||||
hdr_delta = opt->optlen;
|
hdr_delta = opt->optlen;
|
||||||
kfree(opt);
|
kfree(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return hdr_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cipso_v4_sock_delattr - Delete the CIPSO option from a socket
|
||||||
|
* @sk: the socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes the CIPSO option from a socket, if present.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cipso_v4_sock_delattr(struct sock *sk)
|
||||||
|
{
|
||||||
|
int hdr_delta;
|
||||||
|
struct ip_options *opt;
|
||||||
|
struct inet_sock *sk_inet;
|
||||||
|
|
||||||
|
sk_inet = inet_sk(sk);
|
||||||
|
opt = sk_inet->opt;
|
||||||
|
if (opt == NULL || opt->cipso == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hdr_delta = cipso_v4_delopt(&sk_inet->opt);
|
||||||
if (sk_inet->is_icsk && hdr_delta > 0) {
|
if (sk_inet->is_icsk && hdr_delta > 0) {
|
||||||
struct inet_connection_sock *sk_conn = inet_csk(sk);
|
struct inet_connection_sock *sk_conn = inet_csk(sk);
|
||||||
sk_conn->icsk_ext_hdr_len -= hdr_delta;
|
sk_conn->icsk_ext_hdr_len -= hdr_delta;
|
||||||
|
@ -2015,6 +2100,27 @@ void cipso_v4_sock_delattr(struct sock *sk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cipso_v4_req_delattr - Delete the CIPSO option from a request socket
|
||||||
|
* @reg: the request socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes the CIPSO option from a request socket, if present.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cipso_v4_req_delattr(struct request_sock *req)
|
||||||
|
{
|
||||||
|
struct ip_options *opt;
|
||||||
|
struct inet_request_sock *req_inet;
|
||||||
|
|
||||||
|
req_inet = inet_rsk(req);
|
||||||
|
opt = req_inet->opt;
|
||||||
|
if (opt == NULL || opt->cipso == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cipso_v4_delopt(&req_inet->opt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
|
* cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
|
||||||
* @cipso: the CIPSO v4 option
|
* @cipso: the CIPSO v4 option
|
||||||
|
|
|
@ -288,10 +288,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
||||||
if (!req)
|
if (!req)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (security_inet_conn_request(sk, skb, req)) {
|
|
||||||
reqsk_free(req);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ireq = inet_rsk(req);
|
ireq = inet_rsk(req);
|
||||||
treq = tcp_rsk(req);
|
treq = tcp_rsk(req);
|
||||||
treq->rcv_isn = ntohl(th->seq) - 1;
|
treq->rcv_isn = ntohl(th->seq) - 1;
|
||||||
|
@ -322,6 +318,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (security_inet_conn_request(sk, skb, req)) {
|
||||||
|
reqsk_free(req);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
req->expires = 0UL;
|
req->expires = 0UL;
|
||||||
req->retrans = 0;
|
req->retrans = 0;
|
||||||
|
|
||||||
|
|
|
@ -1230,14 +1230,15 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
|
||||||
|
|
||||||
tcp_openreq_init(req, &tmp_opt, skb);
|
tcp_openreq_init(req, &tmp_opt, skb);
|
||||||
|
|
||||||
if (security_inet_conn_request(sk, skb, req))
|
|
||||||
goto drop_and_free;
|
|
||||||
|
|
||||||
ireq = inet_rsk(req);
|
ireq = inet_rsk(req);
|
||||||
ireq->loc_addr = daddr;
|
ireq->loc_addr = daddr;
|
||||||
ireq->rmt_addr = saddr;
|
ireq->rmt_addr = saddr;
|
||||||
ireq->no_srccheck = inet_sk(sk)->transparent;
|
ireq->no_srccheck = inet_sk(sk)->transparent;
|
||||||
ireq->opt = tcp_v4_save_options(sk, skb);
|
ireq->opt = tcp_v4_save_options(sk, skb);
|
||||||
|
|
||||||
|
if (security_inet_conn_request(sk, skb, req))
|
||||||
|
goto drop_and_free;
|
||||||
|
|
||||||
if (!want_cookie)
|
if (!want_cookie)
|
||||||
TCP_ECN_create_request(req, tcp_hdr(skb));
|
TCP_ECN_create_request(req, tcp_hdr(skb));
|
||||||
|
|
||||||
|
|
|
@ -619,8 +619,9 @@ int netlbl_enabled(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_socket_setattr - Label a socket using the correct protocol
|
* netlbl_sock_setattr - Label a socket using the correct protocol
|
||||||
* @sk: the socket to label
|
* @sk: the socket to label
|
||||||
|
* @family: protocol family
|
||||||
* @secattr: the security attributes
|
* @secattr: the security attributes
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
|
@ -633,29 +634,45 @@ int netlbl_enabled(void)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int netlbl_sock_setattr(struct sock *sk,
|
int netlbl_sock_setattr(struct sock *sk,
|
||||||
|
u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
int ret_val = -ENOENT;
|
int ret_val;
|
||||||
struct netlbl_dom_map *dom_entry;
|
struct netlbl_dom_map *dom_entry;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
||||||
if (dom_entry == NULL)
|
if (dom_entry == NULL) {
|
||||||
|
ret_val = -ENOENT;
|
||||||
goto socket_setattr_return;
|
goto socket_setattr_return;
|
||||||
switch (dom_entry->type) {
|
}
|
||||||
case NETLBL_NLTYPE_ADDRSELECT:
|
switch (family) {
|
||||||
ret_val = -EDESTADDRREQ;
|
case AF_INET:
|
||||||
|
switch (dom_entry->type) {
|
||||||
|
case NETLBL_NLTYPE_ADDRSELECT:
|
||||||
|
ret_val = -EDESTADDRREQ;
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_CIPSOV4:
|
||||||
|
ret_val = cipso_v4_sock_setattr(sk,
|
||||||
|
dom_entry->type_def.cipsov4,
|
||||||
|
secattr);
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
ret_val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_CIPSOV4:
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
ret_val = cipso_v4_sock_setattr(sk,
|
case AF_INET6:
|
||||||
dom_entry->type_def.cipsov4,
|
/* since we don't support any IPv6 labeling protocols right
|
||||||
secattr);
|
* now we can optimize everything away until we do */
|
||||||
break;
|
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
|
||||||
ret_val = 0;
|
ret_val = 0;
|
||||||
break;
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
ret_val = -ENOENT;
|
ret_val = -EPROTONOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_setattr_return:
|
socket_setattr_return:
|
||||||
|
@ -689,9 +706,25 @@ void netlbl_sock_delattr(struct sock *sk)
|
||||||
* on failure.
|
* on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
|
int netlbl_sock_getattr(struct sock *sk,
|
||||||
|
struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
return cipso_v4_sock_getattr(sk, secattr);
|
int ret_val;
|
||||||
|
|
||||||
|
switch (sk->sk_family) {
|
||||||
|
case AF_INET:
|
||||||
|
ret_val = cipso_v4_sock_getattr(sk, secattr);
|
||||||
|
break;
|
||||||
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
|
case AF_INET6:
|
||||||
|
ret_val = -ENOMSG;
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
default:
|
||||||
|
ret_val = -EPROTONOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -748,7 +781,7 @@ int netlbl_conn_setattr(struct sock *sk,
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
ret_val = 0;
|
ret_val = -EPROTONOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn_setattr_return:
|
conn_setattr_return:
|
||||||
|
@ -756,6 +789,90 @@ conn_setattr_return:
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_req_setattr - Label a request socket using the correct protocol
|
||||||
|
* @req: the request socket to label
|
||||||
|
* @secattr: the security attributes
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Attach the correct label to the given socket using the security attributes
|
||||||
|
* specified in @secattr. Returns zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int netlbl_req_setattr(struct request_sock *req,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
int ret_val;
|
||||||
|
struct netlbl_dom_map *dom_entry;
|
||||||
|
struct netlbl_domaddr4_map *af4_entry;
|
||||||
|
u32 proto_type;
|
||||||
|
struct cipso_v4_doi *proto_cv4;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
||||||
|
if (dom_entry == NULL) {
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
goto req_setattr_return;
|
||||||
|
}
|
||||||
|
switch (req->rsk_ops->family) {
|
||||||
|
case AF_INET:
|
||||||
|
if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) {
|
||||||
|
struct inet_request_sock *req_inet = inet_rsk(req);
|
||||||
|
af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
|
||||||
|
req_inet->rmt_addr);
|
||||||
|
if (af4_entry == NULL) {
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
goto req_setattr_return;
|
||||||
|
}
|
||||||
|
proto_type = af4_entry->type;
|
||||||
|
proto_cv4 = af4_entry->type_def.cipsov4;
|
||||||
|
} else {
|
||||||
|
proto_type = dom_entry->type;
|
||||||
|
proto_cv4 = dom_entry->type_def.cipsov4;
|
||||||
|
}
|
||||||
|
switch (proto_type) {
|
||||||
|
case NETLBL_NLTYPE_CIPSOV4:
|
||||||
|
ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr);
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
/* just delete the protocols we support for right now
|
||||||
|
* but we could remove other protocols if needed */
|
||||||
|
cipso_v4_req_delattr(req);
|
||||||
|
ret_val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
|
case AF_INET6:
|
||||||
|
/* since we don't support any IPv6 labeling protocols right
|
||||||
|
* now we can optimize everything away until we do */
|
||||||
|
ret_val = 0;
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
default:
|
||||||
|
ret_val = -EPROTONOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
req_setattr_return:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_req_delattr - Delete all the NetLabel labels on a socket
|
||||||
|
* @req: the socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Remove all the NetLabel labeling from @req.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void netlbl_req_delattr(struct request_sock *req)
|
||||||
|
{
|
||||||
|
cipso_v4_req_delattr(req);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_skbuff_setattr - Label a packet using the correct protocol
|
* netlbl_skbuff_setattr - Label a packet using the correct protocol
|
||||||
* @skb: the packet
|
* @skb: the packet
|
||||||
|
@ -808,7 +925,7 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
ret_val = 0;
|
ret_val = -EPROTONOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
skbuff_setattr_return:
|
skbuff_setattr_return:
|
||||||
|
@ -833,9 +950,17 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
struct netlbl_lsm_secattr *secattr)
|
struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
if (CIPSO_V4_OPTEXIST(skb) &&
|
switch (family) {
|
||||||
cipso_v4_skbuff_getattr(skb, secattr) == 0)
|
case AF_INET:
|
||||||
return 0;
|
if (CIPSO_V4_OPTEXIST(skb) &&
|
||||||
|
cipso_v4_skbuff_getattr(skb, secattr) == 0)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
|
case AF_INET6:
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
|
|
||||||
return netlbl_unlabel_getattr(skb, family, secattr);
|
return netlbl_unlabel_getattr(skb, family, secattr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1536,8 +1536,6 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
|
||||||
fd_install(newfd, newfile);
|
fd_install(newfd, newfile);
|
||||||
err = newfd;
|
err = newfd;
|
||||||
|
|
||||||
security_socket_post_accept(sock, newsock);
|
|
||||||
|
|
||||||
out_put:
|
out_put:
|
||||||
fput_light(sock->file, fput_needed);
|
fput_light(sock->file, fput_needed);
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -620,10 +620,6 @@ static int cap_socket_accept(struct socket *sock, struct socket *newsock)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cap_socket_post_accept(struct socket *sock, struct socket *newsock)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
|
static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1014,7 +1010,6 @@ void security_fixup_ops(struct security_operations *ops)
|
||||||
set_to_cap_if_null(ops, socket_connect);
|
set_to_cap_if_null(ops, socket_connect);
|
||||||
set_to_cap_if_null(ops, socket_listen);
|
set_to_cap_if_null(ops, socket_listen);
|
||||||
set_to_cap_if_null(ops, socket_accept);
|
set_to_cap_if_null(ops, socket_accept);
|
||||||
set_to_cap_if_null(ops, socket_post_accept);
|
|
||||||
set_to_cap_if_null(ops, socket_sendmsg);
|
set_to_cap_if_null(ops, socket_sendmsg);
|
||||||
set_to_cap_if_null(ops, socket_recvmsg);
|
set_to_cap_if_null(ops, socket_recvmsg);
|
||||||
set_to_cap_if_null(ops, socket_getsockname);
|
set_to_cap_if_null(ops, socket_getsockname);
|
||||||
|
|
|
@ -1007,11 +1007,6 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
|
||||||
return security_ops->socket_accept(sock, newsock);
|
return security_ops->socket_accept(sock, newsock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void security_socket_post_accept(struct socket *sock, struct socket *newsock)
|
|
||||||
{
|
|
||||||
security_ops->socket_post_accept(sock, newsock);
|
|
||||||
}
|
|
||||||
|
|
||||||
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
|
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
|
||||||
{
|
{
|
||||||
return security_ops->socket_sendmsg(sock, msg, size);
|
return security_ops->socket_sendmsg(sock, msg, size);
|
||||||
|
|
|
@ -93,7 +93,6 @@
|
||||||
|
|
||||||
extern unsigned int policydb_loaded_version;
|
extern unsigned int policydb_loaded_version;
|
||||||
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
|
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
|
||||||
extern int selinux_compat_net;
|
|
||||||
extern struct security_operations *security_ops;
|
extern struct security_operations *security_ops;
|
||||||
|
|
||||||
/* SECMARK reference count */
|
/* SECMARK reference count */
|
||||||
|
@ -311,7 +310,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
|
||||||
ssec->sid = SECINITSID_UNLABELED;
|
ssec->sid = SECINITSID_UNLABELED;
|
||||||
sk->sk_security = ssec;
|
sk->sk_security = ssec;
|
||||||
|
|
||||||
selinux_netlbl_sk_security_reset(ssec, family);
|
selinux_netlbl_sk_security_reset(ssec);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2945,7 +2944,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
|
||||||
static int selinux_revalidate_file_permission(struct file *file, int mask)
|
static int selinux_revalidate_file_permission(struct file *file, int mask)
|
||||||
{
|
{
|
||||||
const struct cred *cred = current_cred();
|
const struct cred *cred = current_cred();
|
||||||
int rc;
|
|
||||||
struct inode *inode = file->f_path.dentry->d_inode;
|
struct inode *inode = file->f_path.dentry->d_inode;
|
||||||
|
|
||||||
if (!mask) {
|
if (!mask) {
|
||||||
|
@ -2957,29 +2955,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
|
||||||
if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
|
if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
|
||||||
mask |= MAY_APPEND;
|
mask |= MAY_APPEND;
|
||||||
|
|
||||||
rc = file_has_perm(cred, file,
|
return file_has_perm(cred, file,
|
||||||
file_mask_to_av(inode->i_mode, mask));
|
file_mask_to_av(inode->i_mode, mask));
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
return selinux_netlbl_inode_permission(inode, mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_file_permission(struct file *file, int mask)
|
static int selinux_file_permission(struct file *file, int mask)
|
||||||
{
|
{
|
||||||
struct inode *inode = file->f_path.dentry->d_inode;
|
if (!mask)
|
||||||
struct file_security_struct *fsec = file->f_security;
|
|
||||||
struct inode_security_struct *isec = inode->i_security;
|
|
||||||
u32 sid = current_sid();
|
|
||||||
|
|
||||||
if (!mask) {
|
|
||||||
/* No permission to check. Existence test. */
|
/* No permission to check. Existence test. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (sid == fsec->sid && fsec->isid == isec->sid
|
|
||||||
&& fsec->pseqno == avc_policy_seqno())
|
|
||||||
return selinux_netlbl_inode_permission(inode, mask);
|
|
||||||
|
|
||||||
return selinux_revalidate_file_permission(file, mask);
|
return selinux_revalidate_file_permission(file, mask);
|
||||||
}
|
}
|
||||||
|
@ -3723,7 +3707,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
|
||||||
sksec = sock->sk->sk_security;
|
sksec = sock->sk->sk_security;
|
||||||
sksec->sid = isec->sid;
|
sksec->sid = isec->sid;
|
||||||
sksec->sclass = isec->sclass;
|
sksec->sclass = isec->sclass;
|
||||||
err = selinux_netlbl_socket_post_create(sock);
|
err = selinux_netlbl_socket_post_create(sock->sk, family);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -3914,13 +3898,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
|
||||||
static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
int rc;
|
return socket_has_perm(current, sock, SOCKET__WRITE);
|
||||||
|
|
||||||
rc = socket_has_perm(current, sock, SOCKET__WRITE);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
|
static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||||
|
@ -4040,72 +4018,6 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
|
||||||
SECCLASS_NODE, NODE__RECVFROM, ad);
|
SECCLASS_NODE, NODE__RECVFROM, ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
|
|
||||||
struct sk_buff *skb,
|
|
||||||
struct avc_audit_data *ad,
|
|
||||||
u16 family,
|
|
||||||
char *addrp)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
|
||||||
u16 sk_class;
|
|
||||||
u32 netif_perm, node_perm, recv_perm;
|
|
||||||
u32 port_sid, node_sid, if_sid, sk_sid;
|
|
||||||
|
|
||||||
sk_sid = sksec->sid;
|
|
||||||
sk_class = sksec->sclass;
|
|
||||||
|
|
||||||
switch (sk_class) {
|
|
||||||
case SECCLASS_UDP_SOCKET:
|
|
||||||
netif_perm = NETIF__UDP_RECV;
|
|
||||||
node_perm = NODE__UDP_RECV;
|
|
||||||
recv_perm = UDP_SOCKET__RECV_MSG;
|
|
||||||
break;
|
|
||||||
case SECCLASS_TCP_SOCKET:
|
|
||||||
netif_perm = NETIF__TCP_RECV;
|
|
||||||
node_perm = NODE__TCP_RECV;
|
|
||||||
recv_perm = TCP_SOCKET__RECV_MSG;
|
|
||||||
break;
|
|
||||||
case SECCLASS_DCCP_SOCKET:
|
|
||||||
netif_perm = NETIF__DCCP_RECV;
|
|
||||||
node_perm = NODE__DCCP_RECV;
|
|
||||||
recv_perm = DCCP_SOCKET__RECV_MSG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
netif_perm = NETIF__RAWIP_RECV;
|
|
||||||
node_perm = NODE__RAWIP_RECV;
|
|
||||||
recv_perm = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sel_netif_sid(skb->iif, &if_sid);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = sel_netnode_sid(addrp, family, &node_sid);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (!recv_perm)
|
|
||||||
return 0;
|
|
||||||
err = sel_netport_sid(sk->sk_protocol,
|
|
||||||
ntohs(ad->u.net.sport), &port_sid);
|
|
||||||
if (unlikely(err)) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"SELinux: failure in"
|
|
||||||
" selinux_sock_rcv_skb_iptables_compat(),"
|
|
||||||
" network port label not found\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
||||||
u16 family)
|
u16 family)
|
||||||
{
|
{
|
||||||
|
@ -4123,14 +4035,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (selinux_compat_net)
|
if (selinux_secmark_enabled()) {
|
||||||
err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
|
|
||||||
family, addrp);
|
|
||||||
else if (selinux_secmark_enabled())
|
|
||||||
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
|
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
|
||||||
PACKET__RECV, &ad);
|
PACKET__RECV, &ad);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (selinux_policycap_netpeer) {
|
if (selinux_policycap_netpeer) {
|
||||||
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
|
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
|
||||||
|
@ -4172,7 +4082,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
* to the selinux_sock_rcv_skb_compat() function to deal with the
|
* to the selinux_sock_rcv_skb_compat() function to deal with the
|
||||||
* special handling. We do this in an attempt to keep this function
|
* special handling. We do this in an attempt to keep this function
|
||||||
* as fast and as clean as possible. */
|
* as fast and as clean as possible. */
|
||||||
if (selinux_compat_net || !selinux_policycap_netpeer)
|
if (!selinux_policycap_netpeer)
|
||||||
return selinux_sock_rcv_skb_compat(sk, skb, family);
|
return selinux_sock_rcv_skb_compat(sk, skb, family);
|
||||||
|
|
||||||
secmark_active = selinux_secmark_enabled();
|
secmark_active = selinux_secmark_enabled();
|
||||||
|
@ -4304,7 +4214,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
|
||||||
newssec->peer_sid = ssec->peer_sid;
|
newssec->peer_sid = ssec->peer_sid;
|
||||||
newssec->sclass = ssec->sclass;
|
newssec->sclass = ssec->sclass;
|
||||||
|
|
||||||
selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
|
selinux_netlbl_sk_security_reset(newssec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
|
static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
|
||||||
|
@ -4348,16 +4258,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
if (peersid == SECSID_NULL) {
|
if (peersid == SECSID_NULL) {
|
||||||
req->secid = sksec->sid;
|
req->secid = sksec->sid;
|
||||||
req->peer_secid = SECSID_NULL;
|
req->peer_secid = SECSID_NULL;
|
||||||
return 0;
|
} else {
|
||||||
|
err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
req->secid = newsid;
|
||||||
|
req->peer_secid = peersid;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
|
return selinux_netlbl_inet_conn_request(req, family);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
req->secid = newsid;
|
|
||||||
req->peer_secid = peersid;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selinux_inet_csk_clone(struct sock *newsk,
|
static void selinux_inet_csk_clone(struct sock *newsk,
|
||||||
|
@ -4374,7 +4283,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
|
||||||
|
|
||||||
/* We don't need to take any sort of lock here as we are the only
|
/* We don't need to take any sort of lock here as we are the only
|
||||||
* thread with access to newsksec */
|
* thread with access to newsksec */
|
||||||
selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
|
selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
|
static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
|
||||||
|
@ -4387,8 +4296,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
|
||||||
family = PF_INET;
|
family = PF_INET;
|
||||||
|
|
||||||
selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
|
selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
|
||||||
|
|
||||||
selinux_netlbl_inet_conn_established(sk, family);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selinux_req_classify_flow(const struct request_sock *req,
|
static void selinux_req_classify_flow(const struct request_sock *req,
|
||||||
|
@ -4540,71 +4447,6 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum,
|
||||||
return selinux_ip_output(skb, PF_INET);
|
return selinux_ip_output(skb, PF_INET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_ip_postroute_iptables_compat(struct sock *sk,
|
|
||||||
int ifindex,
|
|
||||||
struct avc_audit_data *ad,
|
|
||||||
u16 family, char *addrp)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
|
||||||
u16 sk_class;
|
|
||||||
u32 netif_perm, node_perm, send_perm;
|
|
||||||
u32 port_sid, node_sid, if_sid, sk_sid;
|
|
||||||
|
|
||||||
sk_sid = sksec->sid;
|
|
||||||
sk_class = sksec->sclass;
|
|
||||||
|
|
||||||
switch (sk_class) {
|
|
||||||
case SECCLASS_UDP_SOCKET:
|
|
||||||
netif_perm = NETIF__UDP_SEND;
|
|
||||||
node_perm = NODE__UDP_SEND;
|
|
||||||
send_perm = UDP_SOCKET__SEND_MSG;
|
|
||||||
break;
|
|
||||||
case SECCLASS_TCP_SOCKET:
|
|
||||||
netif_perm = NETIF__TCP_SEND;
|
|
||||||
node_perm = NODE__TCP_SEND;
|
|
||||||
send_perm = TCP_SOCKET__SEND_MSG;
|
|
||||||
break;
|
|
||||||
case SECCLASS_DCCP_SOCKET:
|
|
||||||
netif_perm = NETIF__DCCP_SEND;
|
|
||||||
node_perm = NODE__DCCP_SEND;
|
|
||||||
send_perm = DCCP_SOCKET__SEND_MSG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
netif_perm = NETIF__RAWIP_SEND;
|
|
||||||
node_perm = NODE__RAWIP_SEND;
|
|
||||||
send_perm = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sel_netif_sid(ifindex, &if_sid);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = sel_netnode_sid(addrp, family, &node_sid);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (send_perm != 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err = sel_netport_sid(sk->sk_protocol,
|
|
||||||
ntohs(ad->u.net.dport), &port_sid);
|
|
||||||
if (unlikely(err)) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"SELinux: failure in"
|
|
||||||
" selinux_ip_postroute_iptables_compat(),"
|
|
||||||
" network port label not found\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
u16 family)
|
u16 family)
|
||||||
|
@ -4625,15 +4467,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
||||||
if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
|
if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
if (selinux_compat_net) {
|
if (selinux_secmark_enabled())
|
||||||
if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
|
|
||||||
&ad, family, addrp))
|
|
||||||
return NF_DROP;
|
|
||||||
} else if (selinux_secmark_enabled()) {
|
|
||||||
if (avc_has_perm(sksec->sid, skb->secmark,
|
if (avc_has_perm(sksec->sid, skb->secmark,
|
||||||
SECCLASS_PACKET, PACKET__SEND, &ad))
|
SECCLASS_PACKET, PACKET__SEND, &ad))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
|
||||||
|
|
||||||
if (selinux_policycap_netpeer)
|
if (selinux_policycap_netpeer)
|
||||||
if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
|
if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
|
||||||
|
@ -4657,7 +4494,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
||||||
* to the selinux_ip_postroute_compat() function to deal with the
|
* to the selinux_ip_postroute_compat() function to deal with the
|
||||||
* special handling. We do this in an attempt to keep this function
|
* special handling. We do this in an attempt to keep this function
|
||||||
* as fast and as clean as possible. */
|
* as fast and as clean as possible. */
|
||||||
if (selinux_compat_net || !selinux_policycap_netpeer)
|
if (!selinux_policycap_netpeer)
|
||||||
return selinux_ip_postroute_compat(skb, ifindex, family);
|
return selinux_ip_postroute_compat(skb, ifindex, family);
|
||||||
#ifdef CONFIG_XFRM
|
#ifdef CONFIG_XFRM
|
||||||
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
|
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/net.h>
|
#include <linux/net.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
#include <net/request_sock.h>
|
||||||
|
|
||||||
#include "avc.h"
|
#include "avc.h"
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
|
@ -42,8 +43,7 @@ void selinux_netlbl_cache_invalidate(void);
|
||||||
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
|
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
|
||||||
|
|
||||||
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
|
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
|
||||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
|
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec);
|
||||||
int family);
|
|
||||||
|
|
||||||
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
|
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
|
@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
u32 sid);
|
u32 sid);
|
||||||
|
|
||||||
void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
|
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
|
||||||
int selinux_netlbl_socket_post_create(struct socket *sock);
|
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
|
||||||
int selinux_netlbl_inode_permission(struct inode *inode, int mask);
|
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
|
||||||
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
|
@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free(
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void selinux_netlbl_sk_security_reset(
|
static inline void selinux_netlbl_sk_security_reset(
|
||||||
struct sk_security_struct *ssec,
|
struct sk_security_struct *ssec)
|
||||||
int family)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
|
static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
|
||||||
u16 family)
|
u16 family)
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
static inline int selinux_netlbl_socket_post_create(struct socket *sock)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static inline int selinux_netlbl_inode_permission(struct inode *inode,
|
static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
|
||||||
int mask)
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static inline int selinux_netlbl_socket_post_create(struct sock *sk,
|
||||||
|
u16 family)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,41 +99,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
|
||||||
return secattr;
|
return secattr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
|
|
||||||
* @sk: the socket to label
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Attempt to label a socket using the NetLabel mechanism. Returns zero values
|
|
||||||
* on success, negative values on failure.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int selinux_netlbl_sock_setsid(struct sock *sk)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
|
||||||
struct netlbl_lsm_secattr *secattr;
|
|
||||||
|
|
||||||
if (sksec->nlbl_state != NLBL_REQUIRE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
secattr = selinux_netlbl_sock_genattr(sk);
|
|
||||||
if (secattr == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
rc = netlbl_sock_setattr(sk, secattr);
|
|
||||||
switch (rc) {
|
|
||||||
case 0:
|
|
||||||
sksec->nlbl_state = NLBL_LABELED;
|
|
||||||
break;
|
|
||||||
case -EDESTADDRREQ:
|
|
||||||
sksec->nlbl_state = NLBL_REQSKB;
|
|
||||||
rc = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
||||||
*
|
*
|
||||||
|
@ -188,13 +153,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
|
||||||
* The caller is responsibile for all the NetLabel sk_security_struct locking.
|
* The caller is responsibile for all the NetLabel sk_security_struct locking.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
|
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
|
||||||
int family)
|
|
||||||
{
|
{
|
||||||
if (family == PF_INET)
|
ssec->nlbl_state = NLBL_UNSET;
|
||||||
ssec->nlbl_state = NLBL_REQUIRE;
|
|
||||||
else
|
|
||||||
ssec->nlbl_state = NLBL_UNSET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,127 +242,86 @@ skbuff_setsid_return:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
|
* selinux_netlbl_inet_conn_request - Label an incoming stream connection
|
||||||
* @sk: the new connection
|
* @req: incoming connection request socket
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* A new connection has been established on @sk so make sure it is labeled
|
* A new incoming connection request is represented by @req, we need to label
|
||||||
* correctly with the NetLabel susbsystem.
|
* the new request_sock here and the stack will ensure the on-the-wire label
|
||||||
|
* will get preserved when a full sock is created once the connection handshake
|
||||||
|
* is complete. Returns zero on success, negative values on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
|
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
struct netlbl_lsm_secattr secattr;
|
||||||
|
|
||||||
|
if (family != PF_INET)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
netlbl_secattr_init(&secattr);
|
||||||
|
rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
|
||||||
|
if (rc != 0)
|
||||||
|
goto inet_conn_request_return;
|
||||||
|
rc = netlbl_req_setattr(req, &secattr);
|
||||||
|
inet_conn_request_return:
|
||||||
|
netlbl_secattr_destroy(&secattr);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* selinux_netlbl_inet_csk_clone - Initialize the newly created sock
|
||||||
|
* @sk: the new sock
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* A new connection has been established using @sk, we've already labeled the
|
||||||
|
* socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
|
||||||
|
* we need to set the NetLabel state here since we now have a sock structure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
|
||||||
|
{
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
struct netlbl_lsm_secattr *secattr;
|
|
||||||
struct inet_sock *sk_inet = inet_sk(sk);
|
|
||||||
struct sockaddr_in addr;
|
|
||||||
|
|
||||||
if (sksec->nlbl_state != NLBL_REQUIRE)
|
if (family == PF_INET)
|
||||||
return;
|
|
||||||
|
|
||||||
secattr = selinux_netlbl_sock_genattr(sk);
|
|
||||||
if (secattr == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rc = netlbl_sock_setattr(sk, secattr);
|
|
||||||
switch (rc) {
|
|
||||||
case 0:
|
|
||||||
sksec->nlbl_state = NLBL_LABELED;
|
sksec->nlbl_state = NLBL_LABELED;
|
||||||
break;
|
else
|
||||||
case -EDESTADDRREQ:
|
sksec->nlbl_state = NLBL_UNSET;
|
||||||
/* no PF_INET6 support yet because we don't support any IPv6
|
|
||||||
* labeling protocols */
|
|
||||||
if (family != PF_INET) {
|
|
||||||
sksec->nlbl_state = NLBL_UNSET;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.sin_family = family;
|
|
||||||
addr.sin_addr.s_addr = sk_inet->daddr;
|
|
||||||
if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
|
|
||||||
secattr) != 0) {
|
|
||||||
/* we failed to label the connected socket (could be
|
|
||||||
* for a variety of reasons, the actual "why" isn't
|
|
||||||
* important here) so we have to go to our backup plan,
|
|
||||||
* labeling the packets individually in the netfilter
|
|
||||||
* local output hook. this is okay but we need to
|
|
||||||
* adjust the MSS of the connection to take into
|
|
||||||
* account any labeling overhead, since we don't know
|
|
||||||
* the exact overhead at this point we'll use the worst
|
|
||||||
* case value which is 40 bytes for IPv4 */
|
|
||||||
struct inet_connection_sock *sk_conn = inet_csk(sk);
|
|
||||||
sk_conn->icsk_ext_hdr_len += 40 -
|
|
||||||
(sk_inet->opt ? sk_inet->opt->optlen : 0);
|
|
||||||
sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
|
|
||||||
|
|
||||||
sksec->nlbl_state = NLBL_REQSKB;
|
|
||||||
} else
|
|
||||||
sksec->nlbl_state = NLBL_CONNLABELED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* note that we are failing to label the socket which could be
|
|
||||||
* a bad thing since it means traffic could leave the system
|
|
||||||
* without the desired labeling, however, all is not lost as
|
|
||||||
* we have a check in selinux_netlbl_inode_permission() to
|
|
||||||
* pick up the pieces that we might drop here because we can't
|
|
||||||
* return an error code */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* selinux_netlbl_socket_post_create - Label a socket using NetLabel
|
* selinux_netlbl_socket_post_create - Label a socket using NetLabel
|
||||||
* @sock: the socket to label
|
* @sock: the socket to label
|
||||||
|
* @family: protocol family
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Attempt to label a socket using the NetLabel mechanism using the given
|
* Attempt to label a socket using the NetLabel mechanism using the given
|
||||||
* SID. Returns zero values on success, negative values on failure.
|
* SID. Returns zero values on success, negative values on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int selinux_netlbl_socket_post_create(struct socket *sock)
|
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
|
||||||
{
|
|
||||||
return selinux_netlbl_sock_setsid(sock->sk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
|
|
||||||
* @inode: the file descriptor's inode
|
|
||||||
* @mask: the permission mask
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Looks at a file's inode and if it is marked as a socket protected by
|
|
||||||
* NetLabel then verify that the socket has been labeled, if not try to label
|
|
||||||
* the socket now with the inode's SID. Returns zero on success, negative
|
|
||||||
* values on failure.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
int selinux_netlbl_inode_permission(struct inode *inode, int mask)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct sock *sk;
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
struct socket *sock;
|
struct netlbl_lsm_secattr *secattr;
|
||||||
struct sk_security_struct *sksec;
|
|
||||||
|
|
||||||
if (!S_ISSOCK(inode->i_mode) ||
|
if (family != PF_INET)
|
||||||
((mask & (MAY_WRITE | MAY_APPEND)) == 0))
|
|
||||||
return 0;
|
|
||||||
sock = SOCKET_I(inode);
|
|
||||||
sk = sock->sk;
|
|
||||||
if (sk == NULL)
|
|
||||||
return 0;
|
|
||||||
sksec = sk->sk_security;
|
|
||||||
if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
local_bh_disable();
|
secattr = selinux_netlbl_sock_genattr(sk);
|
||||||
bh_lock_sock_nested(sk);
|
if (secattr == NULL)
|
||||||
if (likely(sksec->nlbl_state == NLBL_REQUIRE))
|
return -ENOMEM;
|
||||||
rc = selinux_netlbl_sock_setsid(sk);
|
rc = netlbl_sock_setattr(sk, family, secattr);
|
||||||
else
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
sksec->nlbl_state = NLBL_LABELED;
|
||||||
|
break;
|
||||||
|
case -EDESTADDRREQ:
|
||||||
|
sksec->nlbl_state = NLBL_REQSKB;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
bh_unlock_sock(sk);
|
break;
|
||||||
local_bh_enable();
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ static char *policycap_names[] = {
|
||||||
|
|
||||||
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
|
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
|
||||||
|
|
||||||
int selinux_compat_net = 0;
|
|
||||||
|
|
||||||
static int __init checkreqprot_setup(char *str)
|
static int __init checkreqprot_setup(char *str)
|
||||||
{
|
{
|
||||||
unsigned long checkreqprot;
|
unsigned long checkreqprot;
|
||||||
|
@ -58,16 +56,6 @@ static int __init checkreqprot_setup(char *str)
|
||||||
}
|
}
|
||||||
__setup("checkreqprot=", checkreqprot_setup);
|
__setup("checkreqprot=", checkreqprot_setup);
|
||||||
|
|
||||||
static int __init selinux_compat_net_setup(char *str)
|
|
||||||
{
|
|
||||||
unsigned long compat_net;
|
|
||||||
if (!strict_strtoul(str, 0, &compat_net))
|
|
||||||
selinux_compat_net = compat_net ? 1 : 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
__setup("selinux_compat_net=", selinux_compat_net_setup);
|
|
||||||
|
|
||||||
|
|
||||||
static DEFINE_MUTEX(sel_mutex);
|
static DEFINE_MUTEX(sel_mutex);
|
||||||
|
|
||||||
/* global data for booleans */
|
/* global data for booleans */
|
||||||
|
@ -450,61 +438,6 @@ static const struct file_operations sel_checkreqprot_ops = {
|
||||||
.write = sel_write_checkreqprot,
|
.write = sel_write_checkreqprot,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t sel_read_compat_net(struct file *filp, char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
char tmpbuf[TMPBUFLEN];
|
|
||||||
ssize_t length;
|
|
||||||
|
|
||||||
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_compat_net);
|
|
||||||
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t sel_write_compat_net(struct file *file, const char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
char *page;
|
|
||||||
ssize_t length;
|
|
||||||
int new_value;
|
|
||||||
|
|
||||||
length = task_has_security(current, SECURITY__LOAD_POLICY);
|
|
||||||
if (length)
|
|
||||||
return length;
|
|
||||||
|
|
||||||
if (count >= PAGE_SIZE)
|
|
||||||
return -ENOMEM;
|
|
||||||
if (*ppos != 0) {
|
|
||||||
/* No partial writes. */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
page = (char *)get_zeroed_page(GFP_KERNEL);
|
|
||||||
if (!page)
|
|
||||||
return -ENOMEM;
|
|
||||||
length = -EFAULT;
|
|
||||||
if (copy_from_user(page, buf, count))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
length = -EINVAL;
|
|
||||||
if (sscanf(page, "%d", &new_value) != 1)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (new_value) {
|
|
||||||
printk(KERN_NOTICE
|
|
||||||
"SELinux: compat_net is deprecated, please use secmark"
|
|
||||||
" instead\n");
|
|
||||||
selinux_compat_net = 1;
|
|
||||||
} else
|
|
||||||
selinux_compat_net = 0;
|
|
||||||
length = count;
|
|
||||||
out:
|
|
||||||
free_page((unsigned long) page);
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
static const struct file_operations sel_compat_net_ops = {
|
|
||||||
.read = sel_read_compat_net,
|
|
||||||
.write = sel_write_compat_net,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
|
* Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
|
||||||
*/
|
*/
|
||||||
|
@ -1665,7 +1598,6 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
|
[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
|
||||||
[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
|
[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
|
||||||
[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
|
[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
|
||||||
[SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR},
|
|
||||||
[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
||||||
[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
||||||
/* last one */ {""}
|
/* last one */ {""}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
#include <net/netlabel.h>
|
#include <net/netlabel.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/rculist.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
|
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
|
||||||
|
@ -40,7 +42,6 @@ struct superblock_smack {
|
||||||
struct socket_smack {
|
struct socket_smack {
|
||||||
char *smk_out; /* outbound label */
|
char *smk_out; /* outbound label */
|
||||||
char *smk_in; /* inbound label */
|
char *smk_in; /* inbound label */
|
||||||
int smk_labeled; /* label scheme */
|
|
||||||
char smk_packet[SMK_LABELLEN]; /* TCP peer label */
|
char smk_packet[SMK_LABELLEN]; /* TCP peer label */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,17 +60,10 @@ struct inode_smack {
|
||||||
* A label access rule.
|
* A label access rule.
|
||||||
*/
|
*/
|
||||||
struct smack_rule {
|
struct smack_rule {
|
||||||
char *smk_subject;
|
struct list_head list;
|
||||||
char *smk_object;
|
char *smk_subject;
|
||||||
int smk_access;
|
char *smk_object;
|
||||||
};
|
int smk_access;
|
||||||
|
|
||||||
/*
|
|
||||||
* An entry in the table of permitted label accesses.
|
|
||||||
*/
|
|
||||||
struct smk_list_entry {
|
|
||||||
struct smk_list_entry *smk_next;
|
|
||||||
struct smack_rule smk_rule;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,7 +79,7 @@ struct smack_cipso {
|
||||||
* An entry in the table identifying hosts.
|
* An entry in the table identifying hosts.
|
||||||
*/
|
*/
|
||||||
struct smk_netlbladdr {
|
struct smk_netlbladdr {
|
||||||
struct smk_netlbladdr *smk_next;
|
struct list_head list;
|
||||||
struct sockaddr_in smk_host; /* network address */
|
struct sockaddr_in smk_host; /* network address */
|
||||||
struct in_addr smk_mask; /* network mask */
|
struct in_addr smk_mask; /* network mask */
|
||||||
char *smk_label; /* label */
|
char *smk_label; /* label */
|
||||||
|
@ -113,7 +107,7 @@ struct smk_netlbladdr {
|
||||||
* the cipso direct mapping in used internally.
|
* the cipso direct mapping in used internally.
|
||||||
*/
|
*/
|
||||||
struct smack_known {
|
struct smack_known {
|
||||||
struct smack_known *smk_next;
|
struct list_head list;
|
||||||
char smk_known[SMK_LABELLEN];
|
char smk_known[SMK_LABELLEN];
|
||||||
u32 smk_secid;
|
u32 smk_secid;
|
||||||
struct smack_cipso *smk_cipso;
|
struct smack_cipso *smk_cipso;
|
||||||
|
@ -138,6 +132,8 @@ struct smack_known {
|
||||||
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
|
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
|
||||||
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
|
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
|
||||||
|
|
||||||
|
#define SMACK_CIPSO_OPTION "-CIPSO"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* How communications on this socket are treated.
|
* How communications on this socket are treated.
|
||||||
* Usually it's determined by the underlying netlabel code
|
* Usually it's determined by the underlying netlabel code
|
||||||
|
@ -205,8 +201,8 @@ u32 smack_to_secid(const char *);
|
||||||
extern int smack_cipso_direct;
|
extern int smack_cipso_direct;
|
||||||
extern char *smack_net_ambient;
|
extern char *smack_net_ambient;
|
||||||
extern char *smack_onlycap;
|
extern char *smack_onlycap;
|
||||||
|
extern const char *smack_cipso_option;
|
||||||
|
|
||||||
extern struct smack_known *smack_known;
|
|
||||||
extern struct smack_known smack_known_floor;
|
extern struct smack_known smack_known_floor;
|
||||||
extern struct smack_known smack_known_hat;
|
extern struct smack_known smack_known_hat;
|
||||||
extern struct smack_known smack_known_huh;
|
extern struct smack_known smack_known_huh;
|
||||||
|
@ -214,8 +210,10 @@ extern struct smack_known smack_known_invalid;
|
||||||
extern struct smack_known smack_known_star;
|
extern struct smack_known smack_known_star;
|
||||||
extern struct smack_known smack_known_web;
|
extern struct smack_known smack_known_web;
|
||||||
|
|
||||||
extern struct smk_list_entry *smack_list;
|
extern struct list_head smack_known_list;
|
||||||
extern struct smk_netlbladdr *smack_netlbladdrs;
|
extern struct list_head smack_rule_list;
|
||||||
|
extern struct list_head smk_netlbladdr_list;
|
||||||
|
|
||||||
extern struct security_operations smack_ops;
|
extern struct security_operations smack_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -16,48 +16,42 @@
|
||||||
#include "smack.h"
|
#include "smack.h"
|
||||||
|
|
||||||
struct smack_known smack_known_huh = {
|
struct smack_known smack_known_huh = {
|
||||||
.smk_next = NULL,
|
|
||||||
.smk_known = "?",
|
.smk_known = "?",
|
||||||
.smk_secid = 2,
|
.smk_secid = 2,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_hat = {
|
struct smack_known smack_known_hat = {
|
||||||
.smk_next = &smack_known_huh,
|
|
||||||
.smk_known = "^",
|
.smk_known = "^",
|
||||||
.smk_secid = 3,
|
.smk_secid = 3,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_star = {
|
struct smack_known smack_known_star = {
|
||||||
.smk_next = &smack_known_hat,
|
|
||||||
.smk_known = "*",
|
.smk_known = "*",
|
||||||
.smk_secid = 4,
|
.smk_secid = 4,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_floor = {
|
struct smack_known smack_known_floor = {
|
||||||
.smk_next = &smack_known_star,
|
|
||||||
.smk_known = "_",
|
.smk_known = "_",
|
||||||
.smk_secid = 5,
|
.smk_secid = 5,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_invalid = {
|
struct smack_known smack_known_invalid = {
|
||||||
.smk_next = &smack_known_floor,
|
|
||||||
.smk_known = "",
|
.smk_known = "",
|
||||||
.smk_secid = 6,
|
.smk_secid = 6,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_web = {
|
struct smack_known smack_known_web = {
|
||||||
.smk_next = &smack_known_invalid,
|
|
||||||
.smk_known = "@",
|
.smk_known = "@",
|
||||||
.smk_secid = 7,
|
.smk_secid = 7,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known *smack_known = &smack_known_web;
|
LIST_HEAD(smack_known_list);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The initial value needs to be bigger than any of the
|
* The initial value needs to be bigger than any of the
|
||||||
|
@ -87,7 +81,6 @@ static u32 smack_next_secid = 10;
|
||||||
int smk_access(char *subject_label, char *object_label, int request)
|
int smk_access(char *subject_label, char *object_label, int request)
|
||||||
{
|
{
|
||||||
u32 may = MAY_NOT;
|
u32 may = MAY_NOT;
|
||||||
struct smk_list_entry *sp;
|
|
||||||
struct smack_rule *srp;
|
struct smack_rule *srp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -139,9 +132,8 @@ int smk_access(char *subject_label, char *object_label, int request)
|
||||||
* access (e.g. read is included in readwrite) it's
|
* access (e.g. read is included in readwrite) it's
|
||||||
* good.
|
* good.
|
||||||
*/
|
*/
|
||||||
for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
|
rcu_read_lock();
|
||||||
srp = &sp->smk_rule;
|
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
|
||||||
|
|
||||||
if (srp->smk_subject == subject_label ||
|
if (srp->smk_subject == subject_label ||
|
||||||
strcmp(srp->smk_subject, subject_label) == 0) {
|
strcmp(srp->smk_subject, subject_label) == 0) {
|
||||||
if (srp->smk_object == object_label ||
|
if (srp->smk_object == object_label ||
|
||||||
|
@ -151,6 +143,7 @@ int smk_access(char *subject_label, char *object_label, int request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
/*
|
/*
|
||||||
* This is a bit map operation.
|
* This is a bit map operation.
|
||||||
*/
|
*/
|
||||||
|
@ -228,14 +221,17 @@ struct smack_known *smk_import_entry(const char *string, int len)
|
||||||
|
|
||||||
mutex_lock(&smack_known_lock);
|
mutex_lock(&smack_known_lock);
|
||||||
|
|
||||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
found = 0;
|
||||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
|
list_for_each_entry_rcu(skp, &smack_known_list, list) {
|
||||||
|
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
|
||||||
|
found = 1;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (skp == NULL) {
|
if (found == 0) {
|
||||||
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
|
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
|
||||||
if (skp != NULL) {
|
if (skp != NULL) {
|
||||||
skp->smk_next = smack_known;
|
|
||||||
strncpy(skp->smk_known, smack, SMK_MAXLEN);
|
strncpy(skp->smk_known, smack, SMK_MAXLEN);
|
||||||
skp->smk_secid = smack_next_secid++;
|
skp->smk_secid = smack_next_secid++;
|
||||||
skp->smk_cipso = NULL;
|
skp->smk_cipso = NULL;
|
||||||
|
@ -244,8 +240,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
|
||||||
* Make sure that the entry is actually
|
* Make sure that the entry is actually
|
||||||
* filled before putting it on the list.
|
* filled before putting it on the list.
|
||||||
*/
|
*/
|
||||||
smp_mb();
|
list_add_rcu(&skp->list, &smack_known_list);
|
||||||
smack_known = skp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +261,9 @@ char *smk_import(const char *string, int len)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
|
/* labels cannot begin with a '-' */
|
||||||
|
if (string[0] == '-')
|
||||||
|
return NULL;
|
||||||
skp = smk_import_entry(string, len);
|
skp = smk_import_entry(string, len);
|
||||||
if (skp == NULL)
|
if (skp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -283,14 +281,19 @@ char *smack_from_secid(const u32 secid)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
rcu_read_lock();
|
||||||
if (skp->smk_secid == 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->smk_known;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we got this far someone asked for the translation
|
* If we got this far someone asked for the translation
|
||||||
* of a secid that is not on the list.
|
* of a secid that is not on the list.
|
||||||
*/
|
*/
|
||||||
|
rcu_read_unlock();
|
||||||
return smack_known_invalid.smk_known;
|
return smack_known_invalid.smk_known;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,9 +308,14 @@ u32 smack_to_secid(const char *smack)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
rcu_read_lock();
|
||||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
|
list_for_each_entry_rcu(skp, &smack_known_list, list) {
|
||||||
|
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
|
||||||
|
rcu_read_unlock();
|
||||||
return skp->smk_secid;
|
return skp->smk_secid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +340,8 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
||||||
struct smack_known *kp;
|
struct smack_known *kp;
|
||||||
char *final = NULL;
|
char *final = NULL;
|
||||||
|
|
||||||
for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
|
rcu_read_lock();
|
||||||
|
list_for_each_entry(kp, &smack_known_list, list) {
|
||||||
if (kp->smk_cipso == NULL)
|
if (kp->smk_cipso == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -344,6 +353,7 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
||||||
|
|
||||||
spin_unlock_bh(&kp->smk_cipsolock);
|
spin_unlock_bh(&kp->smk_cipsolock);
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
if (final == NULL)
|
if (final == NULL)
|
||||||
final = smack_known_huh.smk_known;
|
final = smack_known_huh.smk_known;
|
||||||
strncpy(result, final, SMK_MAXLEN);
|
strncpy(result, final, SMK_MAXLEN);
|
||||||
|
@ -360,13 +370,19 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
||||||
int smack_to_cipso(const char *smack, struct smack_cipso *cp)
|
int smack_to_cipso(const char *smack, struct smack_cipso *cp)
|
||||||
{
|
{
|
||||||
struct smack_known *kp;
|
struct smack_known *kp;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
for (kp = smack_known; kp != NULL; kp = kp->smk_next)
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(kp, &smack_known_list, list) {
|
||||||
if (kp->smk_known == smack ||
|
if (kp->smk_known == smack ||
|
||||||
strcmp(kp->smk_known, smack) == 0)
|
strcmp(kp->smk_known, smack) == 0) {
|
||||||
|
found = 1;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (kp == NULL || kp->smk_cipso == NULL)
|
if (found == 0 || kp->smk_cipso == NULL)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
|
memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
* Casey Schaufler <casey@schaufler-ca.com>
|
* Casey Schaufler <casey@schaufler-ca.com>
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
|
* Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
|
||||||
|
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||||
|
* Paul Moore <paul.moore@hp.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2,
|
* it under the terms of the GNU General Public License version 2,
|
||||||
|
@ -20,6 +22,7 @@
|
||||||
#include <linux/ext2_fs.h>
|
#include <linux/ext2_fs.h>
|
||||||
#include <linux/kd.h>
|
#include <linux/kd.h>
|
||||||
#include <asm/ioctls.h>
|
#include <asm/ioctls.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
#include <linux/tcp.h>
|
#include <linux/tcp.h>
|
||||||
#include <linux/udp.h>
|
#include <linux/udp.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
@ -606,6 +609,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
||||||
if (!capable(CAP_MAC_ADMIN))
|
if (!capable(CAP_MAC_ADMIN))
|
||||||
rc = -EPERM;
|
rc = -EPERM;
|
||||||
|
/* a label cannot be void and cannot begin with '-' */
|
||||||
|
if (size == 0 || (size > 0 && ((char *)value)[0] == '-'))
|
||||||
|
rc = -EINVAL;
|
||||||
} else
|
} else
|
||||||
rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
||||||
|
|
||||||
|
@ -1275,7 +1281,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
|
||||||
|
|
||||||
ssp->smk_in = csp;
|
ssp->smk_in = csp;
|
||||||
ssp->smk_out = csp;
|
ssp->smk_out = csp;
|
||||||
ssp->smk_labeled = SMACK_CIPSO_SOCKET;
|
|
||||||
ssp->smk_packet[0] = '\0';
|
ssp->smk_packet[0] = '\0';
|
||||||
|
|
||||||
sk->sk_security = ssp;
|
sk->sk_security = ssp;
|
||||||
|
@ -1294,6 +1299,43 @@ static void smack_sk_free_security(struct sock *sk)
|
||||||
kfree(sk->sk_security);
|
kfree(sk->sk_security);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smack_host_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 char *smack_host_label(struct sockaddr_in *sip)
|
||||||
|
{
|
||||||
|
struct smk_netlbladdr *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)
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_set_catset - convert a capset to netlabel mls categories
|
* smack_set_catset - convert a capset to netlabel mls categories
|
||||||
* @catset: the Smack categories
|
* @catset: the Smack categories
|
||||||
|
@ -1365,11 +1407,10 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
|
||||||
*/
|
*/
|
||||||
static int smack_netlabel(struct sock *sk, int labeled)
|
static int smack_netlabel(struct sock *sk, int labeled)
|
||||||
{
|
{
|
||||||
struct socket_smack *ssp;
|
struct socket_smack *ssp = sk->sk_security;
|
||||||
struct netlbl_lsm_secattr secattr;
|
struct netlbl_lsm_secattr secattr;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
ssp = sk->sk_security;
|
|
||||||
/*
|
/*
|
||||||
* Usually the netlabel code will handle changing the
|
* Usually the netlabel code will handle changing the
|
||||||
* packet labeling based on the label.
|
* packet labeling based on the label.
|
||||||
|
@ -1387,26 +1428,50 @@ static int smack_netlabel(struct sock *sk, int labeled)
|
||||||
else {
|
else {
|
||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
smack_to_secattr(ssp->smk_out, &secattr);
|
smack_to_secattr(ssp->smk_out, &secattr);
|
||||||
rc = netlbl_sock_setattr(sk, &secattr);
|
rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr);
|
||||||
netlbl_secattr_destroy(&secattr);
|
netlbl_secattr_destroy(&secattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bh_unlock_sock(sk);
|
bh_unlock_sock(sk);
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
/*
|
|
||||||
* Remember the label scheme used so that it is not
|
|
||||||
* necessary to do the netlabel setting if it has not
|
|
||||||
* changed the next time through.
|
|
||||||
*
|
|
||||||
* The -EDESTADDRREQ case is an indication that there's
|
|
||||||
* a single level host involved.
|
|
||||||
*/
|
|
||||||
if (rc == 0)
|
|
||||||
ssp->smk_labeled = labeled;
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smack_netlbel_send - Set the secattr on a socket and perform access checks
|
||||||
|
* @sk: the socket
|
||||||
|
* @sap: the destination address
|
||||||
|
*
|
||||||
|
* Set the correct secattr for the given socket based on the destination
|
||||||
|
* address and perform any outbound access checks needed.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or an error code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int sk_lbl;
|
||||||
|
char *hostsp;
|
||||||
|
struct socket_smack *ssp = sk->sk_security;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
hostsp = smack_host_label(sap);
|
||||||
|
if (hostsp != NULL) {
|
||||||
|
sk_lbl = SMACK_UNLABELED_SOCKET;
|
||||||
|
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
||||||
|
} else {
|
||||||
|
sk_lbl = SMACK_CIPSO_SOCKET;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (rc != 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return smack_netlabel(sk, sk_lbl);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_inode_setsecurity - set smack xattrs
|
* smack_inode_setsecurity - set smack xattrs
|
||||||
* @inode: the object
|
* @inode: the object
|
||||||
|
@ -1428,7 +1493,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
||||||
struct socket *sock;
|
struct socket *sock;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (value == NULL || size > SMK_LABELLEN)
|
if (value == NULL || size > SMK_LABELLEN || size == 0)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
sp = smk_import(value, size);
|
sp = smk_import(value, size);
|
||||||
|
@ -1488,41 +1553,6 @@ static int smack_socket_post_create(struct socket *sock, int family,
|
||||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* smack_host_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.
|
|
||||||
*
|
|
||||||
* Returns the label of the far end or NULL if it's not special.
|
|
||||||
*/
|
|
||||||
static char *smack_host_label(struct sockaddr_in *sip)
|
|
||||||
{
|
|
||||||
struct smk_netlbladdr *snp;
|
|
||||||
struct in_addr *siap = &sip->sin_addr;
|
|
||||||
|
|
||||||
if (siap->s_addr == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
|
|
||||||
/*
|
|
||||||
* 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)) {
|
|
||||||
return snp->smk_label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_socket_connect - connect access check
|
* smack_socket_connect - connect access check
|
||||||
* @sock: the socket
|
* @sock: the socket
|
||||||
|
@ -1536,30 +1566,12 @@ static char *smack_host_label(struct sockaddr_in *sip)
|
||||||
static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
|
static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
|
||||||
int addrlen)
|
int addrlen)
|
||||||
{
|
{
|
||||||
struct socket_smack *ssp = sock->sk->sk_security;
|
|
||||||
char *hostsp;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
|
if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (addrlen < sizeof(struct sockaddr_in))
|
if (addrlen < sizeof(struct sockaddr_in))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
hostsp = smack_host_label((struct sockaddr_in *)sap);
|
return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
|
||||||
if (hostsp == NULL) {
|
|
||||||
if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
|
|
||||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
|
||||||
if (rc != 0)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
|
|
||||||
return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2260,9 +2272,6 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
|
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
|
||||||
struct socket_smack *ssp = sock->sk->sk_security;
|
|
||||||
char *hostsp;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perfectly reasonable for this to be NULL
|
* Perfectly reasonable for this to be NULL
|
||||||
|
@ -2270,22 +2279,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||||
if (sip == NULL || sip->sin_family != PF_INET)
|
if (sip == NULL || sip->sin_family != PF_INET)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
hostsp = smack_host_label(sip);
|
return smack_netlabel_send(sock->sk, sip);
|
||||||
if (hostsp == NULL) {
|
|
||||||
if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
|
|
||||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
|
||||||
if (rc != 0)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
|
|
||||||
return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2490,31 +2484,24 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_sock_graft - graft access state between two sockets
|
* smack_sock_graft - Initialize a newly created socket with an existing sock
|
||||||
* @sk: fresh sock
|
* @sk: child sock
|
||||||
* @parent: donor socket
|
* @parent: parent socket
|
||||||
*
|
*
|
||||||
* Sets the netlabel socket state on sk from parent
|
* Set the smk_{in,out} state of an existing sock based on the process that
|
||||||
|
* is creating the new socket.
|
||||||
*/
|
*/
|
||||||
static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
||||||
{
|
{
|
||||||
struct socket_smack *ssp;
|
struct socket_smack *ssp;
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (sk == NULL)
|
if (sk == NULL ||
|
||||||
return;
|
(sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
|
||||||
|
|
||||||
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ssp = sk->sk_security;
|
ssp = sk->sk_security;
|
||||||
ssp->smk_in = ssp->smk_out = current_security();
|
ssp->smk_in = ssp->smk_out = current_security();
|
||||||
ssp->smk_packet[0] = '\0';
|
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
|
||||||
|
|
||||||
rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
|
|
||||||
if (rc != 0)
|
|
||||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
|
||||||
__func__, -rc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2529,35 +2516,82 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
||||||
static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
struct request_sock *req)
|
struct request_sock *req)
|
||||||
{
|
{
|
||||||
struct netlbl_lsm_secattr skb_secattr;
|
u16 family = sk->sk_family;
|
||||||
struct socket_smack *ssp = sk->sk_security;
|
struct socket_smack *ssp = sk->sk_security;
|
||||||
|
struct netlbl_lsm_secattr secattr;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
struct iphdr *hdr;
|
||||||
char smack[SMK_LABELLEN];
|
char smack[SMK_LABELLEN];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (skb == NULL)
|
/* handle mapped IPv4 packets arriving via IPv6 sockets */
|
||||||
return -EACCES;
|
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
|
||||||
|
family = PF_INET;
|
||||||
|
|
||||||
netlbl_secattr_init(&skb_secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
|
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
smack_from_secattr(&skb_secattr, smack);
|
smack_from_secattr(&secattr, smack);
|
||||||
else
|
else
|
||||||
strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
|
strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
|
||||||
netlbl_secattr_destroy(&skb_secattr);
|
netlbl_secattr_destroy(&secattr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Receiving a packet requires that the other end
|
* Receiving a packet requires that the other end be able to write
|
||||||
* be able to write here. Read access is not required.
|
* here. Read access is not required.
|
||||||
*
|
|
||||||
* If the request is successful save the peer's label
|
|
||||||
* so that SO_PEERCRED can report it.
|
|
||||||
*/
|
*/
|
||||||
rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
|
rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
|
||||||
if (rc == 0)
|
if (rc != 0)
|
||||||
strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
|
return rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = smack_to_secid(smack);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to decide if we want to label the incoming connection here
|
||||||
|
* if we do we only need to label the request_sock and the stack will
|
||||||
|
* propogate the wire-label to the sock when it is created.
|
||||||
|
*/
|
||||||
|
hdr = ip_hdr(skb);
|
||||||
|
addr.sin_addr.s_addr = hdr->saddr;
|
||||||
|
rcu_read_lock();
|
||||||
|
if (smack_host_label(&addr) == NULL) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
netlbl_secattr_init(&secattr);
|
||||||
|
smack_to_secattr(smack, &secattr);
|
||||||
|
rc = netlbl_req_setattr(req, &secattr);
|
||||||
|
netlbl_secattr_destroy(&secattr);
|
||||||
|
} else {
|
||||||
|
rcu_read_unlock();
|
||||||
|
netlbl_req_delattr(req);
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smack_inet_csk_clone - Copy the connection information to the new socket
|
||||||
|
* @sk: the new socket
|
||||||
|
* @req: the connection's request_sock
|
||||||
|
*
|
||||||
|
* Transfer the connection's peer label to the newly created socket.
|
||||||
|
*/
|
||||||
|
static void smack_inet_csk_clone(struct sock *sk,
|
||||||
|
const struct request_sock *req)
|
||||||
|
{
|
||||||
|
struct socket_smack *ssp = sk->sk_security;
|
||||||
|
char *smack;
|
||||||
|
|
||||||
|
if (req->peer_secid != 0) {
|
||||||
|
smack = smack_from_secid(req->peer_secid);
|
||||||
|
strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
|
||||||
|
} else
|
||||||
|
ssp->smk_packet[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Key management security hooks
|
* Key management security hooks
|
||||||
*
|
*
|
||||||
|
@ -2909,6 +2943,7 @@ struct security_operations smack_ops = {
|
||||||
.sk_free_security = smack_sk_free_security,
|
.sk_free_security = smack_sk_free_security,
|
||||||
.sock_graft = smack_sock_graft,
|
.sock_graft = smack_sock_graft,
|
||||||
.inet_conn_request = smack_inet_conn_request,
|
.inet_conn_request = smack_inet_conn_request,
|
||||||
|
.inet_csk_clone = smack_inet_csk_clone,
|
||||||
|
|
||||||
/* key management security hooks */
|
/* key management security hooks */
|
||||||
#ifdef CONFIG_KEYS
|
#ifdef CONFIG_KEYS
|
||||||
|
@ -2930,6 +2965,17 @@ struct security_operations smack_ops = {
|
||||||
.release_secctx = smack_release_secctx,
|
.release_secctx = smack_release_secctx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static __init void init_smack_know_list(void)
|
||||||
|
{
|
||||||
|
list_add(&smack_known_huh.list, &smack_known_list);
|
||||||
|
list_add(&smack_known_hat.list, &smack_known_list);
|
||||||
|
list_add(&smack_known_star.list, &smack_known_list);
|
||||||
|
list_add(&smack_known_floor.list, &smack_known_list);
|
||||||
|
list_add(&smack_known_invalid.list, &smack_known_list);
|
||||||
|
list_add(&smack_known_web.list, &smack_known_list);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_init - initialize the smack system
|
* smack_init - initialize the smack system
|
||||||
*
|
*
|
||||||
|
@ -2950,6 +2996,8 @@ static __init int smack_init(void)
|
||||||
cred = (struct cred *) current->cred;
|
cred = (struct cred *) current->cred;
|
||||||
cred->security = &smack_known_floor.smk_known;
|
cred->security = &smack_known_floor.smk_known;
|
||||||
|
|
||||||
|
/* initilize the smack_know_list */
|
||||||
|
init_smack_know_list();
|
||||||
/*
|
/*
|
||||||
* Initialize locks
|
* Initialize locks
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -80,10 +80,14 @@ char *smack_onlycap;
|
||||||
* Packets are sent there unlabeled, but only from tasks that
|
* Packets are sent there unlabeled, but only from tasks that
|
||||||
* can write to the specified label.
|
* can write to the specified label.
|
||||||
*/
|
*/
|
||||||
struct smk_netlbladdr *smack_netlbladdrs;
|
|
||||||
|
LIST_HEAD(smk_netlbladdr_list);
|
||||||
|
LIST_HEAD(smack_rule_list);
|
||||||
|
|
||||||
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
||||||
struct smk_list_entry *smack_list;
|
|
||||||
|
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
|
||||||
|
|
||||||
|
|
||||||
#define SEQ_READ_FINISHED 1
|
#define SEQ_READ_FINISHED 1
|
||||||
|
|
||||||
|
@ -134,24 +138,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
|
||||||
{
|
{
|
||||||
if (*pos == SEQ_READ_FINISHED)
|
if (*pos == SEQ_READ_FINISHED)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (list_empty(&smack_rule_list))
|
||||||
return smack_list;
|
return NULL;
|
||||||
|
return smack_rule_list.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
|
struct list_head *list = v;
|
||||||
|
|
||||||
if (skp == NULL)
|
if (list_is_last(list, &smack_rule_list)) {
|
||||||
*pos = SEQ_READ_FINISHED;
|
*pos = SEQ_READ_FINISHED;
|
||||||
|
return NULL;
|
||||||
return skp;
|
}
|
||||||
|
return list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_seq_show(struct seq_file *s, void *v)
|
static int load_seq_show(struct seq_file *s, void *v)
|
||||||
{
|
{
|
||||||
struct smk_list_entry *slp = (struct smk_list_entry *) v;
|
struct list_head *list = v;
|
||||||
struct smack_rule *srp = &slp->smk_rule;
|
struct smack_rule *srp =
|
||||||
|
list_entry(list, struct smack_rule, list);
|
||||||
|
|
||||||
seq_printf(s, "%s %s", (char *)srp->smk_subject,
|
seq_printf(s, "%s %s", (char *)srp->smk_subject,
|
||||||
(char *)srp->smk_object);
|
(char *)srp->smk_object);
|
||||||
|
@ -212,32 +219,23 @@ static int smk_open_load(struct inode *inode, struct file *file)
|
||||||
*/
|
*/
|
||||||
static int smk_set_access(struct smack_rule *srp)
|
static int smk_set_access(struct smack_rule *srp)
|
||||||
{
|
{
|
||||||
struct smk_list_entry *sp;
|
struct smack_rule *sp;
|
||||||
struct smk_list_entry *newp;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int found;
|
||||||
mutex_lock(&smack_list_lock);
|
mutex_lock(&smack_list_lock);
|
||||||
|
|
||||||
for (sp = smack_list; sp != NULL; sp = sp->smk_next)
|
found = 0;
|
||||||
if (sp->smk_rule.smk_subject == srp->smk_subject &&
|
list_for_each_entry_rcu(sp, &smack_rule_list, list) {
|
||||||
sp->smk_rule.smk_object == srp->smk_object) {
|
if (sp->smk_subject == srp->smk_subject &&
|
||||||
sp->smk_rule.smk_access = srp->smk_access;
|
sp->smk_object == srp->smk_object) {
|
||||||
|
found = 1;
|
||||||
|
sp->smk_access = srp->smk_access;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sp == NULL) {
|
|
||||||
newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
|
|
||||||
if (newp == NULL) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
newp->smk_rule = *srp;
|
|
||||||
newp->smk_next = smack_list;
|
|
||||||
smack_list = newp;
|
|
||||||
}
|
}
|
||||||
|
if (found == 0)
|
||||||
|
list_add_rcu(&srp->list, &smack_rule_list);
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&smack_list_lock);
|
mutex_unlock(&smack_list_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -261,7 +259,7 @@ out:
|
||||||
static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct smack_rule rule;
|
struct smack_rule *rule;
|
||||||
char *data;
|
char *data;
|
||||||
int rc = -EINVAL;
|
int rc = -EINVAL;
|
||||||
|
|
||||||
|
@ -272,9 +270,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
*/
|
*/
|
||||||
if (!capable(CAP_MAC_ADMIN))
|
if (!capable(CAP_MAC_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (*ppos != 0)
|
|
||||||
return -EINVAL;
|
if (*ppos != 0 || count != SMK_LOADLEN)
|
||||||
if (count != SMK_LOADLEN)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
data = kzalloc(count, GFP_KERNEL);
|
data = kzalloc(count, GFP_KERNEL);
|
||||||
|
@ -286,25 +283,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.smk_subject = smk_import(data, 0);
|
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||||
if (rule.smk_subject == NULL)
|
if (rule == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
|
rule->smk_subject = smk_import(data, 0);
|
||||||
if (rule.smk_object == NULL)
|
if (rule->smk_subject == NULL)
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
|
|
||||||
rule.smk_access = 0;
|
rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
|
||||||
|
if (rule->smk_object == NULL)
|
||||||
|
goto out_free_rule;
|
||||||
|
|
||||||
|
rule->smk_access = 0;
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
|
switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
|
||||||
case '-':
|
case '-':
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'R':
|
case 'R':
|
||||||
rule.smk_access |= MAY_READ;
|
rule->smk_access |= MAY_READ;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
|
switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
|
||||||
|
@ -312,10 +315,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
case 'W':
|
case 'W':
|
||||||
rule.smk_access |= MAY_WRITE;
|
rule->smk_access |= MAY_WRITE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
|
switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
|
||||||
|
@ -323,10 +326,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
rule.smk_access |= MAY_EXEC;
|
rule->smk_access |= MAY_EXEC;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
|
switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
|
||||||
|
@ -334,17 +337,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'A':
|
case 'A':
|
||||||
rule.smk_access |= MAY_APPEND;
|
rule->smk_access |= MAY_APPEND;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = smk_set_access(&rule);
|
rc = smk_set_access(rule);
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = count;
|
rc = count;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
out_free_rule:
|
||||||
|
kfree(rule);
|
||||||
out:
|
out:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -433,24 +439,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
|
||||||
{
|
{
|
||||||
if (*pos == SEQ_READ_FINISHED)
|
if (*pos == SEQ_READ_FINISHED)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (list_empty(&smack_known_list))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return smack_known;
|
return smack_known_list.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct smack_known *skp = ((struct smack_known *) v)->smk_next;
|
struct list_head *list = v;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Omit labels with no associated cipso value
|
* labels with no associated cipso value wont be printed
|
||||||
|
* in cipso_seq_show
|
||||||
*/
|
*/
|
||||||
while (skp != NULL && !skp->smk_cipso)
|
if (list_is_last(list, &smack_known_list)) {
|
||||||
skp = skp->smk_next;
|
|
||||||
|
|
||||||
if (skp == NULL)
|
|
||||||
*pos = SEQ_READ_FINISHED;
|
*pos = SEQ_READ_FINISHED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return skp;
|
return list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -459,7 +467,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||||
*/
|
*/
|
||||||
static int cipso_seq_show(struct seq_file *s, void *v)
|
static int cipso_seq_show(struct seq_file *s, void *v)
|
||||||
{
|
{
|
||||||
struct smack_known *skp = (struct smack_known *) v;
|
struct list_head *list = v;
|
||||||
|
struct smack_known *skp =
|
||||||
|
list_entry(list, struct smack_known, list);
|
||||||
struct smack_cipso *scp = skp->smk_cipso;
|
struct smack_cipso *scp = skp->smk_cipso;
|
||||||
char *cbp;
|
char *cbp;
|
||||||
char sep = '/';
|
char sep = '/';
|
||||||
|
@ -558,6 +568,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
|
||||||
goto unlockedout;
|
goto unlockedout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* labels cannot begin with a '-' */
|
||||||
|
if (data[0] == '-') {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto unlockedout;
|
||||||
|
}
|
||||||
data[count] = '\0';
|
data[count] = '\0';
|
||||||
rule = data;
|
rule = data;
|
||||||
/*
|
/*
|
||||||
|
@ -638,18 +653,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
|
||||||
{
|
{
|
||||||
if (*pos == SEQ_READ_FINISHED)
|
if (*pos == SEQ_READ_FINISHED)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (list_empty(&smk_netlbladdr_list))
|
||||||
return smack_netlbladdrs;
|
return NULL;
|
||||||
|
return smk_netlbladdr_list.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
|
struct list_head *list = v;
|
||||||
|
|
||||||
if (skp == NULL)
|
if (list_is_last(list, &smk_netlbladdr_list)) {
|
||||||
*pos = SEQ_READ_FINISHED;
|
*pos = SEQ_READ_FINISHED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return skp;
|
return list->next;
|
||||||
}
|
}
|
||||||
#define BEBITS (sizeof(__be32) * 8)
|
#define BEBITS (sizeof(__be32) * 8)
|
||||||
|
|
||||||
|
@ -658,7 +676,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||||
*/
|
*/
|
||||||
static int netlbladdr_seq_show(struct seq_file *s, void *v)
|
static int netlbladdr_seq_show(struct seq_file *s, void *v)
|
||||||
{
|
{
|
||||||
struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
|
struct list_head *list = v;
|
||||||
|
struct smk_netlbladdr *skp =
|
||||||
|
list_entry(list, struct smk_netlbladdr, list);
|
||||||
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
|
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
|
||||||
int maskn;
|
int maskn;
|
||||||
u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
|
u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
|
||||||
|
@ -702,30 +722,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
|
||||||
*
|
*
|
||||||
* This helper insert netlabel in the smack_netlbladdrs list
|
* This helper insert netlabel in the smack_netlbladdrs list
|
||||||
* sorted by netmask length (longest to smallest)
|
* sorted by netmask length (longest to smallest)
|
||||||
|
* locked by &smk_netlbladdr_lock in smk_write_netlbladdr
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
|
static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
|
||||||
{
|
{
|
||||||
struct smk_netlbladdr *m;
|
struct smk_netlbladdr *m, *m_next;
|
||||||
|
|
||||||
if (smack_netlbladdrs == NULL) {
|
if (list_empty(&smk_netlbladdr_list)) {
|
||||||
smack_netlbladdrs = new;
|
list_add_rcu(&new->list, &smk_netlbladdr_list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
|
||||||
|
struct smk_netlbladdr, list);
|
||||||
|
|
||||||
/* the comparison '>' is a bit hacky, but works */
|
/* the comparison '>' is a bit hacky, but works */
|
||||||
if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
|
if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
|
||||||
new->smk_next = smack_netlbladdrs;
|
list_add_rcu(&new->list, &smk_netlbladdr_list);
|
||||||
smack_netlbladdrs = new;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
|
|
||||||
if (m->smk_next == NULL) {
|
list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
|
||||||
m->smk_next = new;
|
if (list_is_last(&m->list, &smk_netlbladdr_list)) {
|
||||||
|
list_add_rcu(&new->list, &m->list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
|
m_next = list_entry(rcu_dereference(m->list.next),
|
||||||
new->smk_next = m->smk_next;
|
struct smk_netlbladdr, list);
|
||||||
m->smk_next = new;
|
if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
|
||||||
|
list_add_rcu(&new->list, &m->list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -755,6 +781,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||||
struct netlbl_audit audit_info;
|
struct netlbl_audit audit_info;
|
||||||
struct in_addr mask;
|
struct in_addr mask;
|
||||||
unsigned int m;
|
unsigned int m;
|
||||||
|
int found;
|
||||||
u32 mask_bits = (1<<31);
|
u32 mask_bits = (1<<31);
|
||||||
__be32 nsa;
|
__be32 nsa;
|
||||||
u32 temp_mask;
|
u32 temp_mask;
|
||||||
|
@ -789,9 +816,18 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||||
if (m > BEBITS)
|
if (m > BEBITS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
sp = smk_import(smack, 0);
|
/* if smack begins with '-', its an option, don't import it */
|
||||||
if (sp == NULL)
|
if (smack[0] != '-') {
|
||||||
return -EINVAL;
|
sp = smk_import(smack, 0);
|
||||||
|
if (sp == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
|
/* check known options */
|
||||||
|
if (strcmp(smack, smack_cipso_option) == 0)
|
||||||
|
sp = (char *)smack_cipso_option;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
for (temp_mask = 0; m > 0; m--) {
|
for (temp_mask = 0; m > 0; m--) {
|
||||||
temp_mask |= mask_bits;
|
temp_mask |= mask_bits;
|
||||||
|
@ -808,14 +844,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||||
|
|
||||||
nsa = newname.sin_addr.s_addr;
|
nsa = newname.sin_addr.s_addr;
|
||||||
/* try to find if the prefix is already in the list */
|
/* try to find if the prefix is already in the list */
|
||||||
for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
|
found = 0;
|
||||||
|
list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
|
||||||
if (skp->smk_host.sin_addr.s_addr == nsa &&
|
if (skp->smk_host.sin_addr.s_addr == nsa &&
|
||||||
skp->smk_mask.s_addr == mask.s_addr)
|
skp->smk_mask.s_addr == mask.s_addr) {
|
||||||
|
found = 1;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
smk_netlabel_audit_set(&audit_info);
|
smk_netlabel_audit_set(&audit_info);
|
||||||
|
|
||||||
if (skp == NULL) {
|
if (found == 0) {
|
||||||
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
||||||
if (skp == NULL)
|
if (skp == NULL)
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
@ -827,18 +866,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||||
smk_netlbladdr_insert(skp);
|
smk_netlbladdr_insert(skp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
|
/* we delete the unlabeled entry, only if the previous label
|
||||||
&skp->smk_host.sin_addr, &skp->smk_mask,
|
* wasnt the special CIPSO option */
|
||||||
PF_INET, &audit_info);
|
if (skp->smk_label != smack_cipso_option)
|
||||||
|
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
|
||||||
|
&skp->smk_host.sin_addr, &skp->smk_mask,
|
||||||
|
PF_INET, &audit_info);
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
skp->smk_label = sp;
|
skp->smk_label = sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now tell netlabel about the single label nature of
|
* Now tell netlabel about the single label nature of
|
||||||
* this host so that incoming packets get labeled.
|
* this host so that incoming packets get labeled.
|
||||||
|
* but only if we didn't get the special CIPSO option
|
||||||
*/
|
*/
|
||||||
|
if (rc == 0 && sp != smack_cipso_option)
|
||||||
if (rc == 0)
|
|
||||||
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
|
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
|
||||||
&skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
|
&skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
|
||||||
smack_to_secid(skp->smk_label), &audit_info);
|
smack_to_secid(skp->smk_label), &audit_info);
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct tomoyo_path_info {
|
||||||
struct tomoyo_path_info_with_data {
|
struct tomoyo_path_info_with_data {
|
||||||
/* Keep "head" first, for this pointer is passed to tomoyo_free(). */
|
/* Keep "head" first, for this pointer is passed to tomoyo_free(). */
|
||||||
struct tomoyo_path_info head;
|
struct tomoyo_path_info head;
|
||||||
char bariier1[16]; /* Safeguard for overrun. */
|
char barrier1[16]; /* Safeguard for overrun. */
|
||||||
char body[TOMOYO_MAX_PATHNAME_LEN];
|
char body[TOMOYO_MAX_PATHNAME_LEN];
|
||||||
char barrier2[16]; /* Safeguard for overrun. */
|
char barrier2[16]; /* Safeguard for overrun. */
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue