LCOV - code coverage report
Current view: top level - net/core - secure_seq.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 10 19 52.6 %
Date: 2021-04-22 12:43:58 Functions: 1 3 33.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
       4             :  */
       5             : 
       6             : #include <linux/kernel.h>
       7             : #include <linux/init.h>
       8             : #include <linux/module.h>
       9             : #include <linux/cache.h>
      10             : #include <linux/random.h>
      11             : #include <linux/hrtimer.h>
      12             : #include <linux/ktime.h>
      13             : #include <linux/string.h>
      14             : #include <linux/net.h>
      15             : #include <linux/siphash.h>
      16             : #include <net/secure_seq.h>
      17             : 
      18             : #if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET)
      19             : #include <linux/in6.h>
      20             : #include <net/tcp.h>
      21             : 
      22             : static siphash_key_t net_secret __read_mostly;
      23             : static siphash_key_t ts_secret __read_mostly;
      24             : 
      25           4 : static __always_inline void net_secret_init(void)
      26             : {
      27           4 :         net_get_random_once(&net_secret, sizeof(net_secret));
      28             : }
      29             : 
      30           0 : static __always_inline void ts_secret_init(void)
      31             : {
      32           0 :         net_get_random_once(&ts_secret, sizeof(ts_secret));
      33             : }
      34             : #endif
      35             : 
      36             : #ifdef CONFIG_INET
      37           4 : static u32 seq_scale(u32 seq)
      38             : {
      39             :         /*
      40             :          *      As close as possible to RFC 793, which
      41             :          *      suggests using a 250 kHz clock.
      42             :          *      Further reading shows this assumes 2 Mb/s networks.
      43             :          *      For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
      44             :          *      For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
      45             :          *      we also need to limit the resolution so that the u32 seq
      46             :          *      overlaps less than one time per MSL (2 minutes).
      47             :          *      Choosing a clock of 64 ns period is OK. (period of 274 s)
      48             :          */
      49           8 :         return seq + (ktime_get_real_ns() >> 6);
      50             : }
      51             : #endif
      52             : 
      53             : #if IS_ENABLED(CONFIG_IPV6)
      54             : u32 secure_tcpv6_ts_off(const struct net *net,
      55             :                         const __be32 *saddr, const __be32 *daddr)
      56             : {
      57             :         const struct {
      58             :                 struct in6_addr saddr;
      59             :                 struct in6_addr daddr;
      60             :         } __aligned(SIPHASH_ALIGNMENT) combined = {
      61             :                 .saddr = *(struct in6_addr *)saddr,
      62             :                 .daddr = *(struct in6_addr *)daddr,
      63             :         };
      64             : 
      65             :         if (net->ipv4.sysctl_tcp_timestamps != 1)
      66             :                 return 0;
      67             : 
      68             :         ts_secret_init();
      69             :         return siphash(&combined, offsetofend(typeof(combined), daddr),
      70             :                        &ts_secret);
      71             : }
      72             : EXPORT_SYMBOL(secure_tcpv6_ts_off);
      73             : 
      74             : u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
      75             :                      __be16 sport, __be16 dport)
      76             : {
      77             :         const struct {
      78             :                 struct in6_addr saddr;
      79             :                 struct in6_addr daddr;
      80             :                 __be16 sport;
      81             :                 __be16 dport;
      82             :         } __aligned(SIPHASH_ALIGNMENT) combined = {
      83             :                 .saddr = *(struct in6_addr *)saddr,
      84             :                 .daddr = *(struct in6_addr *)daddr,
      85             :                 .sport = sport,
      86             :                 .dport = dport
      87             :         };
      88             :         u32 hash;
      89             : 
      90             :         net_secret_init();
      91             :         hash = siphash(&combined, offsetofend(typeof(combined), dport),
      92             :                        &net_secret);
      93             :         return seq_scale(hash);
      94             : }
      95             : EXPORT_SYMBOL(secure_tcpv6_seq);
      96             : 
      97             : u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
      98             :                                __be16 dport)
      99             : {
     100             :         const struct {
     101             :                 struct in6_addr saddr;
     102             :                 struct in6_addr daddr;
     103             :                 __be16 dport;
     104             :         } __aligned(SIPHASH_ALIGNMENT) combined = {
     105             :                 .saddr = *(struct in6_addr *)saddr,
     106             :                 .daddr = *(struct in6_addr *)daddr,
     107             :                 .dport = dport
     108             :         };
     109             :         net_secret_init();
     110             :         return siphash(&combined, offsetofend(typeof(combined), dport),
     111             :                        &net_secret);
     112             : }
     113             : EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
     114             : #endif
     115             : 
     116             : #ifdef CONFIG_INET
     117           0 : u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
     118             : {
     119           0 :         if (net->ipv4.sysctl_tcp_timestamps != 1)
     120             :                 return 0;
     121             : 
     122           0 :         ts_secret_init();
     123           0 :         return siphash_2u32((__force u32)saddr, (__force u32)daddr,
     124             :                             &ts_secret);
     125             : }
     126             : 
     127             : /* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d),
     128             :  * but fortunately, `sport' cannot be 0 in any circumstances. If this changes,
     129             :  * it would be easy enough to have the former function use siphash_4u32, passing
     130             :  * the arguments as separate u32.
     131             :  */
     132           4 : u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
     133             :                    __be16 sport, __be16 dport)
     134             : {
     135           4 :         u32 hash;
     136             : 
     137           4 :         net_secret_init();
     138           8 :         hash = siphash_3u32((__force u32)saddr, (__force u32)daddr,
     139           4 :                             (__force u32)sport << 16 | (__force u32)dport,
     140             :                             &net_secret);
     141           4 :         return seq_scale(hash);
     142             : }
     143             : EXPORT_SYMBOL_GPL(secure_tcp_seq);
     144             : 
     145           0 : u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
     146             : {
     147           0 :         net_secret_init();
     148           0 :         return siphash_3u32((__force u32)saddr, (__force u32)daddr,
     149             :                             (__force u16)dport, &net_secret);
     150             : }
     151             : EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
     152             : #endif
     153             : 
     154             : #if IS_ENABLED(CONFIG_IP_DCCP)
     155             : u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
     156             :                                 __be16 sport, __be16 dport)
     157             : {
     158             :         u64 seq;
     159             :         net_secret_init();
     160             :         seq = siphash_3u32((__force u32)saddr, (__force u32)daddr,
     161             :                            (__force u32)sport << 16 | (__force u32)dport,
     162             :                            &net_secret);
     163             :         seq += ktime_get_real_ns();
     164             :         seq &= (1ull << 48) - 1;
     165             :         return seq;
     166             : }
     167             : EXPORT_SYMBOL(secure_dccp_sequence_number);
     168             : 
     169             : #if IS_ENABLED(CONFIG_IPV6)
     170             : u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
     171             :                                   __be16 sport, __be16 dport)
     172             : {
     173             :         const struct {
     174             :                 struct in6_addr saddr;
     175             :                 struct in6_addr daddr;
     176             :                 __be16 sport;
     177             :                 __be16 dport;
     178             :         } __aligned(SIPHASH_ALIGNMENT) combined = {
     179             :                 .saddr = *(struct in6_addr *)saddr,
     180             :                 .daddr = *(struct in6_addr *)daddr,
     181             :                 .sport = sport,
     182             :                 .dport = dport
     183             :         };
     184             :         u64 seq;
     185             :         net_secret_init();
     186             :         seq = siphash(&combined, offsetofend(typeof(combined), dport),
     187             :                       &net_secret);
     188             :         seq += ktime_get_real_ns();
     189             :         seq &= (1ull << 48) - 1;
     190             :         return seq;
     191             : }
     192             : EXPORT_SYMBOL(secure_dccpv6_sequence_number);
     193             : #endif
     194             : #endif

Generated by: LCOV version 1.14