Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 22292
b: refs/heads/master
c: 2c7946a
h: refs/heads/master
v: v3
  • Loading branch information
Catherine Zhang authored and David S. Miller committed Mar 21, 2006
1 parent 09b1b60 commit 8e0b078
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 18 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: be33690d8fcf40377f16193c463681170eb6b295
refs/heads/master: 2c7946a7bf45ae86736ab3b43d0085e43947945c
1 change: 1 addition & 0 deletions trunk/include/linux/in.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct in_addr {
#define IP_FREEBIND 15
#define IP_IPSEC_POLICY 16
#define IP_XFRM_POLICY 17
#define IP_PASSSEC 18

/* BSD compatibility */
#define IP_RECVRETOPTS IP_RETOPTS
Expand Down
25 changes: 19 additions & 6 deletions trunk/include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -1286,7 +1286,8 @@ struct security_operations {
int (*socket_setsockopt) (struct socket * sock, int level, int optname);
int (*socket_shutdown) (struct socket * sock, int how);
int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
int (*socket_getpeersec_dgram) (struct sk_buff *skb, char **secdata, u32 *seclen);
int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
void (*sk_free_security) (struct sock *sk);
unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir);
Expand Down Expand Up @@ -2741,10 +2742,16 @@ static inline int security_sock_rcv_skb (struct sock * sk,
return security_ops->socket_sock_rcv_skb (sk, skb);
}

static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
return security_ops->socket_getpeersec(sock, optval, optlen, len);
return security_ops->socket_getpeersec_stream(sock, optval, optlen, len);
}

static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
u32 *seclen)
{
return security_ops->socket_getpeersec_dgram(skb, secdata, seclen);
}

static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
Expand Down Expand Up @@ -2863,8 +2870,14 @@ static inline int security_sock_rcv_skb (struct sock * sk,
return 0;
}

static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
return -ENOPROTOOPT;
}

static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
u32 *seclen)
{
return -ENOPROTOOPT;
}
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ __KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__

#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
#define SCM_SECURITY 0x03 /* rw: security label */

struct ucred {
__u32 pid;
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;

case SO_PEERSEC:
return security_socket_getpeersec(sock, optval, optlen, len);
return security_socket_getpeersec_stream(sock, optval, optlen, len);

default:
return(-ENOPROTOOPT);
Expand Down
31 changes: 30 additions & 1 deletion trunk/net/ipv4/ip_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#define IP_CMSG_TOS 4
#define IP_CMSG_RECVOPTS 8
#define IP_CMSG_RETOPTS 16
#define IP_CMSG_PASSSEC 32

/*
* SOL_IP control messages.
Expand Down Expand Up @@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
}

static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
{
char *secdata;
u32 seclen;
int err;

err = security_socket_getpeersec_dgram(skb, &secdata, &seclen);
if (err)
return;

put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
}


void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
{
Expand Down Expand Up @@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)

if (flags & 1)
ip_cmsg_recv_retopts(msg, skb);
if ((flags>>=1) == 0)
return;

if (flags & 1)
ip_cmsg_recv_security(msg, skb);
}

int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
Expand Down Expand Up @@ -393,7 +412,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
(1<<IP_RETOPTS) | (1<<IP_TOS) |
(1<<IP_TTL) | (1<<IP_HDRINCL) |
(1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) ||
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
(1<<IP_PASSSEC))) ||
optname == IP_MULTICAST_TTL ||
optname == IP_MULTICAST_LOOP) {
if (optlen >= sizeof(int)) {
Expand Down Expand Up @@ -478,6 +498,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
else
inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
break;
case IP_PASSSEC:
if (val)
inet->cmsg_flags |= IP_CMSG_PASSSEC;
else
inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
break;
case IP_TOS: /* This sets both TOS and Precedence */
if (sk->sk_type == SOCK_STREAM) {
val &= ~3;
Expand Down Expand Up @@ -932,6 +958,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
case IP_RETOPTS:
val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
break;
case IP_PASSSEC:
val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
break;
case IP_TOS:
val = inet->tos;
break;
Expand Down
10 changes: 8 additions & 2 deletions trunk/security/dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,8 +763,14 @@ static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
return 0;
}

static int dummy_socket_getpeersec(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
return -ENOPROTOOPT;
}

static int dummy_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
u32 *seclen)
{
return -ENOPROTOOPT;
}
Expand Down
46 changes: 39 additions & 7 deletions trunk/security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -3318,24 +3318,38 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
}

static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
int err = 0;
char *scontext;
u32 scontext_len;
struct sk_security_struct *ssec;
struct inode_security_struct *isec;
u32 peer_sid = 0;

isec = SOCK_INODE(sock)->i_security;
if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {

/* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */
if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) {
ssec = sock->sk->sk_security;
peer_sid = ssec->peer_sid;
}
else if (isec->sclass == SECCLASS_TCP_SOCKET) {
peer_sid = selinux_socket_getpeer_stream(sock->sk);

if (peer_sid == SECSID_NULL) {
err = -ENOPROTOOPT;
goto out;
}
}
else {
err = -ENOPROTOOPT;
goto out;
}

ssec = sock->sk->sk_security;

err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
err = security_sid_to_context(peer_sid, &scontext, &scontext_len);

if (err)
goto out;

Expand All @@ -3356,6 +3370,23 @@ static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
return err;
}

static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
{
int err = 0;
u32 peer_sid = selinux_socket_getpeer_dgram(skb);

if (peer_sid == SECSID_NULL)
return -EINVAL;

err = security_sid_to_context(peer_sid, secdata, seclen);
if (err)
return err;

return 0;
}



static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
return sk_alloc_security(sk, family, priority);
Expand Down Expand Up @@ -4344,7 +4375,8 @@ static struct security_operations selinux_ops = {
.socket_setsockopt = selinux_socket_setsockopt,
.socket_shutdown = selinux_socket_shutdown,
.socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
.socket_getpeersec = selinux_socket_getpeersec,
.socket_getpeersec_stream = selinux_socket_getpeersec_stream,
.socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
.sk_alloc_security = selinux_sk_alloc_security,
.sk_free_security = selinux_sk_free_security,
.sk_getsid = selinux_sk_getsid_security,
Expand Down
2 changes: 2 additions & 0 deletions trunk/security/selinux/include/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ static inline u32 selinux_no_sk_sid(struct flowi *fl)
#ifdef CONFIG_SECURITY_NETWORK_XFRM
int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb);
int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb);
u32 selinux_socket_getpeer_stream(struct sock *sk);
u32 selinux_socket_getpeer_dgram(struct sk_buff *skb);
#else
static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
{
Expand Down
68 changes: 68 additions & 0 deletions trunk/security/selinux/xfrm.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,74 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
kfree(ctx);
}

/*
* SELinux internal function to retrieve the context of a connected
* (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security
* association used to connect to the remote socket.
*
* Retrieve via getsockopt SO_PEERSEC.
*/
u32 selinux_socket_getpeer_stream(struct sock *sk)
{
struct dst_entry *dst, *dst_test;
u32 peer_sid = SECSID_NULL;

if (sk->sk_state != TCP_ESTABLISHED)
goto out;

dst = sk_dst_get(sk);
if (!dst)
goto out;

for (dst_test = dst; dst_test != 0;
dst_test = dst_test->child) {
struct xfrm_state *x = dst_test->xfrm;

if (x && selinux_authorizable_xfrm(x)) {
struct xfrm_sec_ctx *ctx = x->security;
peer_sid = ctx->ctx_sid;
break;
}
}
dst_release(dst);

out:
return peer_sid;
}

/*
* SELinux internal function to retrieve the context of a UDP packet
* based on its security association used to connect to the remote socket.
*
* Retrieve via setsockopt IP_PASSSEC and recvmsg with control message
* type SCM_SECURITY.
*/
u32 selinux_socket_getpeer_dgram(struct sk_buff *skb)
{
struct sec_path *sp;

if (skb == NULL)
return SECSID_NULL;

if (skb->sk->sk_protocol != IPPROTO_UDP)
return SECSID_NULL;

sp = skb->sp;
if (sp) {
int i;

for (i = sp->len-1; i >= 0; i--) {
struct xfrm_state *x = sp->x[i].xvec;
if (selinux_authorizable_xfrm(x)) {
struct xfrm_sec_ctx *ctx = x->security;
return ctx->ctx_sid;
}
}
}

return SECSID_NULL;
}

/*
* LSM hook that controls access to unlabelled packets. If
* a xfrm_state is authorizable (defined by macro) then it was
Expand Down

0 comments on commit 8e0b078

Please sign in to comment.