summaryrefslogtreecommitdiff
path: root/2.6.32
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2012-12-28 14:52:06 -0500
committerAnthony G. Basile <blueness@gentoo.org>2012-12-28 14:52:06 -0500
commit1e65ecc2a2356479967ba18ffb5adddd6b948cd7 (patch)
tree32b0d8abfddf52106f560b497302b7a0876b3cfe /2.6.32
parentGrsec/PaX: 2.9.1-3.7.1-201212171734 (diff)
downloadhardened-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_README2
-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