Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

TCPCT part 1b: generate Responder Cookie secret

Define (missing) hash message size for SHA1.

Define hashing size constants specific to TCP cookies.

Add new function: tcp_cookie_generator().

Maintain global secret values for tcp_cookie_generator().

This is a significantly revised implementation of earlier (15-year-old)
Photuris [RFC-2522] code for the KA9Q cooperative multitasking platform.

Linux RCU technique appears to be well-suited to this application, though
neither of the circular queue items are freed.

These functions will also be used in subsequent patches that implement
additional features.

Signed-off-by: William.Allen.Simpson@gmail.com
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

William Allen Simpson and committed by
David S. Miller
da5c78c8 e6b4d113

+149
+1
include/linux/cryptohash.h
··· 2 2 #define __CRYPTOHASH_H 3 3 4 4 #define SHA_DIGEST_WORDS 5 5 + #define SHA_MESSAGE_BYTES (512 /*bits*/ / 8) 5 6 #define SHA_WORKSPACE_WORDS 80 6 7 7 8 void sha_init(__u32 *buf);
+8
include/net/tcp.h
··· 1478 1478 #endif 1479 1479 }; 1480 1480 1481 + /* Using SHA1 for now, define some constants. 1482 + */ 1483 + #define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS) 1484 + #define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4) 1485 + #define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS) 1486 + 1487 + extern int tcp_cookie_generator(u32 *bakery); 1488 + 1481 1489 extern void tcp_v4_init(void); 1482 1490 extern void tcp_init(void); 1483 1491
+140
net/ipv4/tcp.c
··· 264 264 #include <linux/cache.h> 265 265 #include <linux/err.h> 266 266 #include <linux/crypto.h> 267 + #include <linux/time.h> 267 268 268 269 #include <net/icmp.h> 269 270 #include <net/tcp.h> ··· 2849 2848 2850 2849 #endif 2851 2850 2851 + /** 2852 + * Each Responder maintains up to two secret values concurrently for 2853 + * efficient secret rollover. Each secret value has 4 states: 2854 + * 2855 + * Generating. (tcp_secret_generating != tcp_secret_primary) 2856 + * Generates new Responder-Cookies, but not yet used for primary 2857 + * verification. This is a short-term state, typically lasting only 2858 + * one round trip time (RTT). 2859 + * 2860 + * Primary. (tcp_secret_generating == tcp_secret_primary) 2861 + * Used both for generation and primary verification. 2862 + * 2863 + * Retiring. (tcp_secret_retiring != tcp_secret_secondary) 2864 + * Used for verification, until the first failure that can be 2865 + * verified by the newer Generating secret. At that time, this 2866 + * cookie's state is changed to Secondary, and the Generating 2867 + * cookie's state is changed to Primary. This is a short-term state, 2868 + * typically lasting only one round trip time (RTT). 2869 + * 2870 + * Secondary. (tcp_secret_retiring == tcp_secret_secondary) 2871 + * Used for secondary verification, after primary verification 2872 + * failures. This state lasts no more than twice the Maximum Segment 2873 + * Lifetime (2MSL). Then, the secret is discarded. 2874 + */ 2875 + struct tcp_cookie_secret { 2876 + /* The secret is divided into two parts. The digest part is the 2877 + * equivalent of previously hashing a secret and saving the state, 2878 + * and serves as an initialization vector (IV). The message part 2879 + * serves as the trailing secret. 2880 + */ 2881 + u32 secrets[COOKIE_WORKSPACE_WORDS]; 2882 + unsigned long expires; 2883 + }; 2884 + 2885 + #define TCP_SECRET_1MSL (HZ * TCP_PAWS_MSL) 2886 + #define TCP_SECRET_2MSL (HZ * TCP_PAWS_MSL * 2) 2887 + #define TCP_SECRET_LIFE (HZ * 600) 2888 + 2889 + static struct tcp_cookie_secret tcp_secret_one; 2890 + static struct tcp_cookie_secret tcp_secret_two; 2891 + 2892 + /* Essentially a circular list, without dynamic allocation. */ 2893 + static struct tcp_cookie_secret *tcp_secret_generating; 2894 + static struct tcp_cookie_secret *tcp_secret_primary; 2895 + static struct tcp_cookie_secret *tcp_secret_retiring; 2896 + static struct tcp_cookie_secret *tcp_secret_secondary; 2897 + 2898 + static DEFINE_SPINLOCK(tcp_secret_locker); 2899 + 2900 + /* Select a pseudo-random word in the cookie workspace. 2901 + */ 2902 + static inline u32 tcp_cookie_work(const u32 *ws, const int n) 2903 + { 2904 + return ws[COOKIE_DIGEST_WORDS + ((COOKIE_MESSAGE_WORDS-1) & ws[n])]; 2905 + } 2906 + 2907 + /* Fill bakery[COOKIE_WORKSPACE_WORDS] with generator, updating as needed. 2908 + * Called in softirq context. 2909 + * Returns: 0 for success. 2910 + */ 2911 + int tcp_cookie_generator(u32 *bakery) 2912 + { 2913 + unsigned long jiffy = jiffies; 2914 + 2915 + if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) { 2916 + spin_lock_bh(&tcp_secret_locker); 2917 + if (!time_after_eq(jiffy, tcp_secret_generating->expires)) { 2918 + /* refreshed by another */ 2919 + memcpy(bakery, 2920 + &tcp_secret_generating->secrets[0], 2921 + COOKIE_WORKSPACE_WORDS); 2922 + } else { 2923 + /* still needs refreshing */ 2924 + get_random_bytes(bakery, COOKIE_WORKSPACE_WORDS); 2925 + 2926 + /* The first time, paranoia assumes that the 2927 + * randomization function isn't as strong. But, 2928 + * this secret initialization is delayed until 2929 + * the last possible moment (packet arrival). 2930 + * Although that time is observable, it is 2931 + * unpredictably variable. Mash in the most 2932 + * volatile clock bits available, and expire the 2933 + * secret extra quickly. 2934 + */ 2935 + if (unlikely(tcp_secret_primary->expires == 2936 + tcp_secret_secondary->expires)) { 2937 + struct timespec tv; 2938 + 2939 + getnstimeofday(&tv); 2940 + bakery[COOKIE_DIGEST_WORDS+0] ^= 2941 + (u32)tv.tv_nsec; 2942 + 2943 + tcp_secret_secondary->expires = jiffy 2944 + + TCP_SECRET_1MSL 2945 + + (0x0f & tcp_cookie_work(bakery, 0)); 2946 + } else { 2947 + tcp_secret_secondary->expires = jiffy 2948 + + TCP_SECRET_LIFE 2949 + + (0xff & tcp_cookie_work(bakery, 1)); 2950 + tcp_secret_primary->expires = jiffy 2951 + + TCP_SECRET_2MSL 2952 + + (0x1f & tcp_cookie_work(bakery, 2)); 2953 + } 2954 + memcpy(&tcp_secret_secondary->secrets[0], 2955 + bakery, COOKIE_WORKSPACE_WORDS); 2956 + 2957 + rcu_assign_pointer(tcp_secret_generating, 2958 + tcp_secret_secondary); 2959 + rcu_assign_pointer(tcp_secret_retiring, 2960 + tcp_secret_primary); 2961 + /* 2962 + * Neither call_rcu() nor synchronize_rcu() needed. 2963 + * Retiring data is not freed. It is replaced after 2964 + * further (locked) pointer updates, and a quiet time 2965 + * (minimum 1MSL, maximum LIFE - 2MSL). 2966 + */ 2967 + } 2968 + spin_unlock_bh(&tcp_secret_locker); 2969 + } else { 2970 + rcu_read_lock_bh(); 2971 + memcpy(bakery, 2972 + &rcu_dereference(tcp_secret_generating)->secrets[0], 2973 + COOKIE_WORKSPACE_WORDS); 2974 + rcu_read_unlock_bh(); 2975 + } 2976 + return 0; 2977 + } 2978 + EXPORT_SYMBOL(tcp_cookie_generator); 2979 + 2852 2980 void tcp_done(struct sock *sk) 2853 2981 { 2854 2982 if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) ··· 3012 2882 struct sk_buff *skb = NULL; 3013 2883 unsigned long nr_pages, limit; 3014 2884 int order, i, max_share; 2885 + unsigned long jiffy = jiffies; 3015 2886 3016 2887 BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); 3017 2888 ··· 3106 2975 tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); 3107 2976 3108 2977 tcp_register_congestion_control(&tcp_reno); 2978 + 2979 + memset(&tcp_secret_one.secrets[0], 0, sizeof(tcp_secret_one.secrets)); 2980 + memset(&tcp_secret_two.secrets[0], 0, sizeof(tcp_secret_two.secrets)); 2981 + tcp_secret_one.expires = jiffy; /* past due */ 2982 + tcp_secret_two.expires = jiffy; /* past due */ 2983 + tcp_secret_generating = &tcp_secret_one; 2984 + tcp_secret_primary = &tcp_secret_one; 2985 + tcp_secret_retiring = &tcp_secret_two; 2986 + tcp_secret_secondary = &tcp_secret_two; 3109 2987 } 3110 2988 3111 2989 EXPORT_SYMBOL(tcp_close);