134b0fc544
When a security module is loaded (in this case, SELinux), the security_xfrm_policy_lookup() hook can return an access denied permission (or other error). We were not handling that correctly, and in fact inverting the return logic and propagating a false "ok" back up to xfrm_lookup(), which then allowed packets to pass as if they were not associated with an xfrm policy. The way I was seeing the problem was when connecting via IPsec to a confined service on an SELinux box (vsftpd), which did not have the appropriate SELinux policy permissions to send packets via IPsec. The first SYNACK would be blocked, because of an uncached lookup via flow_cache_lookup(), which would fail to resolve an xfrm policy because the SELinux policy is checked at that point via the resolver. However, retransmitted SYNACKs would then find a cached flow entry when calling into flow_cache_lookup() with a null xfrm policy, which is interpreted by xfrm_lookup() as the packet not having any associated policy and similarly to the first case, allowing it to pass without transformation. The solution presented here is to first ensure that errno values are correctly propagated all the way back up through the various call chains from security_xfrm_policy_lookup(), and handled correctly. Then, flow_cache_lookup() is modified, so that if the policy resolver fails (typically a permission denied via the security module), the flow cache entry is killed rather than having a null policy assigned (which indicates that the packet can pass freely). This also forces any future lookups for the same flow to consult the security module (e.g. SELinux) for current security policy (rather than, say, caching the error on the flow cache entry). Signed-off-by: James Morris <jmorris@namei.org>
109 lines
2.1 KiB
C
109 lines
2.1 KiB
C
/*
|
|
*
|
|
* Generic internet FLOW.
|
|
*
|
|
*/
|
|
|
|
#ifndef _NET_FLOW_H
|
|
#define _NET_FLOW_H
|
|
|
|
#include <linux/in6.h>
|
|
#include <asm/atomic.h>
|
|
|
|
struct flowi {
|
|
int oif;
|
|
int iif;
|
|
|
|
union {
|
|
struct {
|
|
__be32 daddr;
|
|
__be32 saddr;
|
|
__u32 fwmark;
|
|
__u8 tos;
|
|
__u8 scope;
|
|
} ip4_u;
|
|
|
|
struct {
|
|
struct in6_addr daddr;
|
|
struct in6_addr saddr;
|
|
__u32 fwmark;
|
|
__u32 flowlabel;
|
|
} ip6_u;
|
|
|
|
struct {
|
|
__le16 daddr;
|
|
__le16 saddr;
|
|
__u32 fwmark;
|
|
__u8 scope;
|
|
} dn_u;
|
|
} nl_u;
|
|
#define fld_dst nl_u.dn_u.daddr
|
|
#define fld_src nl_u.dn_u.saddr
|
|
#define fld_fwmark nl_u.dn_u.fwmark
|
|
#define fld_scope nl_u.dn_u.scope
|
|
#define fl6_dst nl_u.ip6_u.daddr
|
|
#define fl6_src nl_u.ip6_u.saddr
|
|
#define fl6_fwmark nl_u.ip6_u.fwmark
|
|
#define fl6_flowlabel nl_u.ip6_u.flowlabel
|
|
#define fl4_dst nl_u.ip4_u.daddr
|
|
#define fl4_src nl_u.ip4_u.saddr
|
|
#define fl4_fwmark nl_u.ip4_u.fwmark
|
|
#define fl4_tos nl_u.ip4_u.tos
|
|
#define fl4_scope nl_u.ip4_u.scope
|
|
|
|
__u8 proto;
|
|
__u8 flags;
|
|
#define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
|
|
union {
|
|
struct {
|
|
__be16 sport;
|
|
__be16 dport;
|
|
} ports;
|
|
|
|
struct {
|
|
__u8 type;
|
|
__u8 code;
|
|
} icmpt;
|
|
|
|
struct {
|
|
__le16 sport;
|
|
__le16 dport;
|
|
__u8 objnum;
|
|
__u8 objnamel; /* Not 16 bits since max val is 16 */
|
|
__u8 objname[16]; /* Not zero terminated */
|
|
} dnports;
|
|
|
|
__be32 spi;
|
|
|
|
#ifdef CONFIG_IPV6_MIP6
|
|
struct {
|
|
__u8 type;
|
|
} mht;
|
|
#endif
|
|
} uli_u;
|
|
#define fl_ip_sport uli_u.ports.sport
|
|
#define fl_ip_dport uli_u.ports.dport
|
|
#define fl_icmp_type uli_u.icmpt.type
|
|
#define fl_icmp_code uli_u.icmpt.code
|
|
#define fl_ipsec_spi uli_u.spi
|
|
#ifdef CONFIG_IPV6_MIP6
|
|
#define fl_mh_type uli_u.mht.type
|
|
#endif
|
|
__u32 secid; /* used by xfrm; see secid.txt */
|
|
} __attribute__((__aligned__(BITS_PER_LONG/8)));
|
|
|
|
#define FLOW_DIR_IN 0
|
|
#define FLOW_DIR_OUT 1
|
|
#define FLOW_DIR_FWD 2
|
|
|
|
struct sock;
|
|
typedef int (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir,
|
|
void **objp, atomic_t **obj_refp);
|
|
|
|
extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
|
|
flow_resolve_t resolver);
|
|
extern void flow_cache_flush(void);
|
|
extern atomic_t flow_cache_genid;
|
|
|
|
#endif
|