diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2012-12-28 14:52:06 -0500 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2012-12-28 14:52:06 -0500 |
commit | 1e65ecc2a2356479967ba18ffb5adddd6b948cd7 (patch) | |
tree | 32b0d8abfddf52106f560b497302b7a0876b3cfe /2.6.32 | |
parent | Grsec/PaX: 2.9.1-3.7.1-201212171734 (diff) | |
download | hardened-patchset-1e65ecc2a2356479967ba18ffb5adddd6b948cd7.tar.gz hardened-patchset-1e65ecc2a2356479967ba18ffb5adddd6b948cd7.tar.bz2 hardened-patchset-1e65ecc2a2356479967ba18ffb5adddd6b948cd7.zip |
Grsec/PaX: 2.9.1-{2.6.32.60,3.2.35,3.7.1}-20121227195320121227
Diffstat (limited to '2.6.32')
-rw-r--r-- | 2.6.32/0000_README | 2 | ||||
-rw-r--r-- | 2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201212271948.patch (renamed from 2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201212151417.patch) | 440 |
2 files changed, 401 insertions, 41 deletions
diff --git a/2.6.32/0000_README b/2.6.32/0000_README index 118ed93..bfc0147 100644 --- a/2.6.32/0000_README +++ b/2.6.32/0000_README @@ -34,7 +34,7 @@ Patch: 1059_linux-2.6.32.60.patch From: http://www.kernel.org Desc: Linux 2.6.32.59 -Patch: 4420_grsecurity-2.9.1-2.6.32.60-201212151417.patch +Patch: 4420_grsecurity-2.9.1-2.6.32.60-201212271948.patch From: http://www.grsecurity.net Desc: hardened-sources base patch from upstream grsecurity diff --git a/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201212151417.patch b/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201212271948.patch index 182c7b6..ebf3a53 100644 --- a/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201212151417.patch +++ b/2.6.32/4420_grsecurity-2.9.1-2.6.32.60-201212271948.patch @@ -229,6 +229,22 @@ index 14c7fb0..0f7d099 100644 pcbit= [HW,ISDN] pcd. [PARIDE] +diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt +index fbe427a..195ff43 100644 +--- a/Documentation/networking/ip-sysctl.txt ++++ b/Documentation/networking/ip-sysctl.txt +@@ -479,6 +479,11 @@ tcp_dma_copybreak - INTEGER + and CONFIG_NET_DMA is enabled. + Default: 4096 + ++tcp_challenge_ack_limit - INTEGER ++ Limits number of Challenge ACK sent per second, as recommended ++ in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) ++ Default: 100 ++ + UDP variables: + + udp_mem - vector of 3 INTEGERs: min, pressure, max diff --git a/MAINTAINERS b/MAINTAINERS index 334258c..1e8f4ff 100644 --- a/MAINTAINERS @@ -42636,7 +42652,7 @@ index 62f282e..e45c45c 100644 cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || diff --git a/drivers/char/random.c b/drivers/char/random.c -index 446b20a..8657325 100644 +index 446b20a..d0e60f5 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -269,8 +269,13 @@ @@ -42671,7 +42687,15 @@ index 446b20a..8657325 100644 #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ { 2048, 1638, 1231, 819, 411, 1 }, -@@ -524,8 +536,8 @@ static void __mix_pool_bytes(struct entropy_store *r, const void *in, +@@ -434,6 +446,7 @@ struct entropy_store { + int entropy_count; + int entropy_total; + unsigned int initialized:1; ++ bool last_data_init; + __u8 last_data[EXTRACT_SIZE]; + }; + +@@ -524,8 +537,8 @@ static void __mix_pool_bytes(struct entropy_store *r, const void *in, input_rotate += i ? 7 : 14; } @@ -42682,7 +42706,7 @@ index 446b20a..8657325 100644 smp_wmb(); if (out) -@@ -784,6 +796,17 @@ void add_disk_randomness(struct gendisk *disk) +@@ -784,6 +797,17 @@ void add_disk_randomness(struct gendisk *disk) } #endif @@ -42700,7 +42724,36 @@ index 446b20a..8657325 100644 /********************************************************************* * * Entropy extraction routines -@@ -1015,7 +1038,21 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, +@@ -942,6 +966,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, + ssize_t ret = 0, i; + __u8 tmp[EXTRACT_SIZE]; + ++ /* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */ ++ if (fips_enabled && !r->last_data_init) ++ nbytes += EXTRACT_SIZE; ++ + xfer_secondary_pool(r, nbytes); + nbytes = account(r, nbytes, min, reserved); + +@@ -951,6 +979,17 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, + if (fips_enabled) { + unsigned long flags; + ++ ++ /* prime last_data value if need be, per fips 140-2 */ ++ if (!r->last_data_init) { ++ spin_lock_irqsave(&r->lock, flags); ++ memcpy(r->last_data, tmp, EXTRACT_SIZE); ++ r->last_data_init = true; ++ nbytes -= EXTRACT_SIZE; ++ spin_unlock_irqrestore(&r->lock, flags); ++ extract_buf(r, tmp); ++ } ++ + spin_lock_irqsave(&r->lock, flags); + if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) + panic("Hardware RNG duplicated output!\n"); +@@ -1015,7 +1054,21 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, */ void get_random_bytes(void *buf, int nbytes) { @@ -42723,7 +42776,15 @@ index 446b20a..8657325 100644 } EXPORT_SYMBOL(get_random_bytes); -@@ -1322,7 +1359,7 @@ EXPORT_SYMBOL(generate_random_uuid); +@@ -1068,6 +1121,7 @@ static void init_std_data(struct entropy_store *r) + + r->entropy_count = 0; + r->entropy_total = 0; ++ r->last_data_init = false; + mix_pool_bytes(r, &now, sizeof(now), NULL); + for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) { + if (!arch_get_random_long(&rv)) +@@ -1322,7 +1376,7 @@ EXPORT_SYMBOL(generate_random_uuid); #include <linux/sysctl.h> static int min_read_thresh = 8, min_write_thresh; @@ -42732,7 +42793,7 @@ index 446b20a..8657325 100644 static int max_write_thresh = INPUT_POOL_WORDS * 32; static char sysctl_bootid[16]; -@@ -1397,6 +1434,7 @@ static int uuid_strategy(ctl_table *table, +@@ -1397,6 +1451,7 @@ static int uuid_strategy(ctl_table *table, } static int sysctl_poolsize = INPUT_POOL_WORDS * 32; @@ -42740,7 +42801,7 @@ index 446b20a..8657325 100644 ctl_table random_table[] = { { .ctl_name = RANDOM_POOLSIZE, -@@ -1472,7 +1510,7 @@ late_initcall(random_int_secret_init); +@@ -1472,7 +1527,7 @@ late_initcall(random_int_secret_init); * value is not cryptographically secure but for several uses the cost of * depleting entropy is too high */ @@ -74396,7 +74457,7 @@ index b4ea829..e63ef18 100644 } diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c -index 136a0d6..cdff021 100644 +index 136a0d6..3330341 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -60,7 +60,7 @@ static int autofs4_write(struct file *file, const void *addr, int bytes) @@ -74425,7 +74486,7 @@ index 136a0d6..cdff021 100644 if (IS_ROOT(dentry) && autofs_type_trigger(sbi->type)) +#ifdef CONFIG_GRKERNSEC_HIDESYM + /* this name does get written to userland via autofs4_write() */ -+ qstr.len = sprintf(name, "%08lx", atomic_inc_return_unchecked(&autofs_dummy_name_id)); ++ qstr.len = sprintf(name, "%08x", atomic_inc_return_unchecked(&autofs_dummy_name_id)); +#else qstr.len = sprintf(name, "%p", dentry); +#endif @@ -77839,6 +77900,18 @@ index 2a60541..7439d61 100644 sb->s_dirt = 1; } } +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index efe6363..f9e1b6e 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2179,6 +2179,7 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd, + index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits); + end = (logical + blk_cnt - 1) >> + (PAGE_CACHE_SHIFT - inode->i_blkbits); ++ pagevec_init(&pvec, 0); + while (index <= end) { + nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); + if (nr_pages == 0) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 42bac1b..0aab9d8 100644 --- a/fs/ext4/mballoc.c @@ -80110,7 +80183,7 @@ index ec88ff3..b843a82 100644 cache->c_bucket_bits = bucket_bits; #ifdef MB_CACHE_INDEXES_COUNT diff --git a/fs/namei.c b/fs/namei.c -index b0afbd4..78b0f63 100644 +index b0afbd4..2b96439 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -224,6 +224,14 @@ int generic_permission(struct inode *inode, int mask, @@ -80240,7 +80313,7 @@ index b0afbd4..78b0f63 100644 + if (unlikely(name[0] == '.')) { + if (len < 2 || (len == 2 && name[1] == '.')) -+ return ERR_PTR(-EACCES); ++ return -EACCES; + } + hash = init_name_hash(); @@ -82917,6 +82990,19 @@ index 8f5c05d..c99c76d 100644 } seq_putc(m, '\n'); +diff --git a/fs/read_write.c b/fs/read_write.c +index b7f4a1f..d40066d 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -860,6 +860,8 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, + if (retval > 0) { + add_rchar(current, retval); + add_wchar(current, retval); ++ fsnotify_access(in_file->f_path.dentry); ++ fsnotify_modify(out_file->f_path.dentry); + } + + inc_syscr(current); diff --git a/fs/readdir.c b/fs/readdir.c index 7723401..30059a6 100644 --- a/fs/readdir.c @@ -83952,7 +84038,7 @@ index e89734e..5e84d8d 100644 return 0; diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig new file mode 100644 -index 0000000..5012f34 +index 0000000..7efd211 --- /dev/null +++ b/grsecurity/Kconfig @@ -0,0 +1,946 @@ @@ -84603,7 +84689,7 @@ index 0000000..5012f34 + default y if GRKERNSEC_CONFIG_AUTO + help + If you say Y here, non-root users will not be able to use dmesg(8) -+ to view up to the last 4kb of messages in the kernel's log buffer. ++ to view the contents of the kernel's circular log buffer. + The kernel's log buffer often contains kernel addresses and other + identifying information useful to an attacker in fingerprinting a + system for a targeted exploit. @@ -98283,6 +98369,34 @@ index 5171639..7cf4235 100644 /** create a directory */ struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root, +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h +index 6b202b1..f451772 100644 +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -362,7 +362,7 @@ static inline int PageCompound(struct page *page) + * pages on the LRU and/or pagecache. + */ + TESTPAGEFLAG(Compound, compound) +-__PAGEFLAG(Head, compound) ++__SETPAGEFLAG(Head, compound) __CLEARPAGEFLAG(Head, compound) + + /* + * PG_reclaim is used in combination with PG_compound to mark the +@@ -374,8 +374,14 @@ __PAGEFLAG(Head, compound) + * PG_compound & PG_reclaim => Tail page + * PG_compound & ~PG_reclaim => Head page + */ ++#define PG_head_mask ((1L << PG_compound)) + #define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim)) + ++static inline int PageHead(struct page *page) ++{ ++ return ((page->flags & PG_head_tail_mask) == PG_head_mask); ++} ++ + static inline int PageTail(struct page *page) + { + return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 3c62ed4..8924c7c 100644 --- a/include/linux/pagemap.h @@ -98464,7 +98578,7 @@ index 7456d7d..6c1cfc9 100644 static inline int ptrace_reparented(struct task_struct *child) { diff --git a/include/linux/random.h b/include/linux/random.h -index 1864957..e98160a 100644 +index 1864957..b2ba8bf 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -49,6 +49,10 @@ extern void add_input_randomness(unsigned int type, unsigned int code, @@ -98478,7 +98592,7 @@ index 1864957..e98160a 100644 extern void get_random_bytes(void *buf, int nbytes); extern void get_random_bytes_arch(void *buf, int nbytes); void generate_random_uuid(unsigned char uuid_out[16]); -@@ -76,6 +80,24 @@ static inline int arch_get_random_int(unsigned int *v) +@@ -76,6 +80,11 @@ static inline int arch_get_random_int(unsigned int *v) } #endif @@ -98487,19 +98601,6 @@ index 1864957..e98160a 100644 + return random32() + (sizeof(long) > 4 ? (unsigned long)random32() << 32 : 0); +} + -+#ifdef CONFIG_ARCH_RANDOM -+# include <asm/archrandom.h> -+#else -+static inline int arch_get_random_long(unsigned long *v) -+{ -+ return 0; -+} -+static inline int arch_get_random_int(unsigned int *v) -+{ -+ return 0; -+} -+#endif -+ #endif /* __KERNEL___ */ #endif /* _LINUX_RANDOM_H */ @@ -99331,6 +99432,27 @@ index 5ad70a6..108e1dc 100644 void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); #ifdef CONFIG_KMEMTRACE +diff --git a/include/linux/snmp.h b/include/linux/snmp.h +index 0f953fe..05d45da 100644 +--- a/include/linux/snmp.h ++++ b/include/linux/snmp.h +@@ -208,7 +208,6 @@ enum + LINUX_MIB_TCPDSACKOFOSENT, /* TCPDSACKOfoSent */ + LINUX_MIB_TCPDSACKRECV, /* TCPDSACKRecv */ + LINUX_MIB_TCPDSACKOFORECV, /* TCPDSACKOfoRecv */ +- LINUX_MIB_TCPABORTONSYN, /* TCPAbortOnSyn */ + LINUX_MIB_TCPABORTONDATA, /* TCPAbortOnData */ + LINUX_MIB_TCPABORTONCLOSE, /* TCPAbortOnClose */ + LINUX_MIB_TCPABORTONMEMORY, /* TCPAbortOnMemory */ +@@ -225,6 +224,8 @@ enum + LINUX_MIB_SACKSHIFTED, + LINUX_MIB_SACKMERGED, + LINUX_MIB_SACKSHIFTFALLBACK, ++ LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ ++ LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */ + __LINUX_MIB_MAX + }; + diff --git a/include/linux/sonet.h b/include/linux/sonet.h index 67ad11f..0bbd8af 100644 --- a/include/linux/sonet.h @@ -100299,10 +100421,18 @@ index 78adf52..32bb160 100644 static inline struct page *sk_stream_alloc_page(struct sock *sk) { diff --git a/include/net/tcp.h b/include/net/tcp.h -index 6cfe18b..a0d06df 100644 +index 6cfe18b..24c05d6 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h -@@ -483,7 +483,7 @@ extern void tcp_retransmit_timer(struct sock *sk); +@@ -237,6 +237,7 @@ extern int sysctl_tcp_base_mss; + extern int sysctl_tcp_workaround_signed_windows; + extern int sysctl_tcp_slow_start_after_idle; + extern int sysctl_tcp_max_ssthresh; ++extern int sysctl_tcp_challenge_ack_limit; + + extern atomic_t tcp_memory_allocated; + extern struct percpu_counter tcp_sockets_allocated; +@@ -483,7 +484,7 @@ extern void tcp_retransmit_timer(struct sock *sk); extern void tcp_xmit_retransmit_queue(struct sock *); extern void tcp_simple_retransmit(struct sock *); extern int tcp_trim_head(struct sock *, struct sk_buff *, u32); @@ -100311,7 +100441,7 @@ index 6cfe18b..a0d06df 100644 extern void tcp_send_probe0(struct sock *); extern void tcp_send_partial(struct sock *); -@@ -632,8 +632,8 @@ struct tcp_skb_cb { +@@ -632,8 +633,8 @@ struct tcp_skb_cb { struct inet6_skb_parm h6; #endif } header; /* For incoming frames */ @@ -100322,7 +100452,7 @@ index 6cfe18b..a0d06df 100644 __u32 when; /* used to compute rtt's */ __u8 flags; /* TCP header flags. */ -@@ -658,7 +658,7 @@ struct tcp_skb_cb { +@@ -658,7 +659,7 @@ struct tcp_skb_cb { #define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */ #define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS) @@ -100331,7 +100461,7 @@ index 6cfe18b..a0d06df 100644 }; #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) -@@ -1444,8 +1444,8 @@ enum tcp_seq_states { +@@ -1444,8 +1445,8 @@ enum tcp_seq_states { struct tcp_seq_afinfo { char *name; sa_family_t family; @@ -104383,10 +104513,10 @@ index fce7198..4f23a7e 100644 { struct pid *pid; diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c -index 5c9dc22..d271117 100644 +index 5c9dc22..7652dca 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c -@@ -6,6 +6,7 @@ +@@ -6,9 +6,11 @@ #include <linux/posix-timers.h> #include <linux/errno.h> #include <linux/math64.h> @@ -104394,7 +104524,20 @@ index 5c9dc22..d271117 100644 #include <asm/uaccess.h> #include <linux/kernel_stat.h> #include <trace/events/timer.h> -@@ -1697,7 +1698,7 @@ static long thread_cpu_nsleep_restart(struct restart_block *restart_block) ++#include <linux/random.h> + + /* + * Called after updating RLIMIT_CPU to set timer expiration if necessary. +@@ -516,6 +518,8 @@ static void cleanup_timers(struct list_head *head, + */ + void posix_cpu_timers_exit(struct task_struct *tsk) + { ++ add_device_randomness((const void*) &tsk->se.sum_exec_runtime, ++ sizeof(unsigned long long)); + cleanup_timers(tsk->cpu_timers, + tsk->utime, tsk->stime, tsk->se.sum_exec_runtime); + +@@ -1697,7 +1701,7 @@ static long thread_cpu_nsleep_restart(struct restart_block *restart_block) static __init int init_posix_cpu_timers(void) { @@ -104403,7 +104546,7 @@ index 5c9dc22..d271117 100644 .clock_getres = process_cpu_clock_getres, .clock_get = process_cpu_clock_get, .clock_set = do_posix_clock_nosettime, -@@ -1705,7 +1706,7 @@ static __init int init_posix_cpu_timers(void) +@@ -1705,7 +1709,7 @@ static __init int init_posix_cpu_timers(void) .nsleep = process_cpu_nsleep, .nsleep_restart = process_cpu_nsleep_restart, }; @@ -112912,6 +113055,27 @@ index 0606db1..2f32531 100644 break; case IPT_SO_GET_ENTRIES: +diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c +index f25542c..5a0b902 100644 +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -232,7 +232,6 @@ static const struct snmp_mib snmp4_net_list[] = { + SNMP_MIB_ITEM("TCPDSACKOfoSent", LINUX_MIB_TCPDSACKOFOSENT), + SNMP_MIB_ITEM("TCPDSACKRecv", LINUX_MIB_TCPDSACKRECV), + SNMP_MIB_ITEM("TCPDSACKOfoRecv", LINUX_MIB_TCPDSACKOFORECV), +- SNMP_MIB_ITEM("TCPAbortOnSyn", LINUX_MIB_TCPABORTONSYN), + SNMP_MIB_ITEM("TCPAbortOnData", LINUX_MIB_TCPABORTONDATA), + SNMP_MIB_ITEM("TCPAbortOnClose", LINUX_MIB_TCPABORTONCLOSE), + SNMP_MIB_ITEM("TCPAbortOnMemory", LINUX_MIB_TCPABORTONMEMORY), +@@ -249,6 +248,8 @@ static const struct snmp_mib snmp4_net_list[] = { + SNMP_MIB_ITEM("TCPSackShifted", LINUX_MIB_SACKSHIFTED), + SNMP_MIB_ITEM("TCPSackMerged", LINUX_MIB_SACKMERGED), + SNMP_MIB_ITEM("TCPSackShiftFallback", LINUX_MIB_SACKSHIFTFALLBACK), ++ SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), ++ SNMP_MIB_ITEM("TCPSYNChallenge", LINUX_MIB_TCPSYNCHALLENGE), + SNMP_MIB_SENTINEL + }; + diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index ab996f9..3da5f96 100644 --- a/net/ipv4/raw.c @@ -113017,6 +113181,24 @@ index 58f141b..b759702 100644 (int) ((num_physpages ^ (num_physpages>>8)) ^ (jiffies ^ (jiffies >> 7)))); +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 2dcf04d..4656638 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -638,6 +638,13 @@ static struct ctl_table ipv4_table[] = { + .mode = 0644, + .proc_handler = proc_dointvec + }, ++ { ++ .procname = "tcp_challenge_ack_limit", ++ .data = &sysctl_tcp_challenge_ack_limit, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec ++ }, + #ifdef CONFIG_NET_DMA + { + .ctl_name = NET_TCP_DMA_COPYBREAK, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b9644d8..537313b 100644 --- a/net/ipv4/tcp.c @@ -113061,10 +113243,61 @@ index 1eba160b..c35d91f 100644 } } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index db755c4..04481e4 100644 +index db755c4..fbca78e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c -@@ -4528,7 +4528,7 @@ static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, +@@ -82,6 +82,9 @@ int sysctl_tcp_dsack __read_mostly = 1; + int sysctl_tcp_app_win __read_mostly = 31; + int sysctl_tcp_adv_win_scale __read_mostly = 2; + ++/* rfc5961 challenge ack rate limiting */ ++int sysctl_tcp_challenge_ack_limit = 100; ++ + int sysctl_tcp_stdurg __read_mostly; + int sysctl_tcp_rfc1337 __read_mostly; + int sysctl_tcp_max_orphans __read_mostly = NR_FILE; +@@ -3564,6 +3567,24 @@ static int tcp_process_frto(struct sock *sk, int flag) + return 0; + } + ++/* RFC 5961 7 [ACK Throttling] */ ++static void tcp_send_challenge_ack(struct sock *sk) ++{ ++ /* unprotected vars, we dont care of overwrites */ ++ static u32 challenge_timestamp; ++ static unsigned int challenge_count; ++ u32 now = jiffies / HZ; ++ ++ if (now != challenge_timestamp) { ++ challenge_timestamp = now; ++ challenge_count = 0; ++ } ++ if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { ++ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); ++ tcp_send_ack(sk); ++ } ++} ++ + /* This routine deals with incoming acks, but not outgoing ones. */ + static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) + { +@@ -3580,8 +3601,14 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) + /* If the ack is older than previous acks + * then we can probably ignore it. + */ +- if (before(ack, prior_snd_una)) ++ if (before(ack, prior_snd_una)) { ++ /* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */ ++ if (before(ack, prior_snd_una - tp->max_window)) { ++ tcp_send_challenge_ack(sk); ++ return -1; ++ } + goto old_ack; ++ } + + /* If the ack includes data we haven't sent yet, discard + * this segment (RFC793 Section 3.9). +@@ -4528,7 +4555,7 @@ static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, * simplifies code) */ static void @@ -113073,7 +113306,105 @@ index db755c4..04481e4 100644 struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end) { -@@ -5634,7 +5634,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, +@@ -5069,8 +5096,8 @@ out: + /* Does PAWS and seqno based validation of an incoming segment, flags will + * play significant role here. + */ +-static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, +- struct tcphdr *th, int syn_inerr) ++static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, ++ const struct tcphdr *th, int syn_inerr) + { + struct tcp_sock *tp = tcp_sk(sk); + +@@ -5100,7 +5127,16 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, + + /* Step 2: check RST bit */ + if (th->rst) { +- tcp_reset(sk); ++ /* RFC 5961 3.2 : ++ * If sequence number exactly matches RCV.NXT, then ++ * RESET the connection ++ * else ++ * Send a challenge ACK ++ */ ++ if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) ++ tcp_reset(sk); ++ else ++ tcp_send_challenge_ack(sk); + goto discard; + } + +@@ -5111,20 +5147,22 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, + + /* step 3: check security and precedence [ignored] */ + +- /* step 4: Check for a SYN in window. */ +- if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { ++ /* step 4: Check for a SYN ++ * RFC 5691 4.2 : Send a challenge ack ++ */ ++ if (th->syn) { + if (syn_inerr) + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); +- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN); +- tcp_reset(sk); +- return -1; ++ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNCHALLENGE); ++ tcp_send_challenge_ack(sk); ++ goto discard; + } + +- return 1; ++ return true; + + discard: + __kfree_skb(skb); +- return 0; ++ return false; + } + + /* +@@ -5154,7 +5192,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, + struct tcphdr *th, unsigned len) + { + struct tcp_sock *tp = tcp_sk(sk); +- int res; + + /* + * Header prediction. +@@ -5330,16 +5367,18 @@ slow_path: + if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb)) + goto csum_error; + ++ if (!th->ack) ++ goto discard; ++ + /* + * Standard slow path. + */ + +- res = tcp_validate_incoming(sk, skb, th, 1); +- if (res <= 0) +- return -res; ++ if (!tcp_validate_incoming(sk, skb, th, 1)) ++ return 0; + + step5: +- if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) ++ if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) + goto discard; + + tcp_rcv_rtt_measure_ts(sk, skb); +@@ -5618,7 +5657,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); + int queued = 0; +- int res; + + tp->rx_opt.saw_tstamp = 0; + +@@ -5634,7 +5672,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, goto discard; if (th->syn) { @@ -113082,6 +113413,35 @@ index db755c4..04481e4 100644 goto discard; if (icsk->icsk_af_ops->conn_request(sk, skb) < 0) return 1; +@@ -5673,12 +5711,14 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, + return 0; + } + +- res = tcp_validate_incoming(sk, skb, th, 0); +- if (res <= 0) +- return -res; ++ if (!th->ack) ++ goto discard; ++ ++ if (!tcp_validate_incoming(sk, skb, th, 0)) ++ return 0; + + /* step 5: check the ACK field */ +- if (th->ack) { ++ if (true) { + int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0; + + switch (sk->sk_state) { +@@ -5789,8 +5829,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, + } + break; + } +- } else +- goto discard; ++ } + + /* step 6: check the URG bit */ + tcp_urg(sk, skb, th); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6a4e832..7eb316b 100644 --- a/net/ipv4/tcp_ipv4.c |