|
@@ -457,8 +457,31 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
|
|
return neigh_create(&arp_tbl, pkey, dev);
|
|
return neigh_create(&arp_tbl, pkey, dev);
|
|
}
|
|
}
|
|
|
|
|
|
-atomic_t *ip_idents __read_mostly;
|
|
|
|
-EXPORT_SYMBOL(ip_idents);
|
|
|
|
|
|
+#define IP_IDENTS_SZ 2048u
|
|
|
|
+struct ip_ident_bucket {
|
|
|
|
+ atomic_t id;
|
|
|
|
+ u32 stamp32;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct ip_ident_bucket *ip_idents __read_mostly;
|
|
|
|
+
|
|
|
|
+/* In order to protect privacy, we add a perturbation to identifiers
|
|
|
|
+ * if one generator is seldom used. This makes hard for an attacker
|
|
|
|
+ * to infer how many packets were sent between two points in time.
|
|
|
|
+ */
|
|
|
|
+u32 ip_idents_reserve(u32 hash, int segs)
|
|
|
|
+{
|
|
|
|
+ struct ip_ident_bucket *bucket = ip_idents + hash % IP_IDENTS_SZ;
|
|
|
|
+ u32 old = ACCESS_ONCE(bucket->stamp32);
|
|
|
|
+ u32 now = (u32)jiffies;
|
|
|
|
+ u32 delta = 0;
|
|
|
|
+
|
|
|
|
+ if (old != now && cmpxchg(&bucket->stamp32, old, now) == old)
|
|
|
|
+ delta = prandom_u32_max(now - old);
|
|
|
|
+
|
|
|
|
+ return atomic_add_return(segs + delta, &bucket->id) - segs;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(ip_idents_reserve);
|
|
|
|
|
|
void __ip_select_ident(struct iphdr *iph, int segs)
|
|
void __ip_select_ident(struct iphdr *iph, int segs)
|
|
{
|
|
{
|
|
@@ -467,7 +490,10 @@ void __ip_select_ident(struct iphdr *iph, int segs)
|
|
|
|
|
|
net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd));
|
|
net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd));
|
|
|
|
|
|
- hash = jhash_1word((__force u32)iph->daddr, ip_idents_hashrnd);
|
|
|
|
|
|
+ hash = jhash_3words((__force u32)iph->daddr,
|
|
|
|
+ (__force u32)iph->saddr,
|
|
|
|
+ iph->protocol,
|
|
|
|
+ ip_idents_hashrnd);
|
|
id = ip_idents_reserve(hash, segs);
|
|
id = ip_idents_reserve(hash, segs);
|
|
iph->id = htons(id);
|
|
iph->id = htons(id);
|
|
}
|
|
}
|