x86/asm/traps: Disable tracing and kprobes in fixup_bad_iret and sync_regs
Subsystems (29)
A message that is not in the archive (sent off-list or not yet received): 9c2783dfae10ef2d1e9b08bcc1e562c5@local
PATCH 1/48 x86/asm/traps: Disable tracing and kprobes in fixup_bad_iret and sync_regs
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 7ddc6a2199f1da405a2fb68c40db8899b1a8cd87 upstream.
These functions can be executed on the int3 stack, so kprobes are dangerous. Tracing is probably a bad idea, too.
[bwh: Backported to 3.2:
- Use __kprobes instead of NOKPROBE_SYMBOL()
- Don't use __visible]
--- arch/x86/kernel/traps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/traps.c +2 -2
@@ -493,7 +493,7 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)* for scheduling or signal handling. The actual stack switch is done in * entry.S */ -asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) +asmlinkage notrace __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) {struct pt_regs *regs = eregs;/* Did already sync */
@@ -518,7 +518,7 @@ struct bad_iret_stack {struct pt_regs regs; }; -asmlinkage +asmlinkage notrace __kprobesstruct bad_iret_stack *fixup_bad_iret (struct bad_iret_stack *s) {/*
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 2/48 x86/tls: Validate TLS entries to protect espfix
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 41bdc78544b8a93a9c6814b8bbbfef966272abbe upstream
Installing a 16-bit RW data segment into the GDT defeats espfix. AFAICT this will not affect glibc, Wine, or dosemu at all.
--- arch/x86/kernel/tls.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
arch/x86/kernel/tls.c +23 -0
@@ -28,6 +28,21 @@ static int get_free_idx(void)return -ESRCH ; } +static bool tls_desc_okay (const struct user_desc *info) +{ +if (LDT_empty (info)) +return true; + +/* +* espfix is required for 16-bit data segments, but espfix +* only works for LDT segments. +*/ +if (!info->seg_32bit) +return false; + +return true; +} +static void set_tls_desc (struct task_struct *p,int idx,const struct user_desc *info,int n) {
@@ -67,6 +82,9 @@ int do_set_thread_area(struct task_struct *p, int idx,if (copy_from_user (&info, u_info,sizeof (info)))return -EFAULT ; +if (!tls_desc_okay (&info)) +return -EINVAL ; +if (idx ==-1 ) idx = info.entry_number;
@@ -197,6 +215,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, {struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES ];const struct user_desc *info; +int i; if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) || (pos % sizeof(struct user_desc)) != 0 ||
@@ -210,6 +229,10 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset,else info = infobuf; +for (i =0 ; i < count /sizeof (struct user_desc ); i++) +if (!tls_desc_okay (info + i)) +return -EINVAL ; +set_tls_desc (target,GDT_ENTRY_TLS_MIN + (pos /sizeof (struct user_desc )), info, count /sizeof (struct user_desc ));
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 3/48 x86, tls, ldt: Stop checking lm in LDT_empty
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit e30ab185c490e9a9381385529e0fd32f0a399495 upstream.
32-bit programs don't have an lm bit in their ABI, so they can't reliably cause LDT_empty to return true without resorting to memset. They shouldn't need to do this.
This should fix a longstanding, if minor, issue in all 64-bit kernels as well as a potential regression in the TLS hardening code.
--- arch/x86/include/asm/desc.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
arch/x86/include/asm/desc.h +2 -7
@@ -250,7 +250,8 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; } -#define _LDT_empty (info) \ +/* This intentionally ignores lm, since 32-bit apps don't have that field. */ +#define LDT_empty (info) \ ((info)->base_addr == 0 && \ (info)->limit == 0 && \ (info)->contents == 0 && \
@@ -260,12 +261,6 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) (info)->seg_not_present == 1 && \ (info)->useable == 0) -#ifdef CONFIG_X86_64 -#define LDT_empty (info) (_LDT_empty(info) && ((info)->lm == 0)) -#else -#define LDT_empty (info) (_LDT_empty(info)) -#endif -static inline void clear_LDT (void ) {set_ldt (NULL ,0 );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 4/48 x86, tls: Interpret an all-zero struct user_desc as "no segment"
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 3669ef9fa7d35f573ec9c0e0341b29251c2734a7 upstream.
The Witcher 2 did something like this to allocate a TLS segment index:
struct user_desc u_info;
bzero(&u_info, sizeof(u_info));
u_info.entry_number = (uint32_t)-1;
syscall(SYS_set_thread_area, &u_info);Strictly speaking, this code was never correct. It should have set read_exec_only and seg_not_present to 1 to indicate that it wanted to find a free slot without putting anything there, or it should have put something sensible in the TLS slot if it wanted to allocate a TLS entry for real. The actual effect of this code was to allocate a bogus segment that could be used to exploit espfix.
The set_thread_area hardening patches changed the behavior, causing set_thread_area to return -EINVAL and crashing the game.
This changes set_thread_area to interpret this as a request to find a free slot and to leave it empty, which isn't *quite* what the game expects but should be close enough to keep it working. In particular, using the code above to allocate two segments will allocate the same segment both times.
According to FrostbittenKing on Github, this fixes The Witcher 2.
If this somehow still causes problems, we could instead allocate a limit==0 32-bit data segment, but that seems rather ugly to me.
--- arch/x86/include/asm/desc.h | 13 +++++++++++++ arch/x86/kernel/tls.c | 25 +++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-)
arch/x86/include/asm/desc.h +13 -0
@@ -261,6 +261,19 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) (info)->seg_not_present == 1 && \ (info)->useable == 0) +/* Lots of programs expect an all-zero user_desc to mean "no segment at all". */ +static inline bool LDT_zero (const struct user_desc *info) +{ +return (info->base_addr ==0 && + info->limit ==0 && + info->contents ==0 && + info->read_exec_only ==0 && + info->seg_32bit ==0 && + info->limit_in_pages ==0 && + info->seg_not_present ==0 && + info->useable ==0 ); +} +static inline void clear_LDT (void ) {set_ldt (NULL ,0 );
arch/x86/kernel/tls.c +23 -2
@@ -30,7 +30,28 @@ static int get_free_idx(void)static bool tls_desc_okay (const struct user_desc *info) { -if (LDT_empty (info)) +/* +* For historical reasons (i.e. no one ever documented how any +* of the segmentation APIs work), user programs can and do +* assume that a struct user_desc that's all zeros except for +* entry_number means "no segment at all". This never actually +* worked. In fact, up to Linux 3.19, a struct user_desc like +* this would create a 16-bit read-write segment with base and +* limit both equal to zero. +* +* That was close enough to "no segment at all" until we +* hardened this function to disallow 16-bit TLS segments. Fix +* it up by interpreting these zeroed segments the way that they +* were almost certainly intended to be interpreted. +* +* The correct way to ask for "no segment at all" is to specify +* a user_desc that satisfies LDT_empty. To keep everything +* working, we accept both. +* +* Note that there's a similar kludge in modify_ldt -- look at +* the distinction between modes 1 and 0x11. +*/ +if (LDT_empty (info) ||LDT_zero (info))return true;/*
@@ -56,7 +77,7 @@ static void set_tls_desc(struct task_struct *p, int idx, cpu =get_cpu ();while (n-- >0 ) { -if (LDT_empty (info)) +if (LDT_empty (info) ||LDT_zero (info)) desc->a = desc->b =0 ;else fill_ldt (desc, info);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 5/48 x86_64, switch_to(): Load TLS descriptors before switching DS and ES
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit f647d7c155f069c1a068030255c300663516420e upstream.
Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch.
This also significantly improves the comments and documents some gotchas in the code.
Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails.
----- begin es test -----
/*
* Copyright (c) 2014 Andy Lutomirski
* GPL v2
*/
static unsigned short GDT3(int idx)
{
return (idx << 3) | 3;
}static int create_tls(int idx, unsigned int base)
{
struct user_desc desc = {
.entry_number = idx,
.base_addr = base,
.limit = 0xfffff,
.seg_32bit = 1,
.contents = 0, /* Data, grow-up */
.read_exec_only = 0,
.limit_in_pages = 1,
.seg_not_present = 0,
.useable = 0,
};
if (syscall(SYS_set_thread_area, &desc) != 0)
err(1, "set_thread_area");
return desc.entry_number;
}int main()
{
int idx = create_tls(-1, 0);
printf("Allocated GDT index %d\n", idx);
unsigned short orig_es;
asm volatile ("mov %%es,%0" : "=rm" (orig_es));
int errors = 0;
int total = 1000;
for (int i = 0; i < total; i++) {
asm volatile ("mov %0,%%es" : : "rm" (GDT3(idx)));
usleep(100);
unsigned short es;
asm volatile ("mov %%es,%0" : "=rm" (es));
asm volatile ("mov %0,%%es" : : "rm" (orig_es));
if (es != GDT3(idx)) {
if (errors == 0)
printf("[FAIL]\tES changed from 0x%hx to 0x%hx\n",
GDT3(idx), es);
errors++;
}
}
if (errors) {
printf("[FAIL]\tES was corrupted %d/%d times\n", errors, total);
return 1;
} else {
printf("[OK]\tES was preserved\n");
return 0;
}
}----- end es test -----
----- begin gsbase test -----
/*
* gsbase.c, a gsbase test
* Copyright (c) 2014 Andy Lutomirski
* GPL v2
*/
static unsigned char *testptr, *testptr2;
static unsigned char read_gs_testvals(void)
{
unsigned char ret;
asm volatile ("movb %%gs:%1, %0" : "=r" (ret) : "m" (*testptr));
return ret;
}int main()
{
int errors = 0;
testptr = mmap((void *)0x200000000UL, 1, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (testptr == MAP_FAILED)
err(1, "mmap");
testptr2 = mmap((void *)0x300000000UL, 1, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
if (testptr2 == MAP_FAILED)
err(1, "mmap");
*testptr = 0;
*testptr2 = 1;
if (syscall(SYS_arch_prctl, ARCH_SET_GS,
(unsigned long)testptr2 - (unsigned long)testptr) != 0)
err(1, "ARCH_SET_GS");
usleep(100);
if (read_gs_testvals() == 1) {
printf("[OK]\tARCH_SET_GS worked\n");
} else {
printf("[FAIL]\tARCH_SET_GS failed\n");
errors++;
}
asm volatile ("mov %0,%%gs" : : "r" (0));
if (read_gs_testvals() == 0) {
printf("[OK]\tWriting 0 to gs worked\n");
} else {
printf("[FAIL]\tWriting 0 to gs failed\n");
errors++;
}
usleep(100);
if (read_gs_testvals() == 0) {
printf("[OK]\tgsbase is still zero\n");
} else {
printf("[FAIL]\tgsbase was corrupted\n");
errors++;
}
return errors == 0 ? 0 : 1;
}----- end gsbase test -----
--- arch/x86/kernel/process_64.c | 101 +++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 28 deletions(-)
arch/x86/kernel/process_64.c +73 -28
@@ -394,24 +394,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)if (preload_fpu)prefetch (next->xstate); -/* -* Reload esp0, LDT and the page table pointer: -*/ +/* Reload esp0 and ss1. */ load_sp0 (tss, next); -/* -* Switch DS and ES. -* This won't pick up thread selector changes, but I guess that is ok. -*/ -savesegment (es, prev->es); -if (unlikely (next->es | prev->es)) -loadsegment (es, next->es); - -savesegment (ds, prev->ds); -if (unlikely (next->ds | prev->ds)) -loadsegment (ds, next->ds); - -/* We must save %fs and %gs before load_TLS() because * %fs and %gs may be cleared by load_TLS(). *
@@ -420,6 +405,10 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)savesegment (fs, fsindex);savesegment (gs, gsindex); +/* +* Load TLS before restoring any segments so that segment loads +* reference the correct GDT entries. +*/ load_TLS (next, cpu);/* Must be after DS reload */
@@ -430,38 +419,94 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)clts ();/* -* Leave lazy mode, flushing any hypercalls made here. -* This must be done before restoring TLS segments so -* the GDT and LDT are properly updated, and must be -* done before math_state_restore, so the TS bit is up -* to date. +* Leave lazy mode, flushing any hypercalls made here. This +* must be done after loading TLS entries in the GDT but before +* loading segments that might reference them, and and it must +* be done before math_state_restore, so the TS bit is up to +* date. */ arch_end_context_switch (next_p); +/* Switch DS and ES. +* +* Reading them only returns the selectors, but writing them (if +* nonzero) loads the full descriptor from the GDT or LDT. The +* LDT for next is loaded in switch_mm, and the GDT is loaded +* above. +* +* We therefore need to write new values to the segment +* registers on every context switch unless both the new and old +* values are zero. +* +* Note that we don't need to do anything for CS and SS, as +* those are saved and restored as part of pt_regs. +*/ +savesegment (es, prev->es); +if (unlikely (next->es | prev->es)) +loadsegment (es, next->es); + +savesegment (ds, prev->ds); +if (unlikely (next->ds | prev->ds)) +loadsegment (ds, next->ds); +/* * Switch FS and GS. * -* Segment register != 0 always requires a reload. Also -* reload when it has changed. When prev process used 64bit -* base always reload to avoid an information leak. +* These are even more complicated than FS and GS: they have +* 64-bit bases are that controlled by arch_prctl. Those bases +* only differ from the values in the GDT or LDT if the selector +* is 0. +* +* Loading the segment register resets the hidden base part of +* the register to 0 or the value from the GDT / LDT. If the +* next base address zero, writing 0 to the segment register is +* much faster than using wrmsr to explicitly zero the base. +* +* The thread_struct.fs and thread_struct.gs values are 0 +* if the fs and gs bases respectively are not overridden +* from the values implied by fsindex and gsindex. They +* are nonzero, and store the nonzero base addresses, if +* the bases are overridden. +* +* (fs != 0 && fsindex != 0) || (gs != 0 && gsindex != 0) should +* be impossible. +* +* Therefore we need to reload the segment registers if either +* the old or new selector is nonzero, and we need to override +* the base address if next thread expects it to be overridden. +* +* This code is unnecessarily slow in the case where the old and +* new indexes are zero and the new base is nonzero -- it will +* unnecessarily write 0 to the selector before writing the new +* base address. +* +* Note: This all depends on arch_prctl being the only way that +* user code can override the segment base. Once wrfsbase and +* wrgsbase are enabled, most of this code will need to change. */ if (unlikely (fsindex | next->fsindex | prev->fs)) {loadsegment (fs, next->fsindex); +/* -* Check if the user used a selector != 0; if yes -* clear 64bit base, since overloaded base is always -* mapped to the Null selector +* If user code wrote a nonzero value to FS, then it also +* cleared the overridden base address. +* +* XXX: if user code wrote 0 to FS and cleared the base +* address itself, we won't notice and we'll incorrectly +* restore the prior base address next time we reschdule +* the process. */ if (fsindex) prev->fs =0 ; } -/* when next process has a 64bit base use it */ if (next->fs)wrmsrl (MSR_FS_BASE , next->fs); prev->fsindex = fsindex;if (unlikely (gsindex | next->gsindex | prev->gs)) {load_gs_index (next->gsindex); + +/* This works (and fails) the same way as fsindex above. */ if (gsindex) prev->gs =0 ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit
f647d7c155f069c1a068030255c300663516420eupstream.
Quoted 8 lines
Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch.
This also significantly improves the comments and documents some gotchas in the code.
Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails.
[...]
This depends on the changes to FPU/MMX/SSE state management that you didn't apply to 2.6.32. Note this comment:
/* Must be after DS reload */ unlazy_fpu(prev_p);
Ben.
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
Hi Ben,
Quoted 17 lines · Ben Hutchings
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit
f647d7c155f069c1a068030255c300663516420eupstream.Quoted 8 lines
Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch.
This also significantly improves the comments and documents some gotchas in the code.
Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails.
Quoted 7 lines
[...]
This depends on the changes to FPU/MMX/SSE state management that you didn't apply to 2.6.32. Note this comment:
/* Must be after DS reload */ unlazy_fpu(prev_p);
Are you sure you're not confusing with another one ? When running estest without this patch, I get "FAIL: ES corrupted 1000/1000 times" while I get "OK: ES was preserved" once applied, so it does seem to do what it's intended for.
Also I'm not seeing any reference to the comment above in the patch nor around it, which leaves me confused :-/
Thanks,
Willy
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
Quoted 28 lines · Willy Tarreau
Hi Ben,
Quoted 17 lines · Ben Hutchings
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit
f647d7c155f069c1a068030255c300663516420eupstream.Quoted 8 lines
Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch.
This also significantly improves the comments and documents some gotchas in the code.
Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails.
Quoted 7 lines
[...]
This depends on the changes to FPU/MMX/SSE state management that you didn't apply to 2.6.32. Note this comment:
/* Must be after DS reload */ unlazy_fpu(prev_p);
Quoted 7 lines
Are you sure you're not confusing with another one ? When running estest without this patch, I get "FAIL: ES corrupted 1000/1000 times" while I get "OK: ES was preserved" once applied, so it does seem to do what it's intended for.
Also I'm not seeing any reference to the comment above in the patch nor around it, which leaves me confused :-/
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
commit 0a5ace2ab08d45cd78d7ef0067cdcd5c812ac54f
Author: Andi Kleen <[email protected]> Date: Thu Oct 5 18:47:22 2006 +0200
[PATCH] x86-64: Fix FPU corruption
Ben.
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
Quoted 39 lines · Ben Hutchings
Quoted 28 lines · Willy Tarreau
Hi Ben,
Quoted 17 lines · Ben Hutchings
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit
f647d7c155f069c1a068030255c300663516420eupstream.Quoted 8 lines
Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch.
This also significantly improves the comments and documents some gotchas in the code.
Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails.
Quoted 7 lines
[...]
This depends on the changes to FPU/MMX/SSE state management that you didn't apply to 2.6.32. Note this comment:
/* Must be after DS reload */ unlazy_fpu(prev_p);Quoted 7 lines
Are you sure you're not confusing with another one ? When running estest without this patch, I get "FAIL: ES corrupted 1000/1000 times" while I get "OK: ES was preserved" once applied, so it does seem to do what it's intended for.
Also I'm not seeing any reference to the comment above in the patch nor around it, which leaves me confused :-/
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
Quoted 8 lines
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
commit
0a5ace2ab08d45cd78d7ef0067cdcd5c812ac54fAuthor: Andi Kleen <[email protected]> Date: Thu Oct 5 18:47:22 2006 +0200[PATCH] x86-64: Fix FPU corruption
And that replaced a longer comment that said "the AMD workaround requires it to be after DS reload". The comment above clear_fpu_state() says:
/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
is pending. Clear the x87 state here by setting it to fixed values. The kernel data segment can be sometimes 0 and sometimes new user value. Both should be ok.
Use the PDA as safe address because it should be already in L1. */
Hopefully Andi can explain further if needed; I have no idea.
Ben.
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
In reply to Ben HutchingsQuoted 34 lines · Ben Hutchings
Quoted 33 lines · Willy Tarreau
Hi Ben,
Quoted 17 lines · Ben Hutchings
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit
f647d7c155f069c1a068030255c300663516420eupstream.Quoted 8 lines
Otherwise, if buggy user code points DS or ES into the TLS array, they would be corrupted after a context switch.
This also significantly improves the comments and documents some gotchas in the code.
Before this patch, the both tests below failed. With this patch, the es test passes, although the gsbase test still fails.
Quoted 7 lines
[...]
This depends on the changes to FPU/MMX/SSE state management that you didn't apply to 2.6.32. Note this comment:
/* Must be after DS reload */ unlazy_fpu(prev_p);Are you sure you're not confusing with another one ? When running estest without this patch, I get "FAIL: ES corrupted 1000/1000 times" while I get "OK: ES was preserved" once applied, so it does seem to do what it's intended for.
Quoted 4 lines
Quoted 2 lines
Also I'm not seeing any reference to the comment above in the patch nor around it, which leaves me confused :-/
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
Ah OK I missed it, thanks.
Quoted 8 lines
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
commit
0a5ace2ab08d45cd78d7ef0067cdcd5c812ac54fAuthor: Andi Kleen <[email protected]> Date: Thu Oct 5 18:47:22 2006 +0200[PATCH] x86-64: Fix FPU corruption
Indeed! Andy, is there any practical case covered by your patch that should motivate a safe way to backport it, or can we simply drop it for 2.6.32 ? I don't intend to backport the FPU state management series that late in the cycle just for this!
Thanks!
Willy
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
In reply to Ben HutchingsQuoted 5 lines
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
Yes I already stated before that these super-risky patches are not stable material.
-Andi
Quoted 12 lines
commit
0a5ace2ab08d45cd78d7ef0067cdcd5c812ac54fAuthor: Andi Kleen <[email protected]> Date: Thu Oct 5 18:47:22 2006 +0200[PATCH] x86-64: Fix FPU corruption
Ben.
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
Signature · 1 line
[email protected] -- Speaking for myself only.
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
Quoted 8 lines · Andi Kleen
Quoted 5 lines
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
Yes I already stated before that these super-risky patches are not stable material.
OK thank you Andi, I'm dropping it from -32 then.
Willy
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
In reply to Andi KleenQuoted 8 lines · Andi Kleen
Quoted 5 lines
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
Yes I already stated before that these super-risky patches are not stable material.
[...]
Which other patches do you include in that?
Ben.
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
Re: [ 05/48] x86_64, switch_to(): Load TLS descriptors before switching DS and ES
Quoted 4 lines · Ben Hutchings
Quoted 3 lines · Andi Kleen
Quoted 3 lines
v2.6.32.65:arch/x86/kernel/process_64.c:425: /* Must be after DS reload */
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
If this comment is correct then the patch will cause a regression for FPU state management. The comment was introduced by:
Yes I already stated before that these super-risky patches are not stable material.
[...]
Which other patches do you include in that?
Sorry I misspoke. Currently it's only that one.
-Andi
PATCH 6/48 x86/tls: Disallow unusual TLS segments
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 0e58af4e1d2166e9e33375a0f121e4867010d4f8 upstream.
Users have no business installing custom code segments into the GDT, and segments that are not present but are otherwise valid are a historical source of interesting attacks.
For completeness, block attempts to set the L bit. (Prior to this patch, the L bit would have been silently dropped.)
This is an ABI break. I've checked glibc, musl, and Wine, and none of them look like they'll have any trouble.
Note to stable maintainers: this is a hardening patch that fixes no known bugs. Given the possibility of ABI issues, this probably shouldn't be backported quickly.
--- arch/x86/kernel/tls.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
arch/x86/kernel/tls.c +22 -0
@@ -61,6 +61,28 @@ static bool tls_desc_okay(const struct user_desc *info)if (!info->seg_32bit)return false; +/* Only allow data segments in the TLS array. */ +if (info->contents >1 ) +return false; + +/* +* Non-present segments with DPL 3 present an interesting attack +* surface. The kernel should handle such segments correctly, +* but TLS is very difficult to protect in a sandbox, so prevent +* such segments from being created. +* +* If userspace needs to remove a TLS entry, it can still delete +* it outright. +*/ +if (info->seg_not_present) +return false; + +#ifdef CONFIG_X86_64 +/* The L bit makes no sense for data. */ +if (info->lm) +return false; +#endif +return true; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 7/48 x86/tls: Dont validate lm in set_thread_area() after all
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 3fb2f4237bb452eb4e98f6a5dbd5a445b4fed9d0 upstream.
It turns out that there's a lurking ABI issue. GCC, when compiling this in a 32-bit program:
struct user_desc desc = {
.entry_number = idx,
.base_addr = base,
.limit = 0xfffff,
.seg_32bit = 1,
.contents = 0, /* Data, grow-up */
.read_exec_only = 0,
.limit_in_pages = 1,
.seg_not_present = 0,
.useable = 0,
};will leave .lm uninitialized. This means that anything in the kernel that reads user_desc.lm for 32-bit tasks is unreliable.
Revert the .lm check in set_thread_area(). The value never did anything in the first place.
--- arch/x86/include/asm/ldt.h | 7 +++++++ arch/x86/kernel/tls.c | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-)
arch/x86/include/asm/ldt.h +7 -0
@@ -28,6 +28,13 @@ struct user_desc { unsigned int seg_not_present:1; unsigned int useable:1;#ifdef __x86_64__ +/* +* Because this bit is not present in 32-bit user code, user +* programs can pass uninitialized values here. Therefore, in +* any context in which a user_desc comes from a 32-bit program, +* the kernel must act as though lm == 0, regardless of the +* actual value. +*/ unsigned int lm:1;#endif };
arch/x86/kernel/tls.c +0 -6
@@ -77,12 +77,6 @@ static bool tls_desc_okay(const struct user_desc *info)if (info->seg_not_present)return false; -#ifdef CONFIG_X86_64 -/* The L bit makes no sense for data. */ -if (info->lm) -return false; -#endif -return true; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 8/48 x86, kvm: Clear paravirt_enabled on KVM guests for espfix32s benefit
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 29fa6825463c97e5157284db80107d1bfac5d77b upstream
paravirt_enabled has the following effects:
- Disables the F00F bug workaround warning. There is no F00F bug workaround any more because Linux's standard IDT handling already works around the F00F bug, but the warning still exists. This is only cosmetic, and, in any event, there is no such thing as KVM on a CPU with the F00F bug.
- Disables 32-bit APM BIOS detection. On a KVM paravirt system, there should be no APM BIOS anyway.
- Disables tboot. I think that the tboot code should check the CPUID hypervisor bit directly if it matters.
- paravirt_enabled disables espfix32. espfix32 should *not* be disabled under KVM paravirt.
The last point is the purpose of this patch. It fixes a leak of the high 16 bits of the kernel stack address on 32-bit KVM paravirt guests. Fixes CVE-2014-8134.
--- arch/x86/kernel/kvm.c | 9 ++++++++- arch/x86/kernel/kvmclock.c | 1 - 2 files changed, 8 insertions(+), 2 deletions(-)
arch/x86/kernel/kvm.c +8 -1
@@ -198,7 +198,14 @@ static void kvm_leave_lazy_mmu(void)static void __init paravirt_ops_setup (void ) { pv_info.name ="KVM" ; - pv_info.paravirt_enabled =1 ; + +/* +* KVM isn't paravirt in the sense of paravirt_enabled. A KVM +* guest kernel works like a bare metal kernel with additional +* features, and paravirt_enabled is about features that are +* missing. +*/ + pv_info.paravirt_enabled =0 ;if (kvm_para_has_feature (KVM_FEATURE_NOP_IO_DELAY )) pv_cpu_ops.io_delay = kvm_io_delay;
arch/x86/kernel/kvmclock.c +0 -1
@@ -201,7 +201,6 @@ void __init kvmclock_init(void)#endif kvm_get_preset_lpj ();clocksource_register (&kvm_clock); - pv_info.paravirt_enabled =1 ; pv_info.name ="KVM" ; } }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 9/48 x86_64, vdso: Fix the vdso address randomization algorithm
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 394f56fe480140877304d342dec46d50dc823d46 upstream
The theory behind vdso randomization is that it's mapped at a random offset above the top of the stack. To avoid wasting a page of memory for an extra page table, the vdso isn't supposed to extend past the lowest PMD into which it can fit. Other than that, the address should be a uniformly distributed address that meets all of the alignment requirements.
The current algorithm is buggy: the vdso has about a 50% probability of being at the very end of a PMD. The current algorithm also has a decent chance of failing outright due to incorrect handling of the case where the top of the stack is near the top of its PMD.
This fixes the implementation. The paxtest estimate of vdso "randomisation" improves from 11 bits to 18 bits. (Disclaimer: I don't know what the paxtest code is actually calculating.)
It's worth noting that this algorithm is inherently biased: the vdso is more likely to end up near the end of its PMD than near the beginning. Ideally we would either nix the PMD sharing requirement or jointly randomize the vdso and the stack to reduce the bias.
In the mean time, this is a considerable improvement with basically no risk of compatibility issues, since the allowed outputs of the algorithm are unchanged.
As an easy test, doing this:
for i in seq 10000
do grep -P vdso /proc/self/maps |cut -d- -f1
done |sort |uniq -d
used to produce lots of output (1445 lines on my most recent run). A tiny subset looks like this:
7fffdfffe0007fffe01fe0007fffe05fe0007fffe07fe0007fffe09fe0007fffe0bfe0007fffe0dfe000
Note the suspicious fe000 endings. With the fix, I get a much more palatable 76 repeated addresses.
[bwh: Backported to 2.6.32:
- The whole file is only built for x86_64; adjust context and comment for this
- We don't have align_vdso_addr()]
--- arch/x86/vdso/vma.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-)
arch/x86/vdso/vma.c +26 -10
@@ -77,23 +77,39 @@ __initcall(init_vdso_vars);struct linux_binprm ; -/* Put the vdso above the (randomized) stack with another randomized offset. -This way there is no hole in the middle of address space. -To save memory make sure it is still in the same PTE as the stack top. -This doesn't give that many random bits */ +/* +* Put the vdso above the (randomized) stack with another randomized +* offset. This way there is no hole in the middle of address space. +* To save memory make sure it is still in the same PTE as the stack +* top. This doesn't give that many random bits. +* +* Note that this algorithm is imperfect: the distribution of the vdso +* start address within a PMD is biased toward the end. +*/ static unsigned long vdso_addr (unsigned long start,unsigned len) {unsigned long addr, end;unsigned offset; - end = (start +PMD_SIZE -1 ) &PMD_MASK ; + +/* +* Round up the start address. It can start out unaligned as a result +* of stack start randomization. +*/ + start =PAGE_ALIGN (start); + +/* Round the lowest possible end address up to a PMD boundary. */ + end = (start + len +PMD_SIZE -1 ) &PMD_MASK ;if (end >=TASK_SIZE_MAX ) end =TASK_SIZE_MAX ; end -= len; -/* This loses some more bits than a modulo, but is cheaper */ - offset =get_random_int () & (PTRS_PER_PTE -1 ); - addr = start + (offset <<PAGE_SHIFT ); -if (addr >= end) - addr = end; + +if (end > start) { + offset =get_random_int () % (((end - start) >>PAGE_SHIFT ) +1 ); + addr = start + (offset <<PAGE_SHIFT ); + }else { + addr = start; + } +return addr; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 09/48] x86_64, vdso: Fix the vdso address randomization algorithm
Quoted 53 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit
394f56fe480140877304d342dec46d50dc823d46upstreamThe theory behind vdso randomization is that it's mapped at a random offset above the top of the stack. To avoid wasting a page of memory for an extra page table, the vdso isn't supposed to extend past the lowest PMD into which it can fit. Other than that, the address should be a uniformly distributed address that meets all of the alignment requirements.
The current algorithm is buggy: the vdso has about a 50% probability of being at the very end of a PMD. The current algorithm also has a decent chance of failing outright due to incorrect handling of the case where the top of the stack is near the top of its PMD.
This fixes the implementation. The paxtest estimate of vdso "randomisation" improves from 11 bits to 18 bits. (Disclaimer: I don't know what the paxtest code is actually calculating.)
It's worth noting that this algorithm is inherently biased: the vdso is more likely to end up near the end of its PMD than near the beginning. Ideally we would either nix the PMD sharing requirement or jointly randomize the vdso and the stack to reduce the bias.
In the mean time, this is a considerable improvement with basically no risk of compatibility issues, since the allowed outputs of the algorithm are unchanged.
As an easy test, doing this:
for i in
seq 10000
do grep -P vdso/proc/self/maps|cut -d- -f1
done |sort |uniq -dused to produce lots of output (1445 lines on my most recent run). A tiny subset looks like this:
7fffdfffe0007fffe01fe0007fffe05fe0007fffe07fe0007fffe09fe0007fffe0bfe0007fffe0dfe000Note the suspicious fe000 endings. With the fix, I get a much more palatable 76 repeated addresses.
Quoted 6 lines
Reviewed-by Kees Cook <[email protected]>Signed-off-by Andy Lutomirski <[email protected]>[bwh: Backported to 2.6.32:
- The whole file is only built forx86_64; adjust context and comment for this
- We don't havealign_vdso_addr()]
Quoted 1 line
Signed-off-by Willy Tarreau <[email protected]>
[...]
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
PATCH 10/48 ASLR: fix stack randomization on 64-bit systems
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Hector Marco-Gisbert <[email protected]>
commit 4e7c22d447bb6d7e37bfe39ff658486ae78e8d77 upstream
The issue is that the stack for processes is not properly randomized on 64 bit architectures due to an integer overflow.
The affected function is randomize_stack_top() in file "fs/binfmt_elf.c":
static unsigned long randomize_stack_top(unsigned long stack_top)
{
unsigned int random_variable = 0;
if ((current->flags & PF_RANDOMIZE) &&
!(current->personality & ADDR_NO_RANDOMIZE)) {
random_variable = get_random_int() & STACK_RND_MASK;
random_variable <<= PAGE_SHIFT;
}
return PAGE_ALIGN(stack_top) + random_variable;
return PAGE_ALIGN(stack_top) - random_variable;
}Note that, it declares the "random_variable" variable as "unsigned int". Since the result of the shifting operation between STACK_RND_MASK (which is 0x3fffff on x86_64, 22 bits) and PAGE_SHIFT (which is 12 on x86_64):
random_variable <<= PAGE_SHIFT;
then the two leftmost bits are dropped when storing the result in the "random_variable". This variable shall be at least 34 bits long to hold the (22+12) result.
These two dropped bits have an impact on the entropy of process stack. Concretely, the total stack entropy is reduced by four: from 2^28 to 2^30 (One fourth of expected entropy).
This patch restores back the entropy by correcting the types involved in the operations in the functions randomize_stack_top() and stack_maxrandom_size().
The successful fix can be tested with:
$ for i in `seq 1 10`; do cat /proc/self/maps | grep stack; done 7ffeda566000-7ffeda587000 rw-p 00000000 00:00 0 [stack] 7fff5a332000-7fff5a353000 rw-p 00000000 00:00 0 [stack] 7ffcdb7a1000-7ffcdb7c2000 rw-p 00000000 00:00 0 [stack] 7ffd5e2c4000-7ffd5e2e5000 rw-p 00000000 00:00 0 [stack] ...
Once corrected, the leading bytes should be between 7ffc and 7fff, rather than always being 7fff.
CVE-2015-1593
--- arch/x86/mm/mmap.c | 6 +++--- fs/binfmt_elf.c | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-)
arch/x86/mm/mmap.c +3 -3
@@ -31,12 +31,12 @@#include <linux/sched.h> #include <asm/elf.h> -static unsigned int stack_maxrandom_size (void ) +static unsigned long stack_maxrandom_size (void ) { -unsigned int max =0 ; +unsigned long max =0 ;if ((current->flags &PF_RANDOMIZE ) && !(current->personality &ADDR_NO_RANDOMIZE )) { - max = ((-1U ) &STACK_RND_MASK ) <<PAGE_SHIFT ; + max = ((-1UL ) &STACK_RND_MASK ) <<PAGE_SHIFT ; }return max;
fs/binfmt_elf.c +3 -2
@@ -546,11 +546,12 @@ out:static unsigned long randomize_stack_top (unsigned long stack_top) { -unsigned int random_variable =0 ; +unsigned long random_variable =0 ;if ((current->flags &PF_RANDOMIZE ) && !(current->personality &ADDR_NO_RANDOMIZE )) { - random_variable =get_random_int () &STACK_RND_MASK ; + random_variable = (unsigned long )get_random_int (); + random_variable &=STACK_RND_MASK ; random_variable <<=PAGE_SHIFT ; }#ifdef CONFIG_STACK_GROWSUP
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 11/48 x86, cpu, amd: Add workaround for family 16h, erratum 793
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Borislav Petkov <[email protected]>
commit 3b56496865f9f7d9bcb2f93b44c63f274f08e3b6 upstream
This adds the workaround for erratum 793 as a precaution in case not every BIOS implements it. This addresses CVE-2013-6885.
Erratum text:
[Revision Guide for AMD Family 16h Models 00h-0Fh Processors, document 51810 Rev. 3.04 November 2013]
793 Specific Combination of Writes to Write Combined Memory Types and Locked Instructions May Cause Core Hang
Description
Under a highly specific and detailed set of internal timing conditions, a locked instruction may trigger a timing sequence whereby the write to a write combined memory type is not flushed, causing the locked instruction to stall indefinitely.
Potential Effect on System
Processor core hang.
Suggested Workaround
BIOS should set MSR
C001_1020[15] = 1b.
Fix Planned
No fix planned
[ hpa: updated description, fixed typo in MSR name ]
[bwh: Backported to 3.2:
- Adjust filename
- Venkatesh Srinivas pointed out we should use {rd,wr}msrl_safe() to avoid crashing on KVM. This was fixed upstream by commit 8f86a7373a1c ("x86, AMD: Convert to the new bit access MSR accessors") but that's too much trouble to backport. Here we must use {rd,wr}msrl_amd_safe().]
--- arch/x86/include/asm/msr-index.h | 1 + arch/x86/kernel/cpu/amd.c | 10 ++++++++++ 2 files changed, 11 insertions(+)
arch/x86/include/asm/msr-index.h +1 -0
@@ -110,6 +110,7 @@#define MSR_AMD64_PATCH_LOADER 0xc0010020#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140#define MSR_AMD64_OSVW_STATUS 0xc0010141 +#define MSR_AMD64_LS_CFG 0xc0011020#define MSR_AMD64_DC_CFG 0xc0011022#define MSR_AMD64_IBSFETCHCTL 0xc0011030#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
arch/x86/kernel/cpu/amd.c +10 -0
@@ -413,6 +413,16 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) set_cpu_cap(c, X86_FEATURE_EXTD_APICID); }#endif + +/* F16h erratum 793, CVE-2013-6885 */ +if (c->x86 ==0x16 && c->x86_model <=0xf ) { +u64 val; + +if (!rdmsrl_amd_safe (MSR_AMD64_LS_CFG , &val) && + !(val &BIT (15 ))) +wrmsrl_amd_safe (MSR_AMD64_LS_CFG , val |BIT (15 )); + } + }static void __cpuinit init_amd (struct cpuinfo_x86 *c)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 12/48 x86/asm/entry/64: Remove a bogus ret_from_fork optimization
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andy Lutomirski <[email protected]>
commit 956421fbb74c3a6261903f3836c0740187cf038b upstream.
'ret_from_fork' checks TIF_IA32 to determine whether 'pt_regs' and the related state make sense for 'ret_from_sys_call'. This is entirely the wrong check. TS_COMPAT would make a little more sense, but there's really no point in keeping this optimization at all.
This fixes a return to the wrong user CS if we came from int 0x80 in a 64-bit task.
--- arch/x86/kernel/entry_64.S | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
arch/x86/kernel/entry_64.S +8 -5
@@ -413,11 +413,14 @@ ENTRY(ret_from_fork) testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? je int_ret_from_sys_call - testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET - jnz int_ret_from_sys_call - - RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET - jmp ret_from_sys_call # go to the SYSRET fastpath + /* + * By the time we get here, we have no idea whether our pt_regs, + * ti flags, and ti status came from the 64-bit SYSCALL fast path, + * the slow path, or one of the ia32entry paths. + * Use int_ret_from_sys_call to return, since it can safely handle + * all of the above. + */ + jmp int_ret_from_sys_call CFI_ENDPROC END(ret_from_fork)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 13/48 x86: Conditionally update time when ack-ing pending irqs
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Shai Fultheim <[email protected]>
commit 42fa4250436304d4650fa271f37671f6cee24e08 upstream.
On virtual environments, apic_read could take a long time. As a result, under certain conditions the ack pending loop may exit without any queued irqs left, but after more than one second. A warning will be printed needlessly in this case.
If the loop is about to exit regardless of max_loops, don't update it.
--- arch/x86/kernel/apic/apic.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
arch/x86/kernel/apic/apic.c +7 -5
@@ -1250,11 +1250,13 @@ void __cpuinit setup_local_APIC(void) acked);break ; } -if (cpu_has_tsc) { -rdtscll (ntsc); - max_loops = (cpu_khz <<10 ) - (ntsc - tsc); - }else - max_loops--; +if (queued) { +if (cpu_has_tsc) { +rdtscll (ntsc); + max_loops = (cpu_khz <<10 ) - (ntsc - tsc); + }else + max_loops--; + } }while (queued && max_loops >0 );WARN_ON (max_loops <=0 );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 14/48 serial: samsung: wait for transfer completion before clock disable
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Robert Baldyga <[email protected]>
This patch adds waiting until transmit buffer and shifter will be empty before clock disabling.
Without this fix it's possible to have clock disabled while data was not transmited yet, which causes unproper state of TX line and problems in following data transfers.
--- drivers/serial/samsung.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/serial/samsung.c +4 -0
@@ -443,11 +443,15 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) {struct s3c24xx_uart_port *ourport =to_ourport (port); +int timeout =10000 ; ourport->pm_level = level;switch (level) {case 3 : +while (--timeout && !s3c24xx_serial_txempty_nofifo (port)) +udelay (100 ); +if (!IS_ERR (ourport->baudclk) && ourport->baudclk !=NULL )clk_disable (ourport->baudclk);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 15/48 splice: Apply generic position and size checks to each write
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Ben Hutchings <[email protected]>
We need to check the position and size of file writes against various limits, using generic_write_check(). This was not being done for the splice write path. It was fixed upstream by commit 8d0207652cbe ("->splice_write() via ->write_iter()") but we can't apply that.
CVE-2014-7822
--- fs/ocfs2/file.c | 8 ++++++-- fs/splice.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-)
fs/ocfs2/file.c +6 -2
@@ -2081,9 +2081,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,struct address_space *mapping = out->f_mapping;struct inode *inode = mapping->host;struct splice_desc sd = { - .total_len = len, .flags = flags, - .pos = *ppos, .u.file = out, };
@@ -2092,6 +2090,12 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, out->f_path.dentry->d_name.len, out->f_path.dentry->d_name.name); + ret =generic_write_checks (out, ppos, &len,0 ); +if (ret) +return ret; + sd.total_len = len; + sd.pos = *ppos; +if (pipe->inode)mutex_lock_nested (&pipe->inode->i_mutex,I_MUTEX_PARENT );
fs/splice.c +6 -2
@@ -945,13 +945,17 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,struct address_space *mapping = out->f_mapping;struct inode *inode = mapping->host;struct splice_desc sd = { - .total_len = len, .flags = flags, - .pos = *ppos, .u.file = out, };ssize_t ret; + ret =generic_write_checks (out, ppos, &len,S_ISBLK (inode->i_mode)); +if (ret) +return ret; + sd.total_len = len; + sd.pos = *ppos; +pipe_lock (pipe);splice_from_pipe_begin (&sd);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 16/48 netfilter: conntrack: disable generic tracking for known protocols
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit db29a9508a9246e77087c5531e45b2c88ec6988b upstream
Given following iptables ruleset:
-P FORWARD DROP
-A FORWARD -m sctp --dport 9 -j ACCEPT
-A FORWARD -p tcp --dport 80 -j ACCEPT
-A FORWARD -p tcp -m conntrack -m state ESTABLISHED,RELATED -j ACCEPT
One would assume that this allows SCTP on port 9 and TCP on port 80. Unfortunately, if the SCTP conntrack module is not loaded, this allows *all* SCTP communication, to pass though, i.e. -p sctp -j ACCEPT, which we think is a security issue.
This is because on the first SCTP packet on port 9, we create a dummy "generic l4" conntrack entry without any port information (since conntrack doesn't know how to extract this information).
All subsequent packets that are unknown will then be in established state since they will fallback to proto_generic and will match the 'generic' entry.
Our originally proposed version [1] completely disabled generic protocol tracking, but Jozsef suggests to not track protocols for which a more suitable helper is available, hence we now mitigate the issue for in tree known ct protocol helpers only, so that at least NAT and direction information will still be preserved for others.
[1] http://www.spinics.net/lists/netfilter-devel/msg33430.html
Joint work with Daniel Borkmann.
--- net/netfilter/nf_conntrack_proto_generic.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
net/netfilter/nf_conntrack_proto_generic.c +25 -1
@@ -14,6 +14,30 @@static unsigned int nf_ct_generic_timeout__read_mostly =600 *HZ ; +static bool nf_generic_should_process (u8 proto) +{ +switch (proto) { +#ifdef CONFIG_NF_CT_PROTO_SCTP_MODULE +case IPPROTO_SCTP : +return false; +#endif +#ifdef CONFIG_NF_CT_PROTO_DCCP_MODULE +case IPPROTO_DCCP : +return false; +#endif +#ifdef CONFIG_NF_CT_PROTO_GRE_MODULE +case IPPROTO_GRE : +return false; +#endif +#ifdef CONFIG_NF_CT_PROTO_UDPLITE_MODULE +case IPPROTO_UDPLITE : +return false; +#endif +default : +return true; + } +} +static bool generic_pkt_to_tuple (const struct sk_buff *skb,unsigned int dataoff,struct nf_conntrack_tuple *tuple)
@@ -56,7 +80,7 @@ static int packet(struct nf_conn *ct,static bool new (struct nf_conn *ct,const struct sk_buff *skb,unsigned int dataoff) { -return true; +return nf_generic_should_process (nf_ct_protonum (ct)); }#ifdef CONFIG_SYSCTL
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 16/48] netfilter: conntrack: disable generic tracking for known protocols
Quoted 36 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit
db29a9508a9246e77087c5531e45b2c88ec6988bupstreamGiven following iptables ruleset:
(quoted diff) +0
-4-P FORWARD DROP -A FORWARD -m sctp --dport 9 -j ACCEPT -A FORWARD -p tcp --dport 80 -j ACCEPT -A FORWARD -p tcp -m conntrack -m state ESTABLISHED,RELATED -j ACCEPTOne would assume that this allows SCTP on port 9 and TCP on port 80. Unfortunately, if the SCTP conntrack module is not loaded, this allows *all* SCTP communication, to pass though, i.e. -p sctp -j ACCEPT, which we think is a security issue.
This is because on the first SCTP packet on port 9, we create a dummy "generic l4" conntrack entry without any port information (since conntrack doesn't know how to extract this information).
All subsequent packets that are unknown will then be in established state since they will fallback to
proto_genericand will match the 'generic' entry.Our originally proposed version [1] completely disabled generic protocol tracking, but Jozsef suggests to not track protocols for which a more suitable helper is available, hence we now mitigate the issue for in tree known ct protocol helpers only, so that at least NAT and direction information will still be preserved for others.
[1] http://www.spinics.net/lists/netfilter-devel/msg33430.html
Quoted 7 lines
Joint work with Daniel Borkmann.
Signed-off-by Florian Westphal <[email protected]>Signed-off-by Daniel Borkmann <[email protected]>Acked-by Jozsef Kadlecsik <[email protected]>Signed-off-by Pablo Neira Ayuso <[email protected]>[bwh: Backported to 2.6.32: adjust context]
Quoted 1 line
Signed-off-by Willy Tarreau <[email protected]>
[...]
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
PATCH 17/48 isofs: Fix infinite looping over CE entries
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit f54e18f1b831c92f6512d2eedb224cd63d607d3d upstream
Rock Ridge extensions define so called Continuation Entries (CE) which define where is further space with Rock Ridge data. Corrupted isofs image can contain arbitrarily long chain of these, including a one containing loop and thus causing kernel to end in an infinite loop when traversing these entries.
Limit the traversal to 32 entries which should be more than enough space to store all the Rock Ridge data.
--- fs/isofs/rock.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/isofs/rock.c +6 -0
@@ -31,6 +31,7 @@ struct rock_state {int cont_size;int cont_extent;int cont_offset; +int cont_loops;struct inode *inode; };
@@ -74,6 +75,9 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode) rs->inode = inode; } +/* Maximum number of Rock Ridge continuation entries */ +#define RR_MAX_CE_ENTRIES 32 +/* * Returns 0 if the caller should continue scanning, 1 if the scan must end * and -ve on error.
@@ -106,6 +110,8 @@ static int rock_continue(struct rock_state *rs) goto out; } ret = -EIO ; +if (++rs->cont_loops >=RR_MAX_CE_ENTRIES ) + goto out; bh =sb_bread (rs->inode->i_sb, rs->cont_extent);if (bh) { memcpy(rs->buffer, bh->b_data + rs->cont_offset,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 18/48 isofs: Fix unchecked printing of ER records
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit 4e2024624e678f0ebb916e6192bd23c1f9fdf696 upstream
We didn't check length of rock ridge ER records before printing them. Thus corrupted isofs image can cause us to access and print some memory behind the buffer with obvious consequences.
--- fs/isofs/rock.c | 3 +++ 1 file changed, 3 insertions(+)
fs/isofs/rock.c +3 -0
@@ -363,6 +363,9 @@ repeat: rs.cont_size =isonum_733 (rr->u.CE.size);break ;case SIG ('E' ,'R' ): +/* Invalid length of ER tag id? */ + if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len) + goto out;ISOFS_SB (inode->i_sb)->s_rock =1 ;printk (KERN_DEBUG "ISO 9660 Extensions: " ); {
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 19/48 net: sctp: fix memory leak in auth key management
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <[email protected]>
commit 4184b2a79a7612a9272ce20d639934584a1f3786 upstream.
A very minimal and simple user space application allocating an SCTP socket, setting SCTP_AUTH_KEY setsockopt(2) on it and then closing the socket again will leak the memory containing the authentication key from user space:
unreferenced object 0xffff8800837047c0 (size 16):
comm "a.out", pid 2789, jiffies 4296954322 (age 192.258s) hex dump (first 16 bytes):
01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<ffffffff816d7e8e>] kmemleak_alloc+0x4e/0xb0
[<ffffffff811c88d8>] __kmalloc+0xe8/0x270
[<ffffffffa0870c23>] sctp_auth_create_key+0x23/0x50 [sctp]
[<ffffffffa08718b1>] sctp_auth_set_key+0xa1/0x140 [sctp]
[<ffffffffa086b383>] sctp_setsockopt+0xd03/0x1180 [sctp]
[<ffffffff815bfd94>] sock_common_setsockopt+0x14/0x20
[<ffffffff815beb61>] SyS_setsockopt+0x71/0xd0
[<ffffffff816e58a9>] system_call_fastpath+0x12/0x17
[<ffffffffffffffff>] 0xffffffffffffffffThis is bad because of two things, we can bring down a machine from user space when auth_enable=1, but also we would leave security sensitive keying material in memory without clearing it after use. The issue is that sctp_auth_create_key() already sets the refcount to 1, but after allocation sctp_auth_set_key() does an additional refcount on it, and thus leaving it around when we free the socket.
--- net/sctp/auth.c | 2 -- 1 file changed, 2 deletions(-)
net/sctp/auth.c +0 -2
@@ -865,8 +865,6 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,list_add (&cur_key->key_list, sh_keys); cur_key->key = key; -sctp_auth_key_hold (key); -return 0 ; nomem:if (!replace)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 20/48 net: sctp: fix slab corruption from use after free on INIT collisions
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <[email protected]>
commit 600ddd6825543962fb807884169e57b580dba208 upstream
When hitting an INIT collision case during the 4WHS with AUTH enabled, as already described in detail in commit 1be9a950c646 ("net: sctp: inherit auth_capable on INIT collisions"), it can happen that we occasionally still remotely trigger the following panic on server side which seems to have been uncovered after the fix from commit 1be9a950c646 ...
[ 533.876389] BUG: unable to handle kernel paging request at 00000000ffffffff [ 533.913657] IP: [<ffffffff811ac385>] __kmalloc+0x95/0x230 [ 533.940559] PGD 5030f2067 PUD 0 [ 533.957104] Oops: 0000 [#1] SMP [ 533.974283] Modules linked in: sctp mlx4_en [...] [ 534.939704] Call Trace: [ 534.951833] [<ffffffff81294e30>] ? crypto_init_shash_ops+0x60/0xf0 [ 534.984213] [<ffffffff81294e30>] crypto_init_shash_ops+0x60/0xf0 [ 535.015025] [<ffffffff8128c8ed>] __crypto_alloc_tfm+0x6d/0x170 [ 535.045661] [<ffffffff8128d12c>] crypto_alloc_base+0x4c/0xb0 [ 535.074593] [<ffffffff8160bd42>] ? _raw_spin_lock_bh+0x12/0x50 [ 535.105239] [<ffffffffa0418c11>] sctp_inet_listen+0x161/0x1e0 [sctp] [ 535.138606] [<ffffffff814e43bd>] SyS_listen+0x9d/0xb0 [ 535.166848] [<ffffffff816149a9>] system_call_fastpath+0x16/0x1b
... or depending on the the application, for example this one:
[ 1370.026490] BUG: unable to handle kernel paging request at 00000000ffffffff [ 1370.026506] IP: [<ffffffff811ab455>] kmem_cache_alloc+0x75/0x1d0 [ 1370.054568] PGD 633c94067 PUD 0 [ 1370.070446] Oops: 0000 [#1] SMP [ 1370.085010] Modules linked in: sctp kvm_amd kvm [...] [ 1370.963431] Call Trace: [ 1370.974632] [<ffffffff8120f7cf>] ? SyS_epoll_ctl+0x53f/0x960 [ 1371.000863] [<ffffffff8120f7cf>] SyS_epoll_ctl+0x53f/0x960 [ 1371.027154] [<ffffffff812100d3>] ? anon_inode_getfile+0xd3/0x170 [ 1371.054679] [<ffffffff811e3d67>] ? __alloc_fd+0xa7/0x130 [ 1371.080183] [<ffffffff816149a9>] system_call_fastpath+0x16/0x1b
With slab debugging enabled, we can see that the poison has been overwritten:
[ 669.826368] BUG kmalloc-128 (Tainted: G W ): Poison overwritten [ 669.826385] INFO: 0xffff880228b32e50-0xffff880228b32e50. First byte 0x6a instead of 0x6b [ 669.826414] INFO: Allocated in sctp_auth_create_key+0x23/0x50 [sctp] age=3 cpu=0 pid=18494 [ 669.826424] __slab_alloc+0x4bf/0x566 [ 669.826433] __kmalloc+0x280/0x310 [ 669.826453] sctp_auth_create_key+0x23/0x50 [sctp] [ 669.826471] sctp_auth_asoc_create_secret+0xcb/0x1e0 [sctp] [ 669.826488] sctp_auth_asoc_init_active_key+0x68/0xa0 [sctp] [ 669.826505] sctp_do_sm+0x29d/0x17c0 [sctp] [...] [ 669.826629] INFO: Freed in kzfree+0x31/0x40 age=1 cpu=0 pid=18494 [ 669.826635] __slab_free+0x39/0x2a8 [ 669.826643] kfree+0x1d6/0x230 [ 669.826650] kzfree+0x31/0x40 [ 669.826666] sctp_auth_key_put+0x19/0x20 [sctp] [ 669.826681] sctp_assoc_update+0x1ee/0x2d0 [sctp] [ 669.826695] sctp_do_sm+0x674/0x17c0 [sctp]
Since this only triggers in some collision-cases with AUTH, the problem at heart is that sctp_auth_key_put() on asoc->asoc_shared_key is called twice when having refcnt 1, once directly in sctp_assoc_update() and yet again from within sctp_auth_asoc_init_active_key() via sctp_assoc_update() on the already kzfree'd memory, which is also consistent with the observation of the poison decrease from 0x6b to 0x6a (note: the overwrite is detected at a later point in time when poison is checked on new allocation).
Reference counting of auth keys revisited:
Shared keys for AUTH chunks are being stored in endpoints and associations in endpoint_shared_keys list. On endpoint creation, a null key is being added; on association creation, all endpoint shared keys are being cached and thus cloned over to the association. struct sctp_shared_key only holds a pointer to the actual key bytes, that is, struct sctp_auth_bytes which keeps track of users internally through refcounting. Naturally, on assoc or enpoint destruction, sctp_shared_key are being destroyed directly and the reference on sctp_auth_bytes dropped.
User space can add keys to either list via setsockopt(2) through struct sctp_authkey and by passing that to sctp_auth_set_key() which replaces or adds a new auth key. There, sctp_auth_create_key() creates a new sctp_auth_bytes with refcount 1 and in case of replacement drops the reference on the old sctp_auth_bytes. A key can be set active from user space through setsockopt() on the id via sctp_auth_set_active_key(), which iterates through either endpoint_shared_keys and in case of an assoc, invokes (one of various places) sctp_auth_asoc_init_active_key().
sctp_auth_asoc_init_active_key() computes the actual secret from local's and peer's random, hmac and shared key parameters and returns a new key directly as sctp_auth_bytes, that is asoc->asoc_shared_key, plus drops the reference if there was a previous one. The secret, which where we eventually double drop the ref comes from sctp_auth_asoc_set_secret() with intitial refcount of 1, which also stays unchanged eventually in sctp_assoc_update(). This key is later being used for crypto layer to set the key for the hash in crypto_hash_setkey() from sctp_auth_calculate_hmac().
To close the loop: asoc->asoc_shared_key is freshly allocated secret material and independant of the sctp_shared_key management keeping track of only shared keys in endpoints and assocs. Hence, also commit 4184b2a79a76 ("net: sctp: fix memory leak in auth key management") is independant of this bug here since it concerns a different layer (though same structures being used eventually). asoc->asoc_shared_key is reference dropped correctly on assoc destruction in sctp_association_free() and when active keys are being replaced in sctp_auth_asoc_init_active_key(), it always has a refcount of 1. Hence, it's freed prematurely in sctp_assoc_update(). Simple fix is to remove that sctp_auth_key_put() from there which fixes these panics.
--- net/sctp/associola.c | 1 - 1 file changed, 1 deletion(-)
net/sctp/associola.c +0 -1
@@ -1260,7 +1260,6 @@ void sctp_assoc_update(struct sctp_association *asoc, asoc->peer.peer_hmacs = new->peer.peer_hmacs; new->peer.peer_hmacs =NULL ; -sctp_auth_key_put (asoc->asoc_shared_key);sctp_auth_asoc_init_active_key (asoc,GFP_ATOMIC ); }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 21/48 IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Shachar Raindel <[email protected]>
commit 8494057ab5e40df590ef6ef7d66324d3ae33356b upstream.
Properly verify that the resulting page aligned end address is larger than both the start address and the length of the memory area requested.
Both the start and length arguments for ib_umem_get are controlled by the user. A misbehaving user can provide values which will cause an integer overflow when calculating the page aligned end address.
This overflow can cause also miscalculation of the number of pages mapped, and additional logic issues.
Addresses: CVE-2014-8159
--- drivers/infiniband/core/umem.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/infiniband/core/umem.c +8 -0
@@ -92,6 +92,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,if (dmasync)dma_set_attr (DMA_ATTR_WRITE_BARRIER , &attrs); +/* +* If the combination of the addr and size requested for this memory +* region causes an integer overflow, return error. +*/ +if ((PAGE_ALIGN (addr + size) <= size) || + (PAGE_ALIGN (addr + size) <= addr)) +return ERR_PTR (-EINVAL ); +if (!can_do_mlock ())return ERR_PTR (-EPERM );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 22/48 net: llc: use correct size for sysctl timeout entries
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Sasha Levin <[email protected]>
commit 6b8d9117ccb4f81b1244aafa7bc70ef8fa45fc49 upstream.
The timeout entries are sizeof(int) rather than sizeof(long), which means that when they were getting read we'd also leak kernel memory to userspace along with the timeout values.
--- net/llc/sysctl_net_llc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/llc/sysctl_net_llc.c +4 -4
@@ -18,7 +18,7 @@ static struct ctl_table llc2_timeout_table[] = { .ctl_name = NET_LLC2_ACK_TIMEOUT, .procname = "ack", .data = &sysctl_llc2_ack_timeout, - .maxlen = sizeof(long), + .maxlen = sizeof(sysctl_llc2_ack_timeout), .mode = 0644, .proc_handler = proc_dointvec_jiffies, .strategy = sysctl_jiffies,
@@ -27,7 +27,7 @@ static struct ctl_table llc2_timeout_table[] = { .ctl_name = NET_LLC2_BUSY_TIMEOUT, .procname = "busy", .data = &sysctl_llc2_busy_timeout, - .maxlen = sizeof(long), + .maxlen = sizeof(sysctl_llc2_busy_timeout), .mode = 0644, .proc_handler = proc_dointvec_jiffies, .strategy = sysctl_jiffies,
@@ -36,7 +36,7 @@ static struct ctl_table llc2_timeout_table[] = { .ctl_name = NET_LLC2_P_TIMEOUT, .procname = "p", .data = &sysctl_llc2_p_timeout, - .maxlen = sizeof(long), + .maxlen = sizeof(sysctl_llc2_p_timeout), .mode = 0644, .proc_handler = proc_dointvec_jiffies, .strategy = sysctl_jiffies,
@@ -45,7 +45,7 @@ static struct ctl_table llc2_timeout_table[] = { .ctl_name = NET_LLC2_REJ_TIMEOUT, .procname = "rej", .data = &sysctl_llc2_rej_timeout, - .maxlen = sizeof(long), + .maxlen = sizeof(sysctl_llc2_rej_timeout), .mode = 0644, .proc_handler = proc_dointvec_jiffies, .strategy = sysctl_jiffies,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 23/48 net: rds: use correct size for max unacked packets and bytes
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Sasha Levin <[email protected]>
commit db27ebb111e9f69efece08e4cb6a34ff980f8896 upstream.
Max unacked packets/bytes is an int while sizeof(long) was used in the sysctl table.
This means that when they were getting read we'd also leak kernel memory to userspace along with the timeout values.
--- net/rds/sysctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/rds/sysctl.c +2 -2
@@ -74,7 +74,7 @@ static ctl_table rds_sysctl_rds_table[] = { .ctl_name = CTL_UNNUMBERED, .procname = "max_unacked_packets", .data = &rds_sysctl_max_unacked_packets, - .maxlen = sizeof(unsigned long), + .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, },
@@ -82,7 +82,7 @@ static ctl_table rds_sysctl_rds_table[] = { .ctl_name = CTL_UNNUMBERED, .procname = "max_unacked_bytes", .data = &rds_sysctl_max_unacked_bytes, - .maxlen = sizeof(unsigned long), + .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, },
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 24/48 ipv6: Dont reduce hop limit for an interface
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "D.S. Ljungmark" <[email protected]>
commit 6fd99094de2b83d1d4c8457f2c83483b2828e75a upstream.
A local route may have a lower hop_limit set than global routes do.
RFC 3756, Section 4.2.7, "Parameter Spoofing"
Quoted 8 lines
1. The attacker includes a Current Hop Limit of one or another small number which the attacker knows will cause legitimate packets to be dropped before they reach their destination.
As an example, one possible approach to mitigate this threat is to ignore very small hop limits. The nodes could implement a configurable minimum hop limit, and ignore attempts to set it below said limit.
--- net/ipv6/ndisc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
net/ipv6/ndisc.c +8 -1
@@ -1244,7 +1244,14 @@ static void ndisc_router_discovery(struct sk_buff *skb) rt->rt6i_expires = jiffies + (HZ * lifetime);if (ra_msg->icmph.icmp6_hop_limit) { - in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; +/* Only set hop_limit on the interface if it is higher than +* the current hop_limit. +*/ +if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) { + in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; + }else { +ND_PRINTK2 (KERN_WARNING "RA: Got route advertisement with lower hop_limit than current\n" ); + }if (rt) rt->u.dst.metrics[RTAX_HOPLIMIT -1 ] = ra_msg->icmph.icmp6_hop_limit; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 25/48 fs: take i_mutex during prepare_binprm for set[ug]id executables
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit 8b01fc86b9f425899f8a3a8fc1c47d73c2c20543 upstream.
This prevents a race between chown() and execve(), where chowning a setuid-user binary to root would momentarily make the binary setuid root.
This patch was mostly written by Linus Torvalds.
[bwh: Backported to 3.2:
- Drop the task_no_new_privs() and user namespace checks
- Open-code file_inode()
- s/READ_ONCE/ACCESS_ONCE/
- Adjust context]
--- fs/exec.c | 65 +++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 25 deletions(-)
fs/exec.c +40 -25
@@ -1181,6 +1181,45 @@ int check_unsafe_exec(struct linux_binprm *bprm)return res; } +static void bprm_fill_uid (struct linux_binprm *bprm) +{ +struct inode *inode; +unsigned int mode; +uid_t uid; +gid_t gid; + +/* clear any previous set[ug]id data from a previous binary */ + bprm->cred->euid =current_euid (); + bprm->cred->egid =current_egid (); + +if (bprm->file->f_path.mnt->mnt_flags &MNT_NOSUID ) +return ; + + inode = bprm->file->f_path.dentry->d_inode; + mode =ACCESS_ONCE (inode->i_mode); +if (!(mode & (S_ISUID |S_ISGID ))) +return ; + +/* Be careful if suid/sgid is set */ +mutex_lock (&inode->i_mutex); + +/* reload atomically mode/uid/gid now that lock held */ + mode = inode->i_mode; + uid = inode->i_uid; + gid = inode->i_gid; +mutex_unlock (&inode->i_mutex); + +if (mode &S_ISUID ) { + bprm->per_clear |=PER_CLEAR_ON_SETID ; + bprm->cred->euid = uid; + } + +if ((mode & (S_ISGID |S_IXGRP )) == (S_ISGID |S_IXGRP )) { + bprm->per_clear |=PER_CLEAR_ON_SETID ; + bprm->cred->egid = gid; + } +} +/* * Fill the binprm structure from the inode. * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
@@ -1189,36 +1228,12 @@ int check_unsafe_exec(struct linux_binprm *bprm)*/ int prepare_binprm (struct linux_binprm *bprm) { -umode_t mode; -struct inode * inode = bprm->file->f_path.dentry->d_inode;int retval; - mode = inode->i_mode;if (bprm->file->f_op ==NULL )return -EACCES ; -/* clear any previous set[ug]id data from a previous binary */ - bprm->cred->euid =current_euid (); - bprm->cred->egid =current_egid (); - -if (!(bprm->file->f_path.mnt->mnt_flags &MNT_NOSUID )) { -/* Set-uid? */ -if (mode &S_ISUID ) { - bprm->per_clear |=PER_CLEAR_ON_SETID ; - bprm->cred->euid = inode->i_uid; - } - -/* Set-gid? */ -/* -* If setgid is set but no group execute bit then this -* is a candidate for mandatory locking, not a setgid -* executable. -*/ -if ((mode & (S_ISGID |S_IXGRP )) == (S_ISGID |S_IXGRP )) { - bprm->per_clear |=PER_CLEAR_ON_SETID ; - bprm->cred->egid = inode->i_gid; - } - } +bprm_fill_uid (bprm);/* fill in binprm security blob */ retval =security_bprm_set_creds (bprm);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 26/48 net:socket: set msg_namelen to 0 if msg_name is passed as NULL in msghdr struct from userland.
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Ani Sinha <[email protected]>
commit 6a2a2b3ae0759843b22c929881cc184b00cc63ff upstream.
Linux manpage for recvmsg and sendmsg calls does not explicitly mention setting msg_namelen to 0 when msg_name passed set as NULL. When developers don't set msg_namelen member in msghdr, it might contain garbage value which will fail the validation check and sendmsg and recvmsg calls from kernel will return EINVAL. This will break old binaries and any code for which there is no access to source code.
To fix this, we set msg_namelen to 0 when msg_name is passed as NULL from userland.
--- net/socket.c | 3 +++ 1 file changed, 3 insertions(+)
net/socket.c +3 -0
@@ -1872,6 +1872,9 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,if (copy_from_user (kmsg, umsg,sizeof (struct msghdr )))return -EFAULT ; +if (kmsg->msg_name ==NULL ) + kmsg->msg_namelen =0 ; +if (kmsg->msg_namelen <0 )return -EINVAL ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 26/48] net:socket: set msg_namelen to 0 if msg_name is passed as NULL in msghdr struct from userland.
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Ani Sinha <[email protected]>
Quoted 7 lines
commit
6a2a2b3ae0759843b22c929881cc184b00cc63ffupstream.Linux manpage for recvmsg and sendmsg calls does not explicitly mention setting
msg_namelento 0 whenmsg_namepassed set as NULL. When developers don't setmsg_namelenmember in msghdr, it might contain garbage value which will fail the validation check and sendmsg and recvmsg calls from kernel will return EINVAL. This will break old binaries and any code for which there is no access to source code.
To fix this, we setmsg_namelento 0 whenmsg_nameis passed as NULL from userland.
[...]
I think you'll also want this related fix:
commit 91edd096e224941131f896b86838b1e59553696a
Author: Catalin Marinas <[email protected]> Date: Fri Mar 20 16:48:13 2015 +0000
net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour
Ben.
Signature · 2 lines
Ben Hutchings It is impossible to make anything foolproof because fools are so ingenious.
Re: [ 26/48] net:socket: set msg_namelen to 0 if msg_name is passed as NULL in msghdr struct from userland.
Hi Ben,
Quoted 7 lines · Ben Hutchings
I think you'll also want this related fix:
commit
91edd096e224941131f896b86838b1e59553696aAuthor: Catalin Marinas <[email protected]> Date: Fri Mar 20 16:48:13 2015 +0000net: compat: Update
get_compat_msghdr()to matchcopy_msghdr_from_user()behaviour
Ah good catch, I missed it. Now merged and tested. BTW, I've added your s-o-b on the two other patches.
Thanks!
Willy
PATCH 27/48 ppp: deflate: never return len larger than output buffer
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit e2a4800e75780ccf4e6c2487f82b688ba736eb18 ]
When we've run out of space in the output buffer to store more data, we will call zlib_deflate with a NULL output buffer until we've consumed remaining input.
When this happens, olen contains the size the output buffer would have consumed iff we'd have had enough room.
This can later cause skb_over_panic when ppp_generic skb_put()s the returned length.
--- drivers/net/ppp_deflate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ppp_deflate.c +1 -1
@@ -269,7 +269,7 @@ static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,/* * See if we managed to reduce the size of the packet. */ -if (olen < isize) { +if (olen < isize && olen <= osize) { state->stats.comp_bytes += olen; state->stats.comp_packets++; }else {
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 29/48 net: reject creation of netdev names with colons
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Thode <[email protected]>
[ Upstream commit a4176a9391868bfa87705bcd2e3b49e9b9dd2996 ]
colons are used as a separator in netdev device lookup in dev_ioctl.c
Specific functions are SIOCGIFTXQLEN SIOCETHTOOL SIOCSIFNAME
--- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/core/dev.c +1 -1
@@ -779,7 +779,7 @@ int dev_valid_name(const char *name)return 0 ;while (*name) { -if (*name =='/' ||isspace (*name)) +if (*name =='/' || *name ==':' ||isspace (*name))return 0 ; name++; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 30/48 ipv4: Dont use ufo handling on later transformed packets
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Steffen Klassert <[email protected]>
We might call ip_ufo_append_data() for packets that will be IPsec transformed later. This function should be used just for real udp packets. So we check for rt->dst.header_len which is only nonzero on IPsec handling and call ip_ufo_append_data() just if rt->dst.header_len is zero.
--- net/ipv4/ip_output.c | 1 + 1 file changed, 1 insertion(+)
net/ipv4/ip_output.c +1 -0
@@ -878,6 +878,7 @@ int ip_append_data(struct sock *sk,if (((length > mtu) || (skb &&skb_has_frags (skb))) && (sk->sk_protocol ==IPPROTO_UDP ) && (rt->u.dst.dev->features &NETIF_F_UFO )) { + (rt->u.dst.dev->features & NETIF_F_UFO) && !rt->u.dst.header_len) { err =ip_ufo_append_data (sk, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, mtu, flags);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 31/48 udp: only allow UFO for packets from SOCK_DGRAM sockets
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: =?latin1?q?Michal=20Kube=C4=8Dek?= <[email protected]>
[ Upstream commit acf8dd0a9d0b9e4cdb597c2f74802f79c699e802 ]
If an over-MTU UDP datagram is sent through a SOCK_RAW socket to a UFO-capable device, ip_ufo_append_data() sets skb->ip_summed to CHECKSUM_PARTIAL unconditionally as all GSO code assumes transport layer checksum is to be computed on segmentation. However, in this case, skb->csum_start and skb->csum_offset are never set as raw socket transmit path bypasses udp_send_skb() where they are usually set. As a result, driver may access invalid memory when trying to calculate the checksum and store the result (as observed in virtio_net driver).
Moreover, the very idea of modifying the userspace provided UDP header is IMHO against raw socket semantics (I wasn't able to find a document clearly stating this or the opposite, though). And while allowing CHECKSUM_NONE in the UFO case would be more efficient, it would be a bit too intrusive change just to handle a corner case like this. Therefore disallowing UFO for packets from SOCK_DGRAM seems to be the best option.
--- net/ipv4/ip_output.c | 4 ++-- net/ipv6/ip6_output.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-)
net/ipv4/ip_output.c +2 -2
@@ -877,8 +877,8 @@ int ip_append_data(struct sock *sk, inet->cork.length += length;if (((length > mtu) || (skb &&skb_has_frags (skb))) && (sk->sk_protocol ==IPPROTO_UDP ) && - (rt->u.dst.dev->features &NETIF_F_UFO )) { - (rt->u.dst.dev->features & NETIF_F_UFO) && !rt->u.dst.header_len) { + (rt->u.dst.dev->features &NETIF_F_UFO ) && !rt->u.dst.header_len && + (sk->sk_type ==SOCK_DGRAM )) { err =ip_ufo_append_data (sk, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, mtu, flags);
net/ipv6/ip6_output.c +2 -1
@@ -1259,7 +1259,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,if (((length > mtu) || (skb &&skb_has_frags (skb))) && (sk->sk_protocol ==IPPROTO_UDP ) && - (rt->u.dst.dev->features &NETIF_F_UFO )) { + (rt->u.dst.dev->features &NETIF_F_UFO ) && + (sk->sk_type ==SOCK_DGRAM )) { err =ip6_ufo_append_data (sk, getfrag, from, length, hh_len, fragheaderlen, transhdrlen, mtu, flags, rt);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 32/48 net: avoid to hang up on sending due to sysctl configuration overflow.
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "[email protected]" <[email protected]>
commit cdda88912d62f9603d27433338a18be83ef23ac1 upstream.
I found if we write a larger than 4GB value to some sysctl
variables, the sending syscall will hang up forever, because these variables are 32 bits, such large values make them overflow to 0 or negative.
This patch try to fix overflow or prevent from zero value setup
of below sysctl variables:
net.core.wmem_default
net.core.rmem_default
net.core.rmem_max
net.core.wmem_max
net.ipv4.udp_rmem_min
net.ipv4.udp_wmem_min
net.ipv4.tcp_wmem
net.ipv4.tcp_rmem
[bwh: Backported to 3.2:
- Adjust context
- Delete now-unused 'zero' variable]
--- net/core/sysctl_net_core.c | 18 ++++++++++++++---- net/ipv4/sysctl_net_ipv4.c | 13 +++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-)
net/core/sysctl_net_core.c +14 -4
@@ -17,6 +17,8 @@static int zero =0 ;static int ushort_max =65535 ; +static int one =1 ; + static struct ctl_table net_core_table[] = { #ifdef CONFIG_NET {
@@ -25,7 +27,9 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_wmem_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, + .extra1 = &one, }, { .ctl_name = NET_CORE_RMEM_MAX,
@@ -33,7 +37,9 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_rmem_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, + .extra1 = &one, }, { .ctl_name = NET_CORE_WMEM_DEFAULT,
@@ -41,7 +47,9 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_wmem_default, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, + .extra1 = &one, }, { .ctl_name = NET_CORE_RMEM_DEFAULT,
@@ -49,7 +57,9 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_rmem_default, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, + .extra1 = &one, }, { .ctl_name = NET_CORE_DEV_WEIGHT,
net/ipv4/sysctl_net_ipv4.c +9 -4
@@ -22,6 +22,7 @@#include <net/inet_frag.h> static int zero; +static int one =1 ;static int tcp_retr1_max =255 ;static int tcp_syn_retries_min =1 ;static int tcp_syn_retries_max =MAX_TCP_SYNCNT ;
@@ -521,7 +522,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_wmem, .maxlen = sizeof(sysctl_tcp_wmem), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, + .extra1 = &one, }, { .ctl_name = NET_TCP_RMEM,
@@ -529,7 +532,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_rmem, .maxlen = sizeof(sysctl_tcp_rmem), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, + .extra1 = &one, }, { .ctl_name = NET_TCP_APP_WIN,
@@ -735,7 +740,7 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, - .extra1 = &zero + .extra1 = &one }, { .ctl_name = CTL_UNNUMBERED,
@@ -745,7 +750,7 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, - .extra1 = &zero + .extra1 = &one }, { .ctl_name = 0 } };
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 33/48 net: sysctl_net_core: check SNDBUF and RCVBUF for min length
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Kodanev <[email protected]>
[ Upstream commit b1cb59cf2efe7971d3d72a7b963d09a512d994c9 ]
sysctl has sysctl.net.core.rmem_*/wmem_* parameters which can be set to incorrect values. Given that 'struct sk_buff' allocates from rcvbuf, incorrectly set buffer length could result to memory allocation failures. For example, set them as follows:
# sysctl net.core.rmem_default=64
net.core.wmem_default = 64
# sysctl net.core.wmem_default=64
net.core.wmem_default = 64
# ping localhost -s 1024 -i 0 > /dev/nullThis could result to the following failure:
skbuff: skb_over_panic: text:ffffffff81628db4 len:-32 put:-32 head:ffff88003a1cc200 data:ffff88003a1cc200 tail:0xffffffe0 end:0xc0 dev:<NULL> kernel BUG at net/core/skbuff.c:102!
invalid opcode: 0000 [#1] SMP
...
task: ffff88003b7f5550 ti: ffff88003ae88000 task.ti: ffff88003ae88000
RIP: 0010:[<ffffffff8155fbd1>] [<ffffffff8155fbd1>] skb_put+0xa1/0xb0
RSP: 0018:ffff88003ae8bc68 EFLAGS: 00010296
RAX: 000000000000008d RBX: 00000000ffffffe0 RCX: 0000000000000000
RDX: ffff88003fdcf598 RSI: ffff88003fdcd9c8 RDI: ffff88003fdcd9c8
RBP: ffff88003ae8bc88 R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000001 R11: 00000000000002b2 R12: 0000000000000000
R13: 0000000000000000 R14: ffff88003d3f7300 R15: ffff88000012a900
FS: 00007fa0e2b4a840(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000d0f7e0 CR3: 000000003b8fb000 CR4: 00000000000006f0
Stack:
ffff88003a1cc200 00000000ffffffe0 00000000000000c0 ffffffff818cab1d
ffff88003ae8bd68 ffffffff81628db4 ffff88003ae8bd48 ffff88003b7f5550
ffff880031a09408 ffff88003b7f5550 ffff88000012aa48 ffff88000012ab00
Call Trace:
[<ffffffff81628db4>] unix_stream_sendmsg+0x2c4/0x470
[<ffffffff81556f56>] sock_write_iter+0x146/0x160
[<ffffffff811d9612>] new_sync_write+0x92/0xd0
[<ffffffff811d9cd6>] vfs_write+0xd6/0x180
[<ffffffff811da499>] SyS_write+0x59/0xd0
[<ffffffff81651532>] system_call_fastpath+0x12/0x17
Code: 00 00 48 89 44 24 10 8b 87 c8 00 00 00 48 89 44 24 08 48 8b 87 d8 00
00 00 48 c7 c7 30 db 91 81 48 89 04 24 31 c0 e8 4f a8 0e 00 <0f> 0b
eb fe 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 48 83
RIP [<ffffffff8155fbd1>] skb_put+0xa1/0xb0
RSP <ffff88003ae8bc68>
Kernel panic - not syncing: Fatal exceptionMoreover, the possible minimum is 1, so we can get another kernel panic:
...
BUG: unable to handle kernel paging request at ffff88013caee5c0 IP: [<ffffffff815604cf>] __alloc_skb+0x12f/0x1f0
...
--- net/core/sysctl_net_core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
net/core/sysctl_net_core.c +6 -5
@@ -17,7 +17,8 @@static int zero =0 ;static int ushort_max =65535 ; -static int one =1 ; +static int min_sndbuf =SOCK_MIN_SNDBUF ; +static int min_rcvbuf =SOCK_MIN_RCVBUF ; static struct ctl_table net_core_table[] = {#ifdef CONFIG_NET
@@ -29,7 +30,7 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, - .extra1 = &one, + .extra1 = &min_sndbuf, }, { .ctl_name = NET_CORE_RMEM_MAX,
@@ -39,7 +40,7 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, - .extra1 = &one, + .extra1 = &min_rcvbuf, }, { .ctl_name = NET_CORE_WMEM_DEFAULT,
@@ -49,7 +50,7 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, - .extra1 = &one, + .extra1 = &min_sndbuf, }, { .ctl_name = NET_CORE_RMEM_DEFAULT,
@@ -59,7 +60,7 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .strategy = sysctl_intvec, - .extra1 = &one, + .extra1 = &min_rcvbuf, }, { .ctl_name = NET_CORE_DEV_WEIGHT,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 34/48 rds: avoid potential stack overflow
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Arnd Bergmann <[email protected]>
[ Upstream commit f862e07cf95d5b62a5fc5e981dd7d0dbaf33a501 ]
The rds_iw_update_cm_id function stores a large 'struct rds_sock' object on the stack in order to pass a pair of addresses. This happens to just fit withint the 1024 byte stack size warning limit on x86, but just exceed that limit on ARM, which gives us this warning:
net/rds/iw_rdma.c:200:1: warning: the frame size of 1056 bytes is larger than 1024 bytes [-Wframe-larger-than=]
As the use of this large variable is basically bogus, we can rearrange the code to not do that. Instead of passing an rds socket into rds_iw_get_device, we now just pass the two addresses that we have available in rds_iw_update_cm_id, and we change rds_iw_get_mr accordingly, to create two address structures on the stack there.
--- net/rds/iw_rdma.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-)
net/rds/iw_rdma.c +22 -18
@@ -86,7 +86,9 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool, struct list_head *kill_list);static void rds_iw_destroy_fastreg (struct rds_iw_mr_pool *pool,struct rds_iw_mr *ibmr); -static int rds_iw_get_device (struct rds_sock *rs,struct rds_iw_device **rds_iwdev,struct rdma_cm_id **cm_id) +static int rds_iw_get_device (struct sockaddr_in *src,struct sockaddr_in *dst, +struct rds_iw_device **rds_iwdev, +struct rdma_cm_id **cm_id) {struct rds_iw_device *iwdev;struct rds_iw_cm_id *i_cm_id;
@@ -110,15 +112,15 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd src_addr->sin_port, dst_addr->sin_addr.s_addr, dst_addr->sin_port, - rs->rs_bound_addr, - rs->rs_bound_port, - rs->rs_conn_addr, - rs->rs_conn_port); + src->sin_addr.s_addr, + src->sin_port, + dst->sin_addr.s_addr, + dst->sin_port);#ifdef WORKING_TUPLE_DETECTION -if (src_addr->sin_addr.s_addr == rs->rs_bound_addr && - src_addr->sin_port == rs->rs_bound_port && - dst_addr->sin_addr.s_addr == rs->rs_conn_addr && - dst_addr->sin_port == rs->rs_conn_port) { +if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr && + src_addr->sin_port == src->sin_port && + dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr && + dst_addr->sin_port == dst->sin_port) {#else /* FIXME - needs to compare the local and remote * ipaddr/port tuple, but the ipaddr is the only
@@ -126,7 +128,7 @@ static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwd* zero'ed. It doesn't appear to be properly populated * during connection setup... */ -if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) { +if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {#endif spin_unlock_irq (&iwdev->spinlock); *rds_iwdev = iwdev;
@@ -177,19 +179,13 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i {struct sockaddr_in *src_addr, *dst_addr;struct rds_iw_device *rds_iwdev_old; -struct rds_sock rs;struct rdma_cm_id *pcm_id;int rc; src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr; dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr; - rs.rs_bound_addr = src_addr->sin_addr.s_addr; - rs.rs_bound_port = src_addr->sin_port; - rs.rs_conn_addr = dst_addr->sin_addr.s_addr; - rs.rs_conn_port = dst_addr->sin_port; - - rc =rds_iw_get_device (&rs, &rds_iwdev_old, &pcm_id); + rc =rds_iw_get_device (src_addr, dst_addr, &rds_iwdev_old, &pcm_id);if (rc)rds_iw_remove_cm_id (rds_iwdev, cm_id);
@@ -609,9 +605,17 @@ void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,struct rds_iw_device *rds_iwdev;struct rds_iw_mr *ibmr =NULL ;struct rdma_cm_id *cm_id; +struct sockaddr_in src = { + .sin_addr.s_addr = rs->rs_bound_addr, + .sin_port = rs->rs_bound_port, + }; +struct sockaddr_in dst = { + .sin_addr.s_addr = rs->rs_conn_addr, + .sin_port = rs->rs_conn_port, + };int ret; - ret =rds_iw_get_device (rs, &rds_iwdev, &cm_id); + ret =rds_iw_get_device (&src, &dst, &rds_iwdev, &cm_id);if (ret || !cm_id) { ret = -ENODEV ; goto out;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 35/48 rxrpc: bogus MSG_PEEK test in rxrpc_recvmsg()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <[email protected]>
[ Upstream commit 7d985ed1dca5c90535d67ce92ef6ca520302340a ]
[I would really like an ACK on that one from dhowells; it appears to be quite straightforward, but...]
MSG_PEEK isn't passed to ->recvmsg() via msg->msg_flags; as the matter of fact, neither the kernel users of rxrpc, nor the syscalls ever set that bit in there. It gets passed via flags; in fact, another such check in the same function is done correctly - as flags & MSG_PEEK.
It had been that way (effectively disabled) for 8 years, though, so the patch needs beating up - that case had never been tested. If it is correct, it's -stable fodder.
--- net/rxrpc/ar-recvmsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/rxrpc/ar-recvmsg.c +1 -1
@@ -86,7 +86,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,if (!skb) {/* nothing remains on the queue */ if (copied && - (msg->msg_flags &MSG_PEEK || timeo ==0 )) + (flags &MSG_PEEK || timeo ==0 )) goto out;/* wait for a message to turn up */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 36/48 tcp: make connect() mem charging friendly
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 355a901e6cf1b2b763ec85caa2a9f04fbcc4ab4a ]
While working on sk_forward_alloc problems reported by Denys Fedoryshchenko, we found that tcp connect() (and fastopen) do not call sk_wmem_schedule() for SYN packet (and/or SYN/DATA packet), so sk_forward_alloc is negative while connect is in progress.
We can fix this by calling regular sk_stream_alloc_skb() both for the SYN packet (in tcp_connect()) and the syn_data packet in tcp_send_syn_data()
Then, tcp_send_syn_data() can avoid copying syn_data as we simply can manipulate syn_data->cb[] to remove SYN flag (and increment seq)
Instead of open coding memcpy_fromiovecend(), simply use this helper.
This leaves in socket write queue clean fast clone skbs.
This was tested against our fastopen packetdrill tests.
[bwh: Backported to 3.2:
- Drop the Fast Open changes
- Adjust context]
--- net/ipv4/tcp_output.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
net/ipv4/tcp_output.c +2 -5
@@ -2378,13 +2378,10 @@ int tcp_connect(struct sock *sk)tcp_connect_init (sk); - buff =alloc_skb_fclone (MAX_TCP_HEADER +15 , sk->sk_allocation); -if (unlikely (buff ==NULL )) + buff =sk_stream_alloc_skb (sk,0 , sk->sk_allocation); +if (unlikely (!buff))return -ENOBUFS ; -/* Reserve space for headers. */ -skb_reserve (buff,MAX_TCP_HEADER ); - tp->snd_nxt = tp->write_seq;tcp_init_nondata_skb (buff, tp->write_seq++,TCPCB_FLAG_SYN );TCP_ECN_send_syn (sk, buff);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 37/48 ip_forward: Drop frames with attached skb->sk
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: =?latin1?q?Sebastian=20P=F6hn?= <[email protected]>
[ Upstream commit 2ab957492d13bb819400ac29ae55911d50a82a13 ]
Initial discussion was:
[FYI] xfrm: Don't lookup sk_policy for timewait sockets
Forwarded frames should not have a socket attached. Especially tw sockets will lead to panics later-on in the stack.
This was observed with TPROXY assigning a tw socket and broken policy routing (misconfigured). As a result frame enters forwarding path instead of input. We cannot solve this in TPROXY as it cannot know that policy routing is broken.
v2:
Remove useless comment
--- net/ipv4/ip_forward.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv4/ip_forward.c +3 -0
@@ -56,6 +56,9 @@ int ip_forward(struct sk_buff *skb)struct rtable *rt;/* Route we use */ struct ip_options * opt = &(IPCB (skb)->opt); +if (unlikely (skb->sk)) + goto drop; +if (skb_warn_if_lro (skb)) goto drop;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 38/48 tcp: avoid looping in tcp_send_fin()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 845704a535e9b3c76448f52af1b70e4422ea03fd ]
Presence of an unbound loop in tcp_send_fin() had always been hard to explain when analyzing crash dumps involving gigantic dying processes with millions of sockets.
Lets try a different strategy :
In case of memory pressure, try to add the FIN flag to last packet in write queue, even if packet was already sent. TCP stack will be able to deliver this FIN after a timeout event. Note that this FIN being delivered by a retransmit, it also carries a Push flag given our current implementation.
By checking sk_under_memory_pressure(), we anticipate that cooking many FIN packets might deplete tcp memory.
In the case we could not allocate a packet, even with __GFP_WAIT allocation, then not sending a FIN seems quite reasonable if it allows to get rid of this socket, free memory, and not block the process from eventually doing other useful work.
[bwh: Backported to 3.2:
- Drop inapplicable change to sk_forced_wmem_schedule()
- s/sk_under_memory_pressure(sk)/tcp_memory_pressure/]
--- net/ipv4/tcp_output.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-)
net/ipv4/tcp_output.c +26 -19
@@ -2121,33 +2121,40 @@ begin_fwd: } } -/* Send a fin. The caller locks the socket for us. This cannot be -* allowed to fail queueing a FIN frame under any circumstances. +/* Send a FIN. The caller locks the socket for us. +* We should try to send a FIN packet really hard, but eventually give up. */ void tcp_send_fin (struct sock *sk) { +struct sk_buff *skb, *tskb =tcp_write_queue_tail (sk);struct tcp_sock *tp =tcp_sk (sk); -struct sk_buff *skb =tcp_write_queue_tail (sk); -int mss_now; -/* Optimization, tack on the FIN if we have a queue of -* unsent frames. But be careful about outgoing SACKS -* and IP options. +/* Optimization, tack on the FIN if we have one skb in write queue and +* this skb was not yet sent, or we are under memory pressure. +* Note: in the latter case, FIN packet will be sent after a timeout, +* as TCP stack thinks it has already been transmitted. */ - mss_now =tcp_current_mss (sk); - -if (tcp_send_head (sk) !=NULL ) { +if (tskb && (tcp_send_head (sk) || tcp_memory_pressure)) { +coalesce:TCP_SKB_CB (skb)->flags |=TCPCB_FLAG_FIN ; -TCP_SKB_CB (skb)->end_seq++; +TCP_SKB_CB (tskb)->end_seq++; tp->write_seq++; +if (!tcp_send_head (sk)) { +/* This means tskb was already sent. +* Pretend we included the FIN on previous transmit. +* We need to set tp->snd_nxt to the value it would have +* if FIN had been sent. This is because retransmit path +* does not change tp->snd_nxt. +*/ + tp->snd_nxt++; +return ; + } }else { -/* Socket is locked, keep trying until memory is available. */ -for (;;) { - skb =alloc_skb_fclone (MAX_TCP_HEADER , - sk->sk_allocation); -if (skb) -break ; -yield (); + skb =alloc_skb_fclone (MAX_TCP_HEADER , sk->sk_allocation); +if (unlikely (!skb)) { +if (tskb) + goto coalesce; +return ; }/* Reserve space for headers and prepare control bits. */
@@ -2157,7 +2164,7 @@ void tcp_send_fin(struct sock *sk) TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);tcp_queue_skb (sk, skb); } -__tcp_push_pending_frames (sk, mss_now,TCP_NAGLE_OFF ); +__tcp_push_pending_frames (sk,tcp_current_mss (sk),TCP_NAGLE_OFF ); }/* We get here when a process closes a file descriptor (either due to
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 39/48 spi: spidev: fix possible arithmetic overflow for multi-transfer message
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Ian Abbott <[email protected]>
commit f20fbaad7620af2df36a1f9d1c9ecf48ead5b747 upstream.
spidev_message() sums the lengths of the individual SPI transfers to determine the overall SPI message length. It restricts the total length, returning an error if too long, but it does not check for arithmetic overflow. For example, if the SPI message consisted of two transfers and the first has a length of 10 and the second has a length of (__u32)(-1), the total length would be seen as 9, even though the second transfer is actually very long. If the second transfer specifies a null rx_buf and a non-null tx_buf, the copy_from_user() could overrun the spidev's pre-allocated tx buffer before it reaches an invalid user memory address. Fix it by checking that neither the total nor the individual transfer lengths exceed the maximum allowed value.
Thanks to Dan Carpenter for reporting the potential integer overflow.
[Ian Abbott: Note: original commit compares the lengths to INT_MAX
instead of bufsiz due to changes in earlier commits.]
--- drivers/spi/spidev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/spi/spidev.c +4 -1
@@ -241,7 +241,10 @@ static int spidev_message(struct spidev_data *spidev, k_tmp->len = u_tmp->len; total += k_tmp->len; -if (total > bufsiz) { +/* Check total length of transfers. Also check each +* transfer length to avoid arithmetic overflow. +*/ +if (total > bufsiz || k_tmp->len > bufsiz) { status = -EMSGSIZE ; goto done; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 40/48 IB/core: Avoid leakage from kernel to user space
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Eli Cohen <[email protected]>
commit 377b513485fd885dea1083a9a5430df65b35e048 upstream.
Clear the reserved field of struct ib_uverbs_async_event_desc which is copied to user space.
--- drivers/infiniband/core/uverbs_main.c | 1 + 1 file changed, 1 insertion(+)
drivers/infiniband/core/uverbs_main.c +1 -0
@@ -433,6 +433,7 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, entry->desc.async.element = element; entry->desc.async.event_type = event; + entry->desc.async.reserved =0 ; entry->counter = counter;list_add_tail (&entry->list, &file->async_file->event_list);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 41/48 ipvs: uninitialized data with IP_VS_IPV6
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
commit 3b05ac3824ed9648c0d9c02d51d9b54e4e7e874f upstream.
The app_tcp_pkt_out() function expects "*diff" to be set and ends up using uninitialized data if CONFIG_IP_VS_IPV6 is turned on.
The same issue is there in app_tcp_pkt_in(). Thanks to Julian Anastasov for noticing that.
--- net/netfilter/ipvs/ip_vs_ftp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/netfilter/ipvs/ip_vs_ftp.c +5 -5
@@ -150,6 +150,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,unsigned buf_len;int ret; + *diff =0 ; +#ifdef CONFIG_IP_VS_IPV6 /* This application helper doesn't work with IPv6 yet, * so turn this into a no-op for IPv6 packets
@@ -158,8 +160,6 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,return 1 ;#endif - *diff =0 ; -/* Only useful for established sessions */ if (cp->state !=IP_VS_TCP_S_ESTABLISHED )return 1 ;
@@ -257,6 +257,9 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,__be16 port;struct ip_vs_conn *n_cp; +/* no diff required for incoming packets */ + *diff =0 ; +#ifdef CONFIG_IP_VS_IPV6 /* This application helper doesn't work with IPv6 yet, * so turn this into a no-op for IPv6 packets
@@ -265,9 +268,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,return 1 ;#endif -/* no diff required for incoming packets */ - *diff =0 ; -/* Only useful for established sessions */ if (cp->state !=IP_VS_TCP_S_ESTABLISHED )return 1 ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 42/48 ipv4: fix nexthop attlen check in fib_nh_match
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Pirko <[email protected]>
commit f76936d07c4eeb36d8dbb64ebd30ab46ff85d9f7 upstream.
fib_nh_match does not match nexthops correctly. Example:
ip route add 172.16.10/24 nexthop via 192.168.122.12 dev eth0 \
nexthop via 192.168.122.13 dev eth0
ip route del 172.16.10/24 nexthop via 192.168.122.14 dev eth0 \
nexthop via 192.168.122.15 dev eth0Del command is successful and route is removed. After this patch applied, the route is correctly matched and result is:
RTNETLINK answers: No such process
Please consider this for stable trees as well.
--- net/ipv4/fib_semantics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/fib_semantics.c +1 -1
@@ -453,7 +453,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)return 1 ; attrlen =rtnh_attrlen (rtnh); -if (attrlen <0 ) { +if (attrlen >0 ) {struct nlattr *nla, *attrs =rtnh_attrs (rtnh); nla =nla_find (attrs, attrlen,RTA_GATEWAY );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 43/48 pagemap: do not leak physical addresses to non-privileged userspace
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "Kirill A. Shutemov" <[email protected]>
commit ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce upstream.
As pointed by recent post[1] on exploiting DRAM physical imperfection, /proc/PID/pagemap exposes sensitive information which can be used to do attacks.
This disallows anybody without CAP_SYS_ADMIN to read the pagemap.
[1] http://googleprojectzero.blogspot.com/2015/03/exploiting-dram-rowhammer-bug-to-gain.html
[ Eventually we might want to do anything more finegrained, but for now
this is the simple model. - Linus ]
--- fs/proc/task_mmu.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
fs/proc/task_mmu.c +10 -0
@@ -773,9 +773,19 @@ out: return ret; } +static int pagemap_open (struct inode *inode,struct file *file) +{ +/* do not disclose physical addresses to unprivileged +userspace (closes a rowhammer attack vector) */ +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; +return 0 ; +} +const struct file_operations proc_pagemap_operations = { .llseek = mem_lseek,/* borrow this */ .read = pagemap_read, + .open = pagemap_open, };#endif /* CONFIG_PROC_PAGE_MONITOR */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 44/48 lockd: Try to reconnect if statd has moved
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Coddington <[email protected]>
commit 173b3afceebe76fa2205b2c8808682d5b541fe3c upstream.
If rpc.statd is restarted, upcalls to monitor hosts can fail with ECONNREFUSED. In that case force a lookup of statd's new port and retry the upcall.
--- fs/lockd/mon.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/lockd/mon.c +6 -0
@@ -109,6 +109,12 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) msg.rpc_proc = &clnt->cl_procinfo[proc]; status =rpc_call_sync (clnt, &msg,0 ); +if (status == -ECONNREFUSED ) { +dprintk ("lockd: NSM upcall RPC failed, status=%d, forcing rebind\n" , + status); +rpc_force_rebind (clnt); + status =rpc_call_sync (clnt, &msg,0 ); + }if (status <0 )dprintk ("lockd: NSM upcall RPC failed, status=%d\n" , status);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 45/48 scsi: Fix error handling in SCSI_IOCTL_SEND_COMMAND
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit 84ce0f0e94ac97217398b3b69c21c7a62ebeed05 upstream.
When sg_scsi_ioctl() fails to prepare request to submit in blk_rq_map_kern() we jump to a label where we just end up copying (luckily zeroed-out) kernel buffer to userspace instead of reporting error. Fix the problem by jumping to the right label.
CC: Jens Axboe <[email protected]>
CC: [email protected]
Coverity-id: 1226871
Fixed up the, now unused, out label.
--- block/scsi_ioctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
block/scsi_ioctl.c +1 -2
@@ -503,7 +503,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,if (bytes &&blk_rq_map_kern (q, rq, buffer, bytes, __GFP_WAIT)) { err =DRIVER_ERROR <<24 ; - goto out; + goto error; }memset (sense,0 ,sizeof (sense));
@@ -513,7 +513,6 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,blk_execute_rq (q, disk, rq,0 ); -out: err = rq->errors &0xff ;/* only 8 bit SCSI status */ if (err) {if (rq->sense_len && rq->sense) {
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 46/48 posix-timers: Fix stack info leak in timer_create()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Krause <[email protected]>
commit 6891c4509c792209c44ced55a60f13954cb50ef4 upstream.
If userland creates a timer without specifying a sigevent info, we'll create one ourself, using a stack local variable. Particularly will we use the timer ID as sival_int. But as sigev_value is a union containing a pointer and an int, that assignment will only partially initialize sigev_value on systems where the size of a pointer is bigger than the size of an int. On such systems we'll copy the uninitialized stack bytes from the timer_create() call to userland when the timer actually fires and we're going to deliver the signal.
Initialize sigev_value with 0 to plug the stack info leak.
Found in the PaX patch, written by the PaX Team.
--- kernel/posix-timers.c | 1 + 1 file changed, 1 insertion(+)
kernel/posix-timers.c +1 -0
@@ -578,6 +578,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, goto out; } }else { +memset (&event.sigev_value,0 ,sizeof (event.sigev_value)); event.sigev_notify =SIGEV_SIGNAL ; event.sigev_signo =SIGALRM ; event.sigev_value.sival_int = new_timer->it_id;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 47/48 hfsplus: fix B-tree corruption after insertion at position 0
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Sergei Antonov <[email protected]>
commit 98cf21c61a7f5419d82f847c4d77bf6e96a76f5f upstream.
Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). In this case a hfs_brec_update_parent() is called to update the parent index node (if exists) and it is passed hfs_find_data with a search_key containing a newly inserted key instead of the key to be updated. This results in an inconsistent index node. The bug reproduces on my machine after an extents overflow record for the catalog file (CNID=4) is inserted into the extents overflow B-tree. Because of a low (reserved) value of CNID=4, it has to become the first record in the first leaf node.
The resulting first leaf node is correct:
----------------------------------------------------
| key0.CNID=4 | key1.CNID=123 | key2.CNID=456, ... |
----------------------------------------------------
But the parent index key0 still contains the previous key CNID=123:
-----------------------
| key0.CNID=123 | ... |
-----------------------
A change in hfs_brec_insert() makes hfs_brec_update_parent() work correctly by preventing it from getting fd->record=-1 value from __hfs_brec_find().
Along the way, I removed duplicate code with unification of the if condition. The resulting code is equivalent to the original code because node is never 0.
Also hfs_brec_update_parent() will now return an error after getting a negative fd->record value. However, the return value of hfs_brec_update_parent() is not checked anywhere in the file and I'm leaving it unchanged by this patch. brec.c lacks error checking after some other calls too, but this issue is of less importance than the one being fixed by this patch.
--- fs/hfsplus/brec.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
fs/hfsplus/brec.c +11 -9
@@ -119,13 +119,16 @@ skip:hfs_bnode_write (node, entry, data_off + key_len, entry_len);hfs_bnode_dump (node); -if (new_node) { -/* update parent key if we inserted a key -* at the start of the first node -*/ -if (!rec && new_node != node) -hfs_brec_update_parent (fd); +/* +* update parent key if we inserted a key +* at the start of the node and it is not the new node +*/ +if (!rec && new_node != node) { +hfs_bnode_read_key (node, fd->search_key, data_off + size); +hfs_brec_update_parent (fd); + } +if (new_node) {hfs_bnode_put (fd->bnode);if (!new_node->parent) {hfs_btree_inc_height (tree);
@@ -154,9 +157,6 @@ skip: goto again; } -if (!rec) -hfs_brec_update_parent (fd); -return 0 ; }
@@ -341,6 +341,8 @@ again:if (IS_ERR (parent))return PTR_ERR (parent);__hfs_brec_find (parent, fd); +if (fd->record <0 ) +return -ENOENT ;hfs_bnode_dump (parent); rec = fd->record;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 48/48 sound/oss: fix deadlock in sequencer_ioctl(SNDCTL_SEQ_OUTOFBAND)
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Khoroshilov <[email protected]>
A deadlock can be initiated by userspace via ioctl(SNDCTL_SEQ_OUTOFBAND) on /dev/sequencer with TMR_ECHO midi event.
In this case the control flow is:sound_ioctl()
-> case SND_DEV_SEQ:
case SND_DEV_SEQ2:
sequencer_ioctl()
-> case SNDCTL_SEQ_OUTOFBAND:
spin_lock_irqsave(&lock,flags);
play_event();
-> case EV_TIMING:
seq_timing_event()
-> case TMR_ECHO:
seq_copy_to_input()
-> spin_lock_irqsave(&lock,flags);It seems that spin_lock_irqsave() around play_event() is not necessary, because the only other call location in seq_startplay() makes the call without acquiring spinlock.
So, the patch just removes spinlocks around play_event(). By the way, it removes unreachable code in seq_timing_event(), since (seq_mode == SEQ_2) case is handled in the beginning.
Compile tested only.
Found by Linux Driver Verification project (linuxtesting.org).
--- sound/oss/sequencer.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-)
sound/oss/sequencer.c +2 -10
@@ -677,13 +677,8 @@ static int seq_timing_event(unsigned char *event_rec)break ;case TMR_ECHO : -if (seq_mode ==SEQ_2 ) -seq_copy_to_input (event_rec,8 ); -else - { - parm = (parm <<8 |SEQ_ECHO ); -seq_copy_to_input ((unsigned char *) &parm,4 ); - } + parm = (parm <<8 |SEQ_ECHO ); +seq_copy_to_input ((unsigned char *) &parm,4 );break ;default :;
@@ -1326,7 +1321,6 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *aint mode =translate_mode (file);struct synth_info inf;struct seq_event_rec event_rec; -unsigned long flags;int __user *p = arg; orig_dev = dev = dev >>4 ;
@@ -1481,9 +1475,7 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, void __user *acase SNDCTL_SEQ_OUTOFBAND :if (copy_from_user (&event_rec, arg,sizeof (event_rec)))return -EFAULT ; -spin_lock_irqsave (&lock,flags);play_event (event_rec.arr); -spin_unlock_irqrestore (&lock,flags);return 0 ;case SNDCTL_MIDI_INFO :
Signature · 1 line
1.7.12.2.21.g234cd45.dirty