Skip to content

Commit

Permalink
[MLSXFRM]: Add flow labeling
Browse files Browse the repository at this point in the history
This labels the flows that could utilize IPSec xfrms at the points the
flows are defined so that IPSec policy and SAs at the right label can
be used.

The following protos are currently not handled, but they should
continue to be able to use single-labeled IPSec like they currently
do.

ipmr
ip_gre
ipip
igmp
sit
sctp
ip6_tunnel (IPv6 over IPv6 tunnel device)
decnet

Signed-off-by: Venkat Yekkirala <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Venkat Yekkirala authored and David S. Miller committed Sep 22, 2006
1 parent 4e2ba18 commit beb8d13
Show file tree
Hide file tree
Showing 26 changed files with 79 additions and 40 deletions.
38 changes: 25 additions & 13 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/sched.h>
#include <linux/key.h>
#include <linux/xfrm.h>
#include <net/flow.h>

struct ctl_table;

Expand Down Expand Up @@ -815,8 +816,8 @@ struct swap_info_struct;
* Deallocate security structure.
* @sk_clone_security:
* Clone/copy security structure.
* @sk_getsid:
* Retrieve the LSM-specific sid for the sock to enable caching of network
* @sk_getsecid:
* Retrieve the LSM-specific secid for the sock to enable caching of network
* authorizations.
*
* Security hooks for XFRM operations.
Expand Down Expand Up @@ -882,8 +883,9 @@ struct swap_info_struct;
* Return 1 if there is a match.
* @xfrm_decode_session:
* @skb points to skb to decode.
* @fl points to the flow key to set.
* Return 0 if successful decoding.
* @secid points to the flow key secid to set.
* @ckall says if all xfrms used should be checked for same secid.
* Return 0 if ckall is zero or all xfrms used have the same secid.
*
* Security hooks affecting all Key Management operations
*
Expand Down Expand Up @@ -1353,7 +1355,7 @@ struct security_operations {
int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
void (*sk_free_security) (struct sock *sk);
void (*sk_clone_security) (const struct sock *sk, struct sock *newsk);
unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir);
void (*sk_getsecid) (struct sock *sk, u32 *secid);
#endif /* CONFIG_SECURITY_NETWORK */

#ifdef CONFIG_SECURITY_NETWORK_XFRM
Expand All @@ -1370,7 +1372,7 @@ struct security_operations {
int (*xfrm_state_pol_flow_match)(struct xfrm_state *x,
struct xfrm_policy *xp, struct flowi *fl);
int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm);
int (*xfrm_decode_session)(struct sk_buff *skb, struct flowi *fl);
int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */

/* key management security hooks */
Expand Down Expand Up @@ -2917,9 +2919,9 @@ static inline void security_sk_clone(const struct sock *sk, struct sock *newsk)
return security_ops->sk_clone_security(sk, newsk);
}

static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir)
static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
{
return security_ops->sk_getsid(sk, fl, dir);
security_ops->sk_getsecid(sk, &fl->secid);
}
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct socket * sock,
Expand Down Expand Up @@ -3047,9 +3049,8 @@ static inline void security_sk_clone(const struct sock *sk, struct sock *newsk)
{
}

static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir)
static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK */

Expand Down Expand Up @@ -3114,9 +3115,16 @@ static inline int security_xfrm_flow_state_match(struct flowi *fl, struct xfrm_s
return security_ops->xfrm_flow_state_match(fl, xfrm);
}

static inline int security_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl)
static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
{
return security_ops->xfrm_decode_session(skb, secid, 1);
}

static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl)
{
return security_ops->xfrm_decode_session(skb, fl);
int rc = security_ops->xfrm_decode_session(skb, &fl->secid, 0);

BUG_ON(rc);
}
#else /* CONFIG_SECURITY_NETWORK_XFRM */
static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx)
Expand Down Expand Up @@ -3176,11 +3184,15 @@ static inline int security_xfrm_flow_state_match(struct flowi *fl,
return 1;
}

static inline int security_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl)
static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
{
return 0;
}

static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl)
{
}

#endif /* CONFIG_SECURITY_NETWORK_XFRM */

#ifdef CONFIG_KEYS
Expand Down
3 changes: 3 additions & 0 deletions include/net/route.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/route.h>
#include <linux/ip.h>
#include <linux/cache.h>
#include <linux/security.h>

#ifndef __KERNEL__
#warning This file is not supposed to be used outside of kernel.
Expand Down Expand Up @@ -166,6 +167,7 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst,
ip_rt_put(*rp);
*rp = NULL;
}
security_sk_classify_flow(sk, &fl);
return ip_route_output_flow(rp, &fl, sk, 0);
}

Expand All @@ -182,6 +184,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
fl.proto = protocol;
ip_rt_put(*rp);
*rp = NULL;
security_sk_classify_flow(sk, &fl);
return ip_route_output_flow(rp, &fl, sk, 0);
}
return 0;
Expand Down
1 change: 1 addition & 0 deletions net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
}
};

security_skb_classify_flow(skb, &fl);
if (ip_route_output_flow(&rt, &fl, sk, 0)) {
IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
return NULL;
Expand Down
6 changes: 6 additions & 0 deletions net/dccp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = usin->sin6_port;
fl.fl_ip_sport = inet->sport;
security_sk_classify_flow(sk, &fl);

if (np->opt != NULL && np->opt->srcrt != NULL) {
const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
Expand Down Expand Up @@ -322,6 +323,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_sk_classify_flow(sk, &fl);

err = ip6_dst_lookup(sk, &dst, &fl);
if (err) {
Expand Down Expand Up @@ -422,6 +424,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
fl.oif = ireq6->iif;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
security_sk_classify_flow(sk, &fl);

if (dst == NULL) {
opt = np->opt;
Expand Down Expand Up @@ -566,6 +569,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
fl.oif = inet6_iif(rxskb);
fl.fl_ip_dport = dh->dccph_dport;
fl.fl_ip_sport = dh->dccph_sport;
security_skb_classify_flow(rxskb, &fl);

/* sk = NULL, but it is safe for now. RST socket required. */
if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
Expand Down Expand Up @@ -622,6 +626,7 @@ static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb,
fl.oif = inet6_iif(rxskb);
fl.fl_ip_dport = dh->dccph_dport;
fl.fl_ip_sport = dh->dccph_sport;
security_skb_classify_flow(rxskb, &fl);

if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
Expand Down Expand Up @@ -842,6 +847,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
security_sk_classify_flow(sk, &fl);

if (ip6_dst_lookup(sk, &dst, &fl))
goto out;
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,7 @@ int inet_sk_rebuild_header(struct sock *sk)
},
};

security_sk_classify_flow(sk, &fl);
err = ip_route_output_flow(&rt, &fl, sk, 0);
}
if (!err)
Expand Down
2 changes: 2 additions & 0 deletions net/ipv4/icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
.saddr = rt->rt_spec_dst,
.tos = RT_TOS(skb->nh.iph->tos) } },
.proto = IPPROTO_ICMP };
security_skb_classify_flow(skb, &fl);
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
Expand Down Expand Up @@ -560,6 +561,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
}
}
};
security_skb_classify_flow(skb_in, &fl);
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/inet_connection_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
{ .sport = inet_sk(sk)->sport,
.dport = ireq->rmt_port } } };

security_sk_classify_flow(sk, &fl);
if (ip_route_output_flow(&rt, &fl, sk, 0)) {
IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
return NULL;
Expand Down
2 changes: 2 additions & 0 deletions net/ipv4/ip_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
* keep trying until route appears or the connection times
* itself out.
*/
security_sk_classify_flow(sk, &fl);
if (ip_route_output_flow(&rt, &fl, sk, 0))
goto no_route;
}
Expand Down Expand Up @@ -1366,6 +1367,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
{ .sport = skb->h.th->dest,
.dport = skb->h.th->source } },
.proto = sk->sk_protocol };
security_skb_classify_flow(skb, &fl);
if (ip_route_output_key(&rt, &fl))
return;
}
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/netfilter/ipt_REJECT.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb,
fl.proto = IPPROTO_TCP;
fl.fl_ip_sport = tcph->dest;
fl.fl_ip_dport = tcph->source;
security_skb_classify_flow(skb, &fl);

xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);

Expand Down
1 change: 1 addition & 0 deletions net/ipv4/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (!inet->hdrincl)
raw_probe_proto_opt(&fl, msg);

security_sk_classify_flow(sk, &fl);
err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
}
if (err)
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/syncookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
.uli_u = { .ports =
{ .sport = skb->h.th->dest,
.dport = skb->h.th->source } } };
security_sk_classify_flow(sk, &fl);
if (ip_route_output_key(&rt, &fl)) {
reqsk_free(req);
goto out;
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
.uli_u = { .ports =
{ .sport = inet->sport,
.dport = dport } } };
security_sk_classify_flow(sk, &fl);
err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
if (err)
goto out;
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_sk_classify_flow(sk, &fl);

if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/datagram.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
fl.oif = np->mcast_oif;

security_sk_classify_flow(sk, &fl);

if (flowlabel) {
if (flowlabel->opt && flowlabel->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
fl.oif = iif;
fl.fl_icmp_type = type;
fl.fl_icmp_code = code;
security_skb_classify_flow(skb, &fl);

if (icmpv6_xmit_lock())
return;
Expand Down Expand Up @@ -472,6 +473,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
ipv6_addr_copy(&fl.fl6_src, saddr);
fl.oif = skb->dev->ifindex;
fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
security_skb_classify_flow(skb, &fl);

if (icmpv6_xmit_lock())
return;
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/inet6_connection_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_sport = inet->sport;
fl.fl_ip_dport = inet->dport;
security_sk_classify_flow(sk, &fl);

if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ static inline void ndisc_flow_init(struct flowi *fl, u8 type,
fl->proto = IPPROTO_ICMPV6;
fl->fl_icmp_type = type;
fl->fl_icmp_code = 0;
security_sk_classify_flow(ndisc_socket->sk, fl);
}

static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/netfilter/ip6t_REJECT.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static void send_reset(struct sk_buff *oldskb)
ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
fl.fl_ip_sport = otcph.dest;
fl.fl_ip_dport = otcph.source;
security_skb_classify_flow(oldskb, &fl);
dst = ip6_route_output(NULL, &fl);
if (dst == NULL)
return;
Expand Down
1 change: 1 addition & 0 deletions net/ipv6/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,

if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif;
security_sk_classify_flow(sk, &fl);

err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
Expand Down
7 changes: 7 additions & 0 deletions net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
final_p = &final;
}

security_sk_classify_flow(sk, &fl);

err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
goto failure;
Expand Down Expand Up @@ -374,6 +376,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_skb_classify_flow(skb, &fl);

if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
sk->sk_err_soft = -err;
Expand Down Expand Up @@ -467,6 +470,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
fl.oif = treq->iif;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
security_sk_classify_flow(sk, &fl);

if (dst == NULL) {
opt = np->opt;
Expand Down Expand Up @@ -625,6 +629,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
fl.oif = inet6_iif(skb);
fl.fl_ip_dport = t1->dest;
fl.fl_ip_sport = t1->source;
security_skb_classify_flow(skb, &fl);

/* sk = NULL, but it is safe for now. RST socket required. */
if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
Expand Down Expand Up @@ -691,6 +696,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
fl.oif = inet6_iif(skb);
fl.fl_ip_dport = t1->dest;
fl.fl_ip_sport = t1->source;
security_skb_classify_flow(skb, &fl);

if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
Expand Down Expand Up @@ -923,6 +929,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
security_sk_classify_flow(sk, &fl);

if (ip6_dst_lookup(sk, &dst, &fl))
goto out;
Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,8 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
connected = 0;
}

security_sk_classify_flow(sk, fl);

err = ip6_sk_dst_lookup(sk, &dst, fl);
if (err)
goto out;
Expand Down
Loading

0 comments on commit beb8d13

Please sign in to comment.