|
@@ -61,6 +61,13 @@ static unsigned int xfrm_state_genid;
|
|
static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
|
|
static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
|
|
static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
|
|
static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
|
|
|
|
|
|
|
|
+#ifdef CONFIG_AUDITSYSCALL
|
|
|
|
+static void xfrm_audit_state_replay(struct xfrm_state *x,
|
|
|
|
+ struct sk_buff *skb, __be32 net_seq);
|
|
|
|
+#else
|
|
|
|
+#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
|
|
|
|
+#endif /* CONFIG_AUDITSYSCALL */
|
|
|
|
+
|
|
static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
|
|
static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
|
|
xfrm_address_t *saddr,
|
|
xfrm_address_t *saddr,
|
|
u32 reqid,
|
|
u32 reqid,
|
|
@@ -1609,13 +1616,14 @@ static void xfrm_replay_timer_handler(unsigned long data)
|
|
spin_unlock(&x->lock);
|
|
spin_unlock(&x->lock);
|
|
}
|
|
}
|
|
|
|
|
|
-int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
|
|
|
|
|
|
+int xfrm_replay_check(struct xfrm_state *x,
|
|
|
|
+ struct sk_buff *skb, __be32 net_seq)
|
|
{
|
|
{
|
|
u32 diff;
|
|
u32 diff;
|
|
u32 seq = ntohl(net_seq);
|
|
u32 seq = ntohl(net_seq);
|
|
|
|
|
|
if (unlikely(seq == 0))
|
|
if (unlikely(seq == 0))
|
|
- return -EINVAL;
|
|
|
|
|
|
+ goto err;
|
|
|
|
|
|
if (likely(seq > x->replay.seq))
|
|
if (likely(seq > x->replay.seq))
|
|
return 0;
|
|
return 0;
|
|
@@ -1624,14 +1632,18 @@ int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
|
|
if (diff >= min_t(unsigned int, x->props.replay_window,
|
|
if (diff >= min_t(unsigned int, x->props.replay_window,
|
|
sizeof(x->replay.bitmap) * 8)) {
|
|
sizeof(x->replay.bitmap) * 8)) {
|
|
x->stats.replay_window++;
|
|
x->stats.replay_window++;
|
|
- return -EINVAL;
|
|
|
|
|
|
+ goto err;
|
|
}
|
|
}
|
|
|
|
|
|
if (x->replay.bitmap & (1U << diff)) {
|
|
if (x->replay.bitmap & (1U << diff)) {
|
|
x->stats.replay++;
|
|
x->stats.replay++;
|
|
- return -EINVAL;
|
|
|
|
|
|
+ goto err;
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+err:
|
|
|
|
+ xfrm_audit_state_replay(x, skb, net_seq);
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(xfrm_replay_check);
|
|
EXPORT_SYMBOL(xfrm_replay_check);
|
|
|
|
|
|
@@ -1996,8 +2008,8 @@ void __init xfrm_state_init(void)
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_AUDITSYSCALL
|
|
#ifdef CONFIG_AUDITSYSCALL
|
|
-static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x,
|
|
|
|
- struct audit_buffer *audit_buf)
|
|
|
|
|
|
+static inline void xfrm_audit_helper_sainfo(struct xfrm_state *x,
|
|
|
|
+ struct audit_buffer *audit_buf)
|
|
{
|
|
{
|
|
struct xfrm_sec_ctx *ctx = x->security;
|
|
struct xfrm_sec_ctx *ctx = x->security;
|
|
u32 spi = ntohl(x->id.spi);
|
|
u32 spi = ntohl(x->id.spi);
|
|
@@ -2024,18 +2036,45 @@ static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x,
|
|
audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
|
|
audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
|
|
|
|
+ struct audit_buffer *audit_buf)
|
|
|
|
+{
|
|
|
|
+ struct iphdr *iph4;
|
|
|
|
+ struct ipv6hdr *iph6;
|
|
|
|
+
|
|
|
|
+ switch (family) {
|
|
|
|
+ case AF_INET:
|
|
|
|
+ iph4 = ip_hdr(skb);
|
|
|
|
+ audit_log_format(audit_buf,
|
|
|
|
+ " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
|
|
|
|
+ NIPQUAD(iph4->saddr),
|
|
|
|
+ NIPQUAD(iph4->daddr));
|
|
|
|
+ break;
|
|
|
|
+ case AF_INET6:
|
|
|
|
+ iph6 = ipv6_hdr(skb);
|
|
|
|
+ audit_log_format(audit_buf,
|
|
|
|
+ " src=" NIP6_FMT " dst=" NIP6_FMT
|
|
|
|
+ " flowlbl=0x%x%x%x",
|
|
|
|
+ NIP6(iph6->saddr),
|
|
|
|
+ NIP6(iph6->daddr),
|
|
|
|
+ iph6->flow_lbl[0] & 0x0f,
|
|
|
|
+ iph6->flow_lbl[1],
|
|
|
|
+ iph6->flow_lbl[2]);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
void xfrm_audit_state_add(struct xfrm_state *x, int result,
|
|
void xfrm_audit_state_add(struct xfrm_state *x, int result,
|
|
u32 auid, u32 secid)
|
|
u32 auid, u32 secid)
|
|
{
|
|
{
|
|
struct audit_buffer *audit_buf;
|
|
struct audit_buffer *audit_buf;
|
|
|
|
|
|
- if (audit_enabled == 0)
|
|
|
|
- return;
|
|
|
|
- audit_buf = xfrm_audit_start(auid, secid);
|
|
|
|
|
|
+ audit_buf = xfrm_audit_start("SAD-add");
|
|
if (audit_buf == NULL)
|
|
if (audit_buf == NULL)
|
|
return;
|
|
return;
|
|
- audit_log_format(audit_buf, " op=SAD-add res=%u", result);
|
|
|
|
- xfrm_audit_common_stateinfo(x, audit_buf);
|
|
|
|
|
|
+ xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
|
|
|
|
+ xfrm_audit_helper_sainfo(x, audit_buf);
|
|
|
|
+ audit_log_format(audit_buf, " res=%u", result);
|
|
audit_log_end(audit_buf);
|
|
audit_log_end(audit_buf);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
|
|
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
|
|
@@ -2045,14 +2084,96 @@ void xfrm_audit_state_delete(struct xfrm_state *x, int result,
|
|
{
|
|
{
|
|
struct audit_buffer *audit_buf;
|
|
struct audit_buffer *audit_buf;
|
|
|
|
|
|
- if (audit_enabled == 0)
|
|
|
|
- return;
|
|
|
|
- audit_buf = xfrm_audit_start(auid, secid);
|
|
|
|
|
|
+ audit_buf = xfrm_audit_start("SAD-delete");
|
|
if (audit_buf == NULL)
|
|
if (audit_buf == NULL)
|
|
return;
|
|
return;
|
|
- audit_log_format(audit_buf, " op=SAD-delete res=%u", result);
|
|
|
|
- xfrm_audit_common_stateinfo(x, audit_buf);
|
|
|
|
|
|
+ xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
|
|
|
|
+ xfrm_audit_helper_sainfo(x, audit_buf);
|
|
|
|
+ audit_log_format(audit_buf, " res=%u", result);
|
|
audit_log_end(audit_buf);
|
|
audit_log_end(audit_buf);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
|
|
EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
|
|
|
|
+
|
|
|
|
+void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
|
|
|
|
+ struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ struct audit_buffer *audit_buf;
|
|
|
|
+ u32 spi;
|
|
|
|
+
|
|
|
|
+ audit_buf = xfrm_audit_start("SA-replay-overflow");
|
|
|
|
+ if (audit_buf == NULL)
|
|
|
|
+ return;
|
|
|
|
+ xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
|
|
|
|
+ /* don't record the sequence number because it's inherent in this kind
|
|
|
|
+ * of audit message */
|
|
|
|
+ spi = ntohl(x->id.spi);
|
|
|
|
+ audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
|
|
|
|
+ audit_log_end(audit_buf);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
|
|
|
|
+
|
|
|
|
+static void xfrm_audit_state_replay(struct xfrm_state *x,
|
|
|
|
+ struct sk_buff *skb, __be32 net_seq)
|
|
|
|
+{
|
|
|
|
+ struct audit_buffer *audit_buf;
|
|
|
|
+ u32 spi;
|
|
|
|
+
|
|
|
|
+ audit_buf = xfrm_audit_start("SA-replayed-pkt");
|
|
|
|
+ if (audit_buf == NULL)
|
|
|
|
+ return;
|
|
|
|
+ xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
|
|
|
|
+ spi = ntohl(x->id.spi);
|
|
|
|
+ audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
|
|
|
|
+ spi, spi, ntohl(net_seq));
|
|
|
|
+ audit_log_end(audit_buf);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
|
|
|
|
+{
|
|
|
|
+ struct audit_buffer *audit_buf;
|
|
|
|
+
|
|
|
|
+ audit_buf = xfrm_audit_start("SA-notfound");
|
|
|
|
+ if (audit_buf == NULL)
|
|
|
|
+ return;
|
|
|
|
+ xfrm_audit_helper_pktinfo(skb, family, audit_buf);
|
|
|
|
+ audit_log_end(audit_buf);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
|
|
|
|
+
|
|
|
|
+void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
|
|
|
|
+ __be32 net_spi, __be32 net_seq)
|
|
|
|
+{
|
|
|
|
+ struct audit_buffer *audit_buf;
|
|
|
|
+ u32 spi;
|
|
|
|
+
|
|
|
|
+ audit_buf = xfrm_audit_start("SA-notfound");
|
|
|
|
+ if (audit_buf == NULL)
|
|
|
|
+ return;
|
|
|
|
+ xfrm_audit_helper_pktinfo(skb, family, audit_buf);
|
|
|
|
+ spi = ntohl(net_spi);
|
|
|
|
+ audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
|
|
|
|
+ spi, spi, ntohl(net_seq));
|
|
|
|
+ audit_log_end(audit_buf);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
|
|
|
|
+
|
|
|
|
+void xfrm_audit_state_icvfail(struct xfrm_state *x,
|
|
|
|
+ struct sk_buff *skb, u8 proto)
|
|
|
|
+{
|
|
|
|
+ struct audit_buffer *audit_buf;
|
|
|
|
+ __be32 net_spi;
|
|
|
|
+ __be32 net_seq;
|
|
|
|
+
|
|
|
|
+ audit_buf = xfrm_audit_start("SA-icv-failure");
|
|
|
|
+ if (audit_buf == NULL)
|
|
|
|
+ return;
|
|
|
|
+ xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
|
|
|
|
+ if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
|
|
|
|
+ u32 spi = ntohl(net_spi);
|
|
|
|
+ audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
|
|
|
|
+ spi, spi, ntohl(net_seq));
|
|
|
|
+ }
|
|
|
|
+ audit_log_end(audit_buf);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
|
|
#endif /* CONFIG_AUDITSYSCALL */
|
|
#endif /* CONFIG_AUDITSYSCALL */
|