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:
Коммит
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
|
||||
team. Smack labels are unstructured, case sensitive, and the only operation
|
||||
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:
|
||||
|
||||
_ Pronounced "floor", a single underscore character.
|
||||
^ Pronounced "hat", a single circumflex character.
|
||||
* Pronounced "star", a single asterisk character.
|
||||
? Pronounced "huh", a single question mark character.
|
||||
_ Pronounced "floor", a single underscore character.
|
||||
^ Pronounced "hat", a single circumflex character.
|
||||
* Pronounced "star", a single asterisk 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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
When: September 2009
|
||||
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
|
||||
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]
|
||||
|
||||
shapers= [NET]
|
||||
|
|
|
@ -880,11 +880,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
|||
* @sock contains the listening socket structure.
|
||||
* @newsock contains the newly created server socket for connection.
|
||||
* 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:
|
||||
* Check permission before transmitting a message to another socket.
|
||||
* @sock contains the socket structure.
|
||||
|
@ -1554,8 +1549,6 @@ struct security_operations {
|
|||
struct sockaddr *address, int addrlen);
|
||||
int (*socket_listen) (struct socket *sock, int backlog);
|
||||
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,
|
||||
struct msghdr *msg, int size);
|
||||
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_listen(struct socket *sock, int backlog);
|
||||
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_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
int size, int flags);
|
||||
|
@ -2616,11 +2608,6 @@ static inline int security_socket_accept(struct socket *sock,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_socket_post_accept(struct socket *sock,
|
||||
struct socket *newsock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int security_socket_sendmsg(struct socket *sock,
|
||||
struct msghdr *msg, int size)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/net.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/request_sock.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
/* known doi values */
|
||||
|
@ -215,6 +216,10 @@ int cipso_v4_sock_setattr(struct sock *sk,
|
|||
const struct netlbl_lsm_secattr *secattr);
|
||||
void cipso_v4_sock_delattr(struct sock *sk);
|
||||
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,
|
||||
const struct cipso_v4_doi *doi_def,
|
||||
const struct netlbl_lsm_secattr *secattr);
|
||||
|
@ -247,6 +252,18 @@ static inline int cipso_v4_sock_getattr(struct sock *sk,
|
|||
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,
|
||||
const struct cipso_v4_doi *doi_def,
|
||||
const struct netlbl_lsm_secattr *secattr)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/request_sock.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
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_sock_setattr(struct sock *sk,
|
||||
u16 family,
|
||||
const struct netlbl_lsm_secattr *secattr);
|
||||
void netlbl_sock_delattr(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,
|
||||
struct sockaddr *addr,
|
||||
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,
|
||||
u16 family,
|
||||
const struct netlbl_lsm_secattr *secattr);
|
||||
|
@ -519,7 +524,8 @@ static inline int netlbl_enabled(void)
|
|||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -537,6 +543,15 @@ static inline int netlbl_conn_setattr(struct sock *sk,
|
|||
{
|
||||
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,
|
||||
u16 family,
|
||||
const struct netlbl_lsm_secattr *secattr)
|
||||
|
|
|
@ -1942,23 +1942,85 @@ socket_setattr_failure:
|
|||
}
|
||||
|
||||
/**
|
||||
* cipso_v4_sock_delattr - Delete the CIPSO option from a socket
|
||||
* @sk: the socket
|
||||
* cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
|
||||
* @req: the connection request socket
|
||||
* @doi_def: the CIPSO DOI to use
|
||||
* @secattr: the specific security attributes of the socket
|
||||
*
|
||||
* 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;
|
||||
struct ip_options *opt;
|
||||
struct inet_sock *sk_inet;
|
||||
int ret_val = -EPERM;
|
||||
unsigned char *buf = NULL;
|
||||
u32 buf_len;
|
||||
u32 opt_len;
|
||||
struct ip_options *opt = NULL;
|
||||
struct inet_request_sock *req_inet;
|
||||
|
||||
sk_inet = inet_sk(sk);
|
||||
opt = sk_inet->opt;
|
||||
if (opt == NULL || opt->cipso == 0)
|
||||
return;
|
||||
/* We allocate the maximum CIPSO option size here so we are probably
|
||||
* being a little wasteful, but it makes our life _much_ easier later
|
||||
* on and after all we are only talking about 40 bytes. */
|
||||
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) {
|
||||
u8 cipso_len;
|
||||
|
@ -2003,11 +2065,34 @@ void cipso_v4_sock_delattr(struct sock *sk)
|
|||
} else {
|
||||
/* only the cipso option was present on the socket so we can
|
||||
* remove the entire option struct */
|
||||
sk_inet->opt = NULL;
|
||||
*opt_ptr = NULL;
|
||||
hdr_delta = opt->optlen;
|
||||
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) {
|
||||
struct inet_connection_sock *sk_conn = inet_csk(sk);
|
||||
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: the CIPSO v4 option
|
||||
|
|
|
@ -288,10 +288,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
|
|||
if (!req)
|
||||
goto out;
|
||||
|
||||
if (security_inet_conn_request(sk, skb, req)) {
|
||||
reqsk_free(req);
|
||||
goto out;
|
||||
}
|
||||
ireq = inet_rsk(req);
|
||||
treq = tcp_rsk(req);
|
||||
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->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);
|
||||
|
||||
if (security_inet_conn_request(sk, skb, req))
|
||||
goto drop_and_free;
|
||||
|
||||
ireq = inet_rsk(req);
|
||||
ireq->loc_addr = daddr;
|
||||
ireq->rmt_addr = saddr;
|
||||
ireq->no_srccheck = inet_sk(sk)->transparent;
|
||||
ireq->opt = tcp_v4_save_options(sk, skb);
|
||||
|
||||
if (security_inet_conn_request(sk, skb, req))
|
||||
goto drop_and_free;
|
||||
|
||||
if (!want_cookie)
|
||||
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
|
||||
* @family: protocol family
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* Description:
|
||||
|
@ -633,29 +634,45 @@ int netlbl_enabled(void)
|
|||
*
|
||||
*/
|
||||
int netlbl_sock_setattr(struct sock *sk,
|
||||
u16 family,
|
||||
const struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
int ret_val = -ENOENT;
|
||||
int ret_val;
|
||||
struct netlbl_dom_map *dom_entry;
|
||||
|
||||
rcu_read_lock();
|
||||
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
||||
if (dom_entry == NULL)
|
||||
if (dom_entry == NULL) {
|
||||
ret_val = -ENOENT;
|
||||
goto socket_setattr_return;
|
||||
switch (dom_entry->type) {
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
ret_val = -EDESTADDRREQ;
|
||||
}
|
||||
switch (family) {
|
||||
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;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = cipso_v4_sock_setattr(sk,
|
||||
dom_entry->type_def.cipsov4,
|
||||
secattr);
|
||||
break;
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
#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 = -ENOENT;
|
||||
ret_val = -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
socket_setattr_return:
|
||||
|
@ -689,9 +706,25 @@ void netlbl_sock_delattr(struct sock *sk)
|
|||
* 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;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
ret_val = 0;
|
||||
ret_val = -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
conn_setattr_return:
|
||||
|
@ -756,6 +789,90 @@ conn_setattr_return:
|
|||
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
|
||||
* @skb: the packet
|
||||
|
@ -808,7 +925,7 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
|||
break;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
ret_val = 0;
|
||||
ret_val = -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
skbuff_setattr_return:
|
||||
|
@ -833,9 +950,17 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
|||
u16 family,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if (CIPSO_V4_OPTEXIST(skb) &&
|
||||
cipso_v4_skbuff_getattr(skb, secattr) == 0)
|
||||
return 0;
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1536,8 +1536,6 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
|
|||
fd_install(newfd, newfile);
|
||||
err = newfd;
|
||||
|
||||
security_socket_post_accept(sock, newsock);
|
||||
|
||||
out_put:
|
||||
fput_light(sock->file, fput_needed);
|
||||
out:
|
||||
|
|
|
@ -620,10 +620,6 @@ static int cap_socket_accept(struct socket *sock, struct socket *newsock)
|
|||
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)
|
||||
{
|
||||
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_listen);
|
||||
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_recvmsg);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return security_ops->socket_sendmsg(sock, msg, size);
|
||||
|
|
|
@ -93,7 +93,6 @@
|
|||
|
||||
extern unsigned int policydb_loaded_version;
|
||||
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
|
||||
extern int selinux_compat_net;
|
||||
extern struct security_operations *security_ops;
|
||||
|
||||
/* SECMARK reference count */
|
||||
|
@ -311,7 +310,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
|
|||
ssec->sid = SECINITSID_UNLABELED;
|
||||
sk->sk_security = ssec;
|
||||
|
||||
selinux_netlbl_sk_security_reset(ssec, family);
|
||||
selinux_netlbl_sk_security_reset(ssec);
|
||||
|
||||
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)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int rc;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
|
||||
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))
|
||||
mask |= MAY_APPEND;
|
||||
|
||||
rc = file_has_perm(cred, file,
|
||||
file_mask_to_av(inode->i_mode, mask));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return selinux_netlbl_inode_permission(inode, mask);
|
||||
return file_has_perm(cred, file,
|
||||
file_mask_to_av(inode->i_mode, mask));
|
||||
}
|
||||
|
||||
static int selinux_file_permission(struct file *file, int mask)
|
||||
{
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
struct file_security_struct *fsec = file->f_security;
|
||||
struct inode_security_struct *isec = inode->i_security;
|
||||
u32 sid = current_sid();
|
||||
|
||||
if (!mask) {
|
||||
if (!mask)
|
||||
/* No permission to check. Existence test. */
|
||||
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);
|
||||
}
|
||||
|
@ -3723,7 +3707,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
|
|||
sksec = sock->sk->sk_security;
|
||||
sksec->sid = isec->sid;
|
||||
sksec->sclass = isec->sclass;
|
||||
err = selinux_netlbl_socket_post_create(sock);
|
||||
err = selinux_netlbl_socket_post_create(sock->sk, family);
|
||||
}
|
||||
|
||||
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,
|
||||
int size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = socket_has_perm(current, sock, SOCKET__WRITE);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
|
||||
return socket_has_perm(current, sock, SOCKET__WRITE);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
u16 family)
|
||||
{
|
||||
|
@ -4123,14 +4035,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (selinux_compat_net)
|
||||
err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
|
||||
family, addrp);
|
||||
else if (selinux_secmark_enabled())
|
||||
if (selinux_secmark_enabled()) {
|
||||
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
|
||||
PACKET__RECV, &ad);
|
||||
if (err)
|
||||
return err;
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (selinux_policycap_netpeer) {
|
||||
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
|
||||
* special handling. We do this in an attempt to keep this function
|
||||
* 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);
|
||||
|
||||
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->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)
|
||||
|
@ -4348,16 +4258,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
|||
if (peersid == SECSID_NULL) {
|
||||
req->secid = sksec->sid;
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
req->secid = newsid;
|
||||
req->peer_secid = peersid;
|
||||
return 0;
|
||||
return selinux_netlbl_inet_conn_request(req, family);
|
||||
}
|
||||
|
||||
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
|
||||
* 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)
|
||||
|
@ -4387,8 +4296,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
|
|||
family = PF_INET;
|
||||
|
||||
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,
|
||||
|
@ -4540,71 +4447,6 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum,
|
|||
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,
|
||||
int ifindex,
|
||||
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))
|
||||
return NF_DROP;
|
||||
|
||||
if (selinux_compat_net) {
|
||||
if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
|
||||
&ad, family, addrp))
|
||||
return NF_DROP;
|
||||
} else if (selinux_secmark_enabled()) {
|
||||
if (selinux_secmark_enabled())
|
||||
if (avc_has_perm(sksec->sid, skb->secmark,
|
||||
SECCLASS_PACKET, PACKET__SEND, &ad))
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
if (selinux_policycap_netpeer)
|
||||
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
|
||||
* special handling. We do this in an attempt to keep this function
|
||||
* 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);
|
||||
#ifdef CONFIG_XFRM
|
||||
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/net.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/request_sock.h>
|
||||
|
||||
#include "avc.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_sk_security_free(struct sk_security_struct *ssec);
|
||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
|
||||
int family);
|
||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec);
|
||||
|
||||
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
|
||||
u16 family,
|
||||
|
@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
|
|||
u16 family,
|
||||
u32 sid);
|
||||
|
||||
void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
|
||||
int selinux_netlbl_socket_post_create(struct socket *sock);
|
||||
int selinux_netlbl_inode_permission(struct inode *inode, int mask);
|
||||
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
|
||||
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
|
||||
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
|
||||
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
||||
struct sk_buff *skb,
|
||||
u16 family,
|
||||
|
@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free(
|
|||
}
|
||||
|
||||
static inline void selinux_netlbl_sk_security_reset(
|
||||
struct sk_security_struct *ssec,
|
||||
int family)
|
||||
struct sk_security_struct *ssec)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
|
||||
u16 family)
|
||||
{
|
||||
return;
|
||||
}
|
||||
static inline int selinux_netlbl_socket_post_create(struct socket *sock)
|
||||
static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
|
||||
u16 family)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int selinux_netlbl_inode_permission(struct inode *inode,
|
||||
int mask)
|
||||
static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
|
||||
{
|
||||
return;
|
||||
}
|
||||
static inline int selinux_netlbl_socket_post_create(struct sock *sk,
|
||||
u16 family)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -99,41 +99,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
|
|||
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
|
||||
*
|
||||
|
@ -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.
|
||||
*
|
||||
*/
|
||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
|
||||
int family)
|
||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
|
||||
{
|
||||
if (family == PF_INET)
|
||||
ssec->nlbl_state = NLBL_REQUIRE;
|
||||
else
|
||||
ssec->nlbl_state = NLBL_UNSET;
|
||||
ssec->nlbl_state = NLBL_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,127 +242,86 @@ skbuff_setsid_return:
|
|||
}
|
||||
|
||||
/**
|
||||
* selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
|
||||
* @sk: the new connection
|
||||
* selinux_netlbl_inet_conn_request - Label an incoming stream connection
|
||||
* @req: incoming connection request socket
|
||||
*
|
||||
* Description:
|
||||
* A new connection has been established on @sk so make sure it is labeled
|
||||
* correctly with the NetLabel susbsystem.
|
||||
* A new incoming connection request is represented by @req, we need to label
|
||||
* 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;
|
||||
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 netlbl_lsm_secattr *secattr;
|
||||
struct inet_sock *sk_inet = inet_sk(sk);
|
||||
struct sockaddr_in addr;
|
||||
|
||||
if (sksec->nlbl_state != NLBL_REQUIRE)
|
||||
return;
|
||||
|
||||
secattr = selinux_netlbl_sock_genattr(sk);
|
||||
if (secattr == NULL)
|
||||
return;
|
||||
|
||||
rc = netlbl_sock_setattr(sk, secattr);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
if (family == PF_INET)
|
||||
sksec->nlbl_state = NLBL_LABELED;
|
||||
break;
|
||||
case -EDESTADDRREQ:
|
||||
/* 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;
|
||||
}
|
||||
else
|
||||
sksec->nlbl_state = NLBL_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* selinux_netlbl_socket_post_create - Label a socket using NetLabel
|
||||
* @sock: the socket to label
|
||||
* @family: protocol family
|
||||
*
|
||||
* Description:
|
||||
* Attempt to label a socket using the NetLabel mechanism using the given
|
||||
* SID. Returns zero values on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int selinux_netlbl_socket_post_create(struct socket *sock)
|
||||
{
|
||||
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 selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
|
||||
{
|
||||
int rc;
|
||||
struct sock *sk;
|
||||
struct socket *sock;
|
||||
struct sk_security_struct *sksec;
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
struct netlbl_lsm_secattr *secattr;
|
||||
|
||||
if (!S_ISSOCK(inode->i_mode) ||
|
||||
((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)
|
||||
if (family != PF_INET)
|
||||
return 0;
|
||||
|
||||
local_bh_disable();
|
||||
bh_lock_sock_nested(sk);
|
||||
if (likely(sksec->nlbl_state == NLBL_REQUIRE))
|
||||
rc = selinux_netlbl_sock_setsid(sk);
|
||||
else
|
||||
secattr = selinux_netlbl_sock_genattr(sk);
|
||||
if (secattr == NULL)
|
||||
return -ENOMEM;
|
||||
rc = netlbl_sock_setattr(sk, family, secattr);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
sksec->nlbl_state = NLBL_LABELED;
|
||||
break;
|
||||
case -EDESTADDRREQ:
|
||||
sksec->nlbl_state = NLBL_REQSKB;
|
||||
rc = 0;
|
||||
bh_unlock_sock(sk);
|
||||
local_bh_enable();
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -47,8 +47,6 @@ static char *policycap_names[] = {
|
|||
|
||||
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
|
||||
|
||||
int selinux_compat_net = 0;
|
||||
|
||||
static int __init checkreqprot_setup(char *str)
|
||||
{
|
||||
unsigned long checkreqprot;
|
||||
|
@ -58,16 +56,6 @@ static int __init checkreqprot_setup(char *str)
|
|||
}
|
||||
__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);
|
||||
|
||||
/* global data for booleans */
|
||||
|
@ -450,61 +438,6 @@ static const struct file_operations sel_checkreqprot_ops = {
|
|||
.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
|
||||
*/
|
||||
|
@ -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_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
|
||||
[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_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
||||
/* last one */ {""}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/security.h>
|
||||
#include <linux/in.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
|
||||
|
@ -40,7 +42,6 @@ struct superblock_smack {
|
|||
struct socket_smack {
|
||||
char *smk_out; /* outbound label */
|
||||
char *smk_in; /* inbound label */
|
||||
int smk_labeled; /* label scheme */
|
||||
char smk_packet[SMK_LABELLEN]; /* TCP peer label */
|
||||
};
|
||||
|
||||
|
@ -59,17 +60,10 @@ struct inode_smack {
|
|||
* A label access rule.
|
||||
*/
|
||||
struct smack_rule {
|
||||
char *smk_subject;
|
||||
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;
|
||||
struct list_head list;
|
||||
char *smk_subject;
|
||||
char *smk_object;
|
||||
int smk_access;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -85,7 +79,7 @@ struct smack_cipso {
|
|||
* An entry in the table identifying hosts.
|
||||
*/
|
||||
struct smk_netlbladdr {
|
||||
struct smk_netlbladdr *smk_next;
|
||||
struct list_head list;
|
||||
struct sockaddr_in smk_host; /* network address */
|
||||
struct in_addr smk_mask; /* network mask */
|
||||
char *smk_label; /* label */
|
||||
|
@ -113,7 +107,7 @@ struct smk_netlbladdr {
|
|||
* the cipso direct mapping in used internally.
|
||||
*/
|
||||
struct smack_known {
|
||||
struct smack_known *smk_next;
|
||||
struct list_head list;
|
||||
char smk_known[SMK_LABELLEN];
|
||||
u32 smk_secid;
|
||||
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_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
|
||||
|
||||
#define SMACK_CIPSO_OPTION "-CIPSO"
|
||||
|
||||
/*
|
||||
* How communications on this socket are treated.
|
||||
* 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 char *smack_net_ambient;
|
||||
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_hat;
|
||||
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_web;
|
||||
|
||||
extern struct smk_list_entry *smack_list;
|
||||
extern struct smk_netlbladdr *smack_netlbladdrs;
|
||||
extern struct list_head smack_known_list;
|
||||
extern struct list_head smack_rule_list;
|
||||
extern struct list_head smk_netlbladdr_list;
|
||||
|
||||
extern struct security_operations smack_ops;
|
||||
|
||||
/*
|
||||
|
|
|
@ -16,48 +16,42 @@
|
|||
#include "smack.h"
|
||||
|
||||
struct smack_known smack_known_huh = {
|
||||
.smk_next = NULL,
|
||||
.smk_known = "?",
|
||||
.smk_secid = 2,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_hat = {
|
||||
.smk_next = &smack_known_huh,
|
||||
.smk_known = "^",
|
||||
.smk_secid = 3,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_star = {
|
||||
.smk_next = &smack_known_hat,
|
||||
.smk_known = "*",
|
||||
.smk_secid = 4,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_floor = {
|
||||
.smk_next = &smack_known_star,
|
||||
.smk_known = "_",
|
||||
.smk_secid = 5,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_invalid = {
|
||||
.smk_next = &smack_known_floor,
|
||||
.smk_known = "",
|
||||
.smk_secid = 6,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_web = {
|
||||
.smk_next = &smack_known_invalid,
|
||||
.smk_known = "@",
|
||||
.smk_secid = 7,
|
||||
.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
|
||||
|
@ -87,7 +81,6 @@ static u32 smack_next_secid = 10;
|
|||
int smk_access(char *subject_label, char *object_label, int request)
|
||||
{
|
||||
u32 may = MAY_NOT;
|
||||
struct smk_list_entry *sp;
|
||||
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
|
||||
* good.
|
||||
*/
|
||||
for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
|
||||
srp = &sp->smk_rule;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
|
||||
if (srp->smk_subject == subject_label ||
|
||||
strcmp(srp->smk_subject, subject_label) == 0) {
|
||||
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.
|
||||
*/
|
||||
|
@ -228,14 +221,17 @@ struct smack_known *smk_import_entry(const char *string, int len)
|
|||
|
||||
mutex_lock(&smack_known_lock);
|
||||
|
||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
|
||||
found = 0;
|
||||
list_for_each_entry_rcu(skp, &smack_known_list, list) {
|
||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skp == NULL) {
|
||||
if (found == 0) {
|
||||
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
|
||||
if (skp != NULL) {
|
||||
skp->smk_next = smack_known;
|
||||
strncpy(skp->smk_known, smack, SMK_MAXLEN);
|
||||
skp->smk_secid = smack_next_secid++;
|
||||
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
|
||||
* filled before putting it on the list.
|
||||
*/
|
||||
smp_mb();
|
||||
smack_known = skp;
|
||||
list_add_rcu(&skp->list, &smack_known_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,6 +261,9 @@ char *smk_import(const char *string, int len)
|
|||
{
|
||||
struct smack_known *skp;
|
||||
|
||||
/* labels cannot begin with a '-' */
|
||||
if (string[0] == '-')
|
||||
return NULL;
|
||||
skp = smk_import_entry(string, len);
|
||||
if (skp == NULL)
|
||||
return NULL;
|
||||
|
@ -283,14 +281,19 @@ char *smack_from_secid(const u32 secid)
|
|||
{
|
||||
struct smack_known *skp;
|
||||
|
||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
||||
if (skp->smk_secid == secid)
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(skp, &smack_known_list, list) {
|
||||
if (skp->smk_secid == secid) {
|
||||
rcu_read_unlock();
|
||||
return skp->smk_known;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got this far someone asked for the translation
|
||||
* of a secid that is not on the list.
|
||||
*/
|
||||
rcu_read_unlock();
|
||||
return smack_known_invalid.smk_known;
|
||||
}
|
||||
|
||||
|
@ -305,9 +308,14 @@ u32 smack_to_secid(const char *smack)
|
|||
{
|
||||
struct smack_known *skp;
|
||||
|
||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
|
||||
rcu_read_lock();
|
||||
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;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -332,7 +340,8 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
|||
struct smack_known *kp;
|
||||
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)
|
||||
continue;
|
||||
|
||||
|
@ -344,6 +353,7 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
|||
|
||||
spin_unlock_bh(&kp->smk_cipsolock);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (final == NULL)
|
||||
final = smack_known_huh.smk_known;
|
||||
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)
|
||||
{
|
||||
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 ||
|
||||
strcmp(kp->smk_known, smack) == 0)
|
||||
strcmp(kp->smk_known, smack) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (kp == NULL || kp->smk_cipso == NULL)
|
||||
if (found == 0 || kp->smk_cipso == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* 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
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -20,6 +22,7 @@
|
|||
#include <linux/ext2_fs.h>
|
||||
#include <linux/kd.h>
|
||||
#include <asm/ioctls.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.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) {
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
/* a label cannot be void and cannot begin with '-' */
|
||||
if (size == 0 || (size > 0 && ((char *)value)[0] == '-'))
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
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_out = csp;
|
||||
ssp->smk_labeled = SMACK_CIPSO_SOCKET;
|
||||
ssp->smk_packet[0] = '\0';
|
||||
|
||||
sk->sk_security = ssp;
|
||||
|
@ -1294,6 +1299,43 @@ static void smack_sk_free_security(struct sock *sk)
|
|||
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
|
||||
* @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)
|
||||
{
|
||||
struct socket_smack *ssp;
|
||||
struct socket_smack *ssp = sk->sk_security;
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
int rc = 0;
|
||||
|
||||
ssp = sk->sk_security;
|
||||
/*
|
||||
* Usually the netlabel code will handle changing the
|
||||
* packet labeling based on the label.
|
||||
|
@ -1387,26 +1428,50 @@ static int smack_netlabel(struct sock *sk, int labeled)
|
|||
else {
|
||||
netlbl_secattr_init(&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);
|
||||
}
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @inode: the object
|
||||
|
@ -1428,7 +1493,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
|||
struct socket *sock;
|
||||
int rc = 0;
|
||||
|
||||
if (value == NULL || size > SMK_LABELLEN)
|
||||
if (value == NULL || size > SMK_LABELLEN || size == 0)
|
||||
return -EACCES;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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,
|
||||
int addrlen)
|
||||
{
|
||||
struct socket_smack *ssp = sock->sk->sk_security;
|
||||
char *hostsp;
|
||||
int rc;
|
||||
|
||||
if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
|
||||
return 0;
|
||||
|
||||
if (addrlen < sizeof(struct sockaddr_in))
|
||||
return -EINVAL;
|
||||
|
||||
hostsp = smack_host_label((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;
|
||||
return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2260,9 +2272,6 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
|||
int size)
|
||||
{
|
||||
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
|
||||
|
@ -2270,22 +2279,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
|||
if (sip == NULL || sip->sin_family != PF_INET)
|
||||
return 0;
|
||||
|
||||
hostsp = smack_host_label(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;
|
||||
|
||||
return smack_netlabel_send(sock->sk, sip);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2490,31 +2484,24 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
|||
}
|
||||
|
||||
/**
|
||||
* smack_sock_graft - graft access state between two sockets
|
||||
* @sk: fresh sock
|
||||
* @parent: donor socket
|
||||
* smack_sock_graft - Initialize a newly created socket with an existing sock
|
||||
* @sk: child sock
|
||||
* @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)
|
||||
{
|
||||
struct socket_smack *ssp;
|
||||
int rc;
|
||||
|
||||
if (sk == NULL)
|
||||
return;
|
||||
|
||||
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
|
||||
if (sk == NULL ||
|
||||
(sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
|
||||
return;
|
||||
|
||||
ssp = sk->sk_security;
|
||||
ssp->smk_in = ssp->smk_out = current_security();
|
||||
ssp->smk_packet[0] = '\0';
|
||||
|
||||
rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
/* cssp->smk_packet is already set in smack_inet_csk_clone() */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
struct request_sock *req)
|
||||
{
|
||||
struct netlbl_lsm_secattr skb_secattr;
|
||||
u16 family = sk->sk_family;
|
||||
struct socket_smack *ssp = sk->sk_security;
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
struct sockaddr_in addr;
|
||||
struct iphdr *hdr;
|
||||
char smack[SMK_LABELLEN];
|
||||
int rc;
|
||||
|
||||
if (skb == NULL)
|
||||
return -EACCES;
|
||||
/* handle mapped IPv4 packets arriving via IPv6 sockets */
|
||||
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
|
||||
family = PF_INET;
|
||||
|
||||
netlbl_secattr_init(&skb_secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
|
||||
netlbl_secattr_init(&secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0)
|
||||
smack_from_secattr(&skb_secattr, smack);
|
||||
smack_from_secattr(&secattr, smack);
|
||||
else
|
||||
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
|
||||
* be able to write here. Read access is not required.
|
||||
*
|
||||
* If the request is successful save the peer's label
|
||||
* so that SO_PEERCRED can report it.
|
||||
* Receiving a packet requires that the other end be able to write
|
||||
* here. Read access is not required.
|
||||
*/
|
||||
rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
|
||||
if (rc == 0)
|
||||
strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
|
||||
if (rc != 0)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -2909,6 +2943,7 @@ struct security_operations smack_ops = {
|
|||
.sk_free_security = smack_sk_free_security,
|
||||
.sock_graft = smack_sock_graft,
|
||||
.inet_conn_request = smack_inet_conn_request,
|
||||
.inet_csk_clone = smack_inet_csk_clone,
|
||||
|
||||
/* key management security hooks */
|
||||
#ifdef CONFIG_KEYS
|
||||
|
@ -2930,6 +2965,17 @@ struct security_operations smack_ops = {
|
|||
.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
|
||||
*
|
||||
|
@ -2950,6 +2996,8 @@ static __init int smack_init(void)
|
|||
cred = (struct cred *) current->cred;
|
||||
cred->security = &smack_known_floor.smk_known;
|
||||
|
||||
/* initilize the smack_know_list */
|
||||
init_smack_know_list();
|
||||
/*
|
||||
* Initialize locks
|
||||
*/
|
||||
|
|
|
@ -80,10 +80,14 @@ char *smack_onlycap;
|
|||
* Packets are sent there unlabeled, but only from tasks that
|
||||
* 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;
|
||||
struct smk_list_entry *smack_list;
|
||||
|
||||
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
|
||||
|
||||
|
||||
#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)
|
||||
return NULL;
|
||||
|
||||
return smack_list;
|
||||
if (list_empty(&smack_rule_list))
|
||||
return NULL;
|
||||
return smack_rule_list.next;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return skp;
|
||||
return NULL;
|
||||
}
|
||||
return list->next;
|
||||
}
|
||||
|
||||
static int load_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct smk_list_entry *slp = (struct smk_list_entry *) v;
|
||||
struct smack_rule *srp = &slp->smk_rule;
|
||||
struct list_head *list = v;
|
||||
struct smack_rule *srp =
|
||||
list_entry(list, struct smack_rule, list);
|
||||
|
||||
seq_printf(s, "%s %s", (char *)srp->smk_subject,
|
||||
(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)
|
||||
{
|
||||
struct smk_list_entry *sp;
|
||||
struct smk_list_entry *newp;
|
||||
struct smack_rule *sp;
|
||||
int ret = 0;
|
||||
|
||||
int found;
|
||||
mutex_lock(&smack_list_lock);
|
||||
|
||||
for (sp = smack_list; sp != NULL; sp = sp->smk_next)
|
||||
if (sp->smk_rule.smk_subject == srp->smk_subject &&
|
||||
sp->smk_rule.smk_object == srp->smk_object) {
|
||||
sp->smk_rule.smk_access = srp->smk_access;
|
||||
found = 0;
|
||||
list_for_each_entry_rcu(sp, &smack_rule_list, list) {
|
||||
if (sp->smk_subject == srp->smk_subject &&
|
||||
sp->smk_object == srp->smk_object) {
|
||||
found = 1;
|
||||
sp->smk_access = srp->smk_access;
|
||||
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);
|
||||
|
||||
return ret;
|
||||
|
@ -261,7 +259,7 @@ out:
|
|||
static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct smack_rule rule;
|
||||
struct smack_rule *rule;
|
||||
char *data;
|
||||
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))
|
||||
return -EPERM;
|
||||
if (*ppos != 0)
|
||||
return -EINVAL;
|
||||
if (count != SMK_LOADLEN)
|
||||
|
||||
if (*ppos != 0 || count != SMK_LOADLEN)
|
||||
return -EINVAL;
|
||||
|
||||
data = kzalloc(count, GFP_KERNEL);
|
||||
|
@ -286,25 +283,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rule.smk_subject = smk_import(data, 0);
|
||||
if (rule.smk_subject == NULL)
|
||||
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||
if (rule == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
|
||||
if (rule.smk_object == NULL)
|
||||
goto out;
|
||||
rule->smk_subject = smk_import(data, 0);
|
||||
if (rule->smk_subject == NULL)
|
||||
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]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
rule.smk_access |= MAY_READ;
|
||||
rule->smk_access |= MAY_READ;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
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;
|
||||
case 'w':
|
||||
case 'W':
|
||||
rule.smk_access |= MAY_WRITE;
|
||||
rule->smk_access |= MAY_WRITE;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
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;
|
||||
case 'x':
|
||||
case 'X':
|
||||
rule.smk_access |= MAY_EXEC;
|
||||
rule->smk_access |= MAY_EXEC;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
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;
|
||||
case 'a':
|
||||
case 'A':
|
||||
rule.smk_access |= MAY_APPEND;
|
||||
rule->smk_access |= MAY_APPEND;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
rc = smk_set_access(&rule);
|
||||
rc = smk_set_access(rule);
|
||||
|
||||
if (!rc)
|
||||
rc = count;
|
||||
goto out;
|
||||
|
||||
out_free_rule:
|
||||
kfree(rule);
|
||||
out:
|
||||
kfree(data);
|
||||
return rc;
|
||||
|
@ -433,24 +439,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
|
|||
{
|
||||
if (*pos == SEQ_READ_FINISHED)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
skp = skp->smk_next;
|
||||
|
||||
if (skp == NULL)
|
||||
if (list_is_last(list, &smack_known_list)) {
|
||||
*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)
|
||||
{
|
||||
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;
|
||||
char *cbp;
|
||||
char sep = '/';
|
||||
|
@ -558,6 +568,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
|
|||
goto unlockedout;
|
||||
}
|
||||
|
||||
/* labels cannot begin with a '-' */
|
||||
if (data[0] == '-') {
|
||||
rc = -EINVAL;
|
||||
goto unlockedout;
|
||||
}
|
||||
data[count] = '\0';
|
||||
rule = data;
|
||||
/*
|
||||
|
@ -638,18 +653,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
|
|||
{
|
||||
if (*pos == SEQ_READ_FINISHED)
|
||||
return NULL;
|
||||
|
||||
return smack_netlbladdrs;
|
||||
if (list_empty(&smk_netlbladdr_list))
|
||||
return NULL;
|
||||
return smk_netlbladdr_list.next;
|
||||
}
|
||||
|
||||
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;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return skp;
|
||||
return list->next;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
int maskn;
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
struct smk_netlbladdr *m;
|
||||
struct smk_netlbladdr *m, *m_next;
|
||||
|
||||
if (smack_netlbladdrs == NULL) {
|
||||
smack_netlbladdrs = new;
|
||||
if (list_empty(&smk_netlbladdr_list)) {
|
||||
list_add_rcu(&new->list, &smk_netlbladdr_list);
|
||||
return;
|
||||
}
|
||||
|
||||
m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
|
||||
struct smk_netlbladdr, list);
|
||||
|
||||
/* the comparison '>' is a bit hacky, but works */
|
||||
if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
|
||||
new->smk_next = smack_netlbladdrs;
|
||||
smack_netlbladdrs = new;
|
||||
if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
|
||||
list_add_rcu(&new->list, &smk_netlbladdr_list);
|
||||
return;
|
||||
}
|
||||
for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
|
||||
if (m->smk_next == NULL) {
|
||||
m->smk_next = new;
|
||||
|
||||
list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
|
||||
if (list_is_last(&m->list, &smk_netlbladdr_list)) {
|
||||
list_add_rcu(&new->list, &m->list);
|
||||
return;
|
||||
}
|
||||
if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
|
||||
new->smk_next = m->smk_next;
|
||||
m->smk_next = new;
|
||||
m_next = list_entry(rcu_dereference(m->list.next),
|
||||
struct smk_netlbladdr, list);
|
||||
if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
|
||||
list_add_rcu(&new->list, &m->list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -755,6 +781,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
|||
struct netlbl_audit audit_info;
|
||||
struct in_addr mask;
|
||||
unsigned int m;
|
||||
int found;
|
||||
u32 mask_bits = (1<<31);
|
||||
__be32 nsa;
|
||||
u32 temp_mask;
|
||||
|
@ -789,9 +816,18 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
|||
if (m > BEBITS)
|
||||
return -EINVAL;
|
||||
|
||||
sp = smk_import(smack, 0);
|
||||
if (sp == NULL)
|
||||
return -EINVAL;
|
||||
/* if smack begins with '-', its an option, don't import it */
|
||||
if (smack[0] != '-') {
|
||||
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--) {
|
||||
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;
|
||||
/* 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 &&
|
||||
skp->smk_mask.s_addr == mask.s_addr)
|
||||
skp->smk_mask.s_addr == mask.s_addr) {
|
||||
found = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
smk_netlabel_audit_set(&audit_info);
|
||||
|
||||
if (skp == NULL) {
|
||||
if (found == 0) {
|
||||
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
||||
if (skp == NULL)
|
||||
rc = -ENOMEM;
|
||||
|
@ -827,18 +866,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
|||
smk_netlbladdr_insert(skp);
|
||||
}
|
||||
} else {
|
||||
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
|
||||
&skp->smk_host.sin_addr, &skp->smk_mask,
|
||||
PF_INET, &audit_info);
|
||||
/* we delete the unlabeled entry, only if the previous label
|
||||
* wasnt the special CIPSO option */
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now tell netlabel about the single label nature of
|
||||
* this host so that incoming packets get labeled.
|
||||
* but only if we didn't get the special CIPSO option
|
||||
*/
|
||||
|
||||
if (rc == 0)
|
||||
if (rc == 0 && sp != smack_cipso_option)
|
||||
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
|
||||
&skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
|
||||
smack_to_secid(skp->smk_label), &audit_info);
|
||||
|
|
|
@ -55,7 +55,7 @@ struct tomoyo_path_info {
|
|||
struct tomoyo_path_info_with_data {
|
||||
/* Keep "head" first, for this pointer is passed to tomoyo_free(). */
|
||||
struct tomoyo_path_info head;
|
||||
char bariier1[16]; /* Safeguard for overrun. */
|
||||
char barrier1[16]; /* Safeguard for overrun. */
|
||||
char body[TOMOYO_MAX_PATHNAME_LEN];
|
||||
char barrier2[16]; /* Safeguard for overrun. */
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче