Revert "pcdp: use early_ioremap/early_iounmap to
Subsystems (89)
A message that is not in the archive (sent off-list or not yet received): 58df134a4b98edf5b0073e2e1e988fe6@local
PATCH 1/184 Revert "pcdp: use early_ioremap/early_iounmap to
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
access pcdp table"
From: Ben Hutchings <[email protected]>
This reverts commit 2af3af56e7d4756b21a2e0d86e4fc4e5b7f0df24, which was commit 6c4088ac3a4d82779903433bcd5f048c58fb1aca upstream.
This broke compilation of the driver in 2.6.32.y as the early_io{remap,unmap}() functions are not defined for ia64. The driver can *only* be built for ia64 (even in current mainline), so a fix for x86_64 is pointless.
--- drivers/firmware/pcdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/firmware/pcdp.c +2 -2
@@ -95,7 +95,7 @@ efi_setup_pcdp_console(char *cmdline)if (efi.hcdp ==EFI_INVALID_TABLE_ADDR )return -ENODEV ; - pcdp =early_ioremap (efi.hcdp,4096 ); + pcdp =ioremap (efi.hcdp,4096 );printk (KERN_INFO "PCDP: v%d at 0x%lx\n" , pcdp->rev, efi.hcdp);if (strstr (cmdline,"console=hcdp" )) {
@@ -131,6 +131,6 @@ efi_setup_pcdp_console(char *cmdline) } out: -early_iounmap (pcdp,4096 ); +iounmap (pcdp);return rc; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 2/184 Revert "block: improve queue_should_plug() by
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
looking at IO depths"
From: Jens Axboe <[email protected]>
This reverts commit fb1e75389bd06fd5987e9cda1b4e0305c782f854.
"Benjamin S." <[email protected]> reports that the patch in question causes a big drop in sequential throughput for him, dropping from 200MB/sec down to only 70MB/sec.
Needs to be investigated more fully, for now lets just revert the offending commit.
Conflicts:
include/linux/blkdev.h
--- block/blk-core.c | 11 ++--------- include/linux/blkdev.h | 4 +--- 2 files changed, 3 insertions(+), 12 deletions(-)
block/blk-core.c +2 -9
@@ -1149,7 +1149,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)*/ static inline bool queue_should_plug (struct request_queue *q) { -return !(blk_queue_nonrot (q) &&blk_queue_queuing (q)); +return !(blk_queue_nonrot (q) &&blk_queue_tagged (q)); }static int __make_request (struct request_queue *q,struct bio *bio)
@@ -1861,15 +1861,8 @@ void blk_dequeue_request(struct request *rq)* and to it is freed is accounted as io that is in progress at * the driver side. */ -if (blk_account_rq (rq)) { +if (blk_account_rq (rq)) q->in_flight[rq_is_sync (rq)]++; -/* -* Mark this device as supporting hardware queuing, if -* we have more IOs in flight than 4. -*/ -if (!blk_queue_queuing (q) &&queue_in_flight (q) >4 ) -set_bit (QUEUE_FLAG_CQ , &q->queue_flags); - } }/**
include/linux/blkdev.h +1 -3
@@ -456,8 +456,7 @@ struct request_queue#define QUEUE_FLAG_NONROT 14/* non-rotational device (SSD) */ #define QUEUE_FLAG_VIRT QUEUE_FLAG_NONROT/* paravirt device */ #define QUEUE_FLAG_IO_STAT 15/* do IO stats */ -#define QUEUE_FLAG_CQ 16/* hardware does queuing */ -#define QUEUE_FLAG_DISCARD 17/* supports DISCARD */ +#define QUEUE_FLAG_DISCARD 16/* supports DISCARD */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \
@@ -580,7 +579,6 @@ enum {#define blk_queue_plugged (q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)#define blk_queue_tagged (q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) -#define blk_queue_queuing (q) test_bit(QUEUE_FLAG_CQ, &(q)->queue_flags)#define blk_queue_stopped (q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)#define blk_queue_nomerges (q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)#define blk_queue_nonrot (q) test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 3/184 2.6.32.y: timekeeping: Fix nohz issue with commit
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
61b76840ddee647c0c223365378c3f394355b7d7
From: John Stultz <[email protected]>
Commit 61b76840ddee647c0c223365378c3f394355b7d7 ("time: Avoid making adjustments if we haven't accumulated anything") introduced a regression with nohz.
Basically with kernels between 2.6.20-something to 2.6.32, we accumulate time in half second chunks, rather then every timer-tick. This was added because when NOHZ landed, if you were idle for a few seconds, you had to spin for every tick we skipped in the accumulation loop, which created some bad latencies.
However, this required that we create the xtime_cache() which was still updated each tick, so that filesystem timestamps, etc continued to see time increment normally.
Of course, the xtime_cache is updated at the bottom of update_wall_time(). So the early return on
(offset < timekeeper.cycle_interval), added by the problematic commit causes the xtime_cache to not be updated.
This can cause code using current_kernel_time() (like the mqueue code) or hrtimer_get_softirq_time(), which uses the non-updated xtime_cache, to see timers to fire with very coarse half-second granularity.
Many thanks to Romain for describing the issue clearly, providing test case to reproduce it and helping with testing the solution.
This change is for 2.6.32-stable ONLY!
--- kernel/time/timekeeping.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/time/timekeeping.c +2 -1
@@ -809,7 +809,7 @@ void update_wall_time(void)#endif /* Check if there's really nothing to do */ if (offset < timekeeper.cycle_interval) -return ; + goto out; timekeeper.xtime_nsec = (s64 )xtime.tv_nsec << timekeeper.shift;
@@ -881,6 +881,7 @@ void update_wall_time(void) timekeeper.ntp_error += timekeeper.xtime_nsec << timekeeper.ntp_error_shift; +out: nsecs =clocksource_cyc2ns (offset, timekeeper.mult, timekeeper.shift);update_xtime_cache (nsecs);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 4/184 clockevents: Dont allow dummy broadcast timers
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
commit a7dc19b8652c862d5b7c4d2339bd3c428bd29c4a upstream.
Currently tick_check_broadcast_device doesn't reject clock_event_devices with CLOCK_EVT_FEAT_DUMMY, and may select them in preference to real hardware if they have a higher rating value. In this situation, the dummy timer is responsible for broadcasting to itself, and the core clockevents code may attempt to call non-existent callbacks for programming the dummy, eventually leading to a panic.
This patch makes tick_check_broadcast_device always reject dummy timers, preventing this problem.
--- kernel/time/tick-broadcast.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/time/tick-broadcast.c +2 -1
@@ -67,7 +67,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)*/ int tick_check_broadcast_device (struct clock_event_device *dev) { -if ((tick_broadcast_device.evtdev && +if ((dev->features &CLOCK_EVT_FEAT_DUMMY ) || + (tick_broadcast_device.evtdev && tick_broadcast_device.evtdev->rating >= dev->rating) || (dev->features &CLOCK_EVT_FEAT_C3STOP ))return 0 ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 5/184 posix-cpu-timers: Fix nanosleep task_struct leak
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Stanislaw Gruszka <[email protected]>
commit e6c42c295e071dd74a66b5a9fcf4f44049888ed8 upstream.
The trinity fuzzer triggered a task_struct reference leak via clock_nanosleep with CPU_TIMERs. do_cpu_nanosleep() calls posic_cpu_timer_create(), but misses a corresponding posix_cpu_timer_del() which leads to the task_struct reference leak.
--- kernel/posix-cpu-timers.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
kernel/posix-cpu-timers.c +21 -2
@@ -1537,8 +1537,10 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,while (!signal_pending (current)) {if (timer.it.cpu.expires.sched ==0 ) {/* -* Our timer fired and was reset. +* Our timer fired and was reset, below +* deletion can not fail. */ +posix_cpu_timer_del (&timer);spin_unlock_irq (&timer.it_lock);return 0 ; }
@@ -1556,9 +1558,26 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,* We were interrupted by a signal. */ sample_to_timespec (which_clock, timer.it.cpu.expires, rqtp); -posix_cpu_timer_set (&timer,0 , &zero_it, it); + error =posix_cpu_timer_set (&timer,0 , &zero_it, it); +if (!error) { +/* +* Timer is now unarmed, deletion can not fail. +*/ +posix_cpu_timer_del (&timer); + }spin_unlock_irq (&timer.it_lock); +while (error ==TIMER_RETRY ) { +/* +* We need to handle case when timer was or is in the +* middle of firing. In other cases we already freed +* resources. +*/ +spin_lock_irq (&timer.it_lock); + error =posix_cpu_timer_del (&timer); +spin_unlock_irq (&timer.it_lock); + } +if ((it->it_value.tv_sec | it->it_value.tv_nsec) ==0 ) {/* * It actually did fire already.
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 6/184 timer: Dont reinitialize the cpu base lock during
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
CPU_UP_PREPARE
From: Tirupathi Reddy <[email protected]>
commit 42a5cf46cd56f46267d2a9fcf2655f4078cd3042 upstream.
An inactive timer's base can refer to a offline cpu's base.
In the current code, cpu_base's lock is blindly reinitialized each time a CPU is brought up. If a CPU is brought online during the period that another thread is trying to modify an inactive timer on that CPU with holding its timer base lock, then the lock will be reinitialized under its feet. This leads to following SPIN_BUG().
<0> BUG: spinlock already unlocked on CPU#3, kworker/u:3/1466
<0> lock: 0xe3ebe000, .magic: dead4ead, .owner: kworker/u:3/1466, .owner_cpu: 1
<4> [<c0013dc4>] (unwind_backtrace+0x0/0x11c) from [<c026e794>] (do_raw_spin_unlock+0x40/0xcc) <4> [<c026e794>] (do_raw_spin_unlock+0x40/0xcc) from [<c076c160>] (_raw_spin_unlock+0x8/0x30) <4> [<c076c160>] (_raw_spin_unlock+0x8/0x30) from [<c009b858>] (mod_timer+0x294/0x310) <4> [<c009b858>] (mod_timer+0x294/0x310) from [<c00a5e04>] (queue_delayed_work_on+0x104/0x120) <4> [<c00a5e04>] (queue_delayed_work_on+0x104/0x120) from [<c04eae00>] (sdhci_msm_bus_voting+0x88/0x9c) <4> [<c04eae00>] (sdhci_msm_bus_voting+0x88/0x9c) from [<c04d8780>] (sdhci_disable+0x40/0x48) <4> [<c04d8780>] (sdhci_disable+0x40/0x48) from [<c04bf300>] (mmc_release_host+0x4c/0xb0) <4> [<c04bf300>] (mmc_release_host+0x4c/0xb0) from [<c04c7aac>] (mmc_sd_detect+0x90/0xfc) <4> [<c04c7aac>] (mmc_sd_detect+0x90/0xfc) from [<c04c2504>] (mmc_rescan+0x7c/0x2c4) <4> [<c04c2504>] (mmc_rescan+0x7c/0x2c4) from [<c00a6a7c>] (process_one_work+0x27c/0x484) <4> [<c00a6a7c>] (process_one_work+0x27c/0x484) from [<c00a6e94>] (worker_thread+0x210/0x3b0) <4> [<c00a6e94>] (worker_thread+0x210/0x3b0) from [<c00aad9c>] (kthread+0x80/0x8c)
<4> [<c00aad9c>] (kthread+0x80/0x8c) from [<c000ea80>] (kernel_thread_exit+0x0/0x8)
As an example, this particular crash occurred when CPU #3 is executing mod_timer() on an inactive timer whose base is refered to offlined CPU #2. The code locked the timer_base corresponding to CPU #2. Before it could proceed, CPU #2 came online and reinitialized the spinlock corresponding to its base. Thus now CPU #3 held a lock which was reinitialized. When CPU #3 finally ended up unlocking the old cpu_base corresponding to CPU #2, we hit the above SPIN_BUG().
CPU #0 CPU #3 CPU #2
------ ------- -------
..... ...... <Offline>
mod_timer() lock_timer_base spin_lock_irqsave(&base->lock)
cpu_up(2) ..... ......
init_timers_cpu()
.... ..... spin_lock_init(&base->lock)
..... spin_unlock_irqrestore(&base->lock) ......
<spin_bug>
Allocation of per_cpu timer vector bases is done only once under "tvec_base_done[]" check. In the current code, spinlock_initialization of base->lock isn't under this check. When a CPU is up each time the base lock is reinitialized. Move base spinlock initialization under the check.
--- kernel/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/timer.c +1 -1
@@ -1553,12 +1553,12 @@ static int __cpuinit init_timers_cpu(int cpu) boot_done =1 ; base = &boot_tvec_bases; } +spin_lock_init (&base->lock); tvec_base_done[cpu] =1 ; }else { base =per_cpu (tvec_bases, cpu); } -spin_lock_init (&base->lock);for (j =0 ; j <TVN_SIZE ; j++) {INIT_LIST_HEAD (base->tv5.vec + j);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 7/184 tick: Cleanup NOHZ per cpu data on cpu down
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit 4b0c0f294f60abcdd20994a8341a95c8ac5eeb96 upstream.
Prarit reported a crash on CPU offline/online. The reason is that on CPU down the NOHZ related per cpu data of the dead cpu is not cleaned up. If at cpu online an interrupt happens before the per cpu tick device is registered the irq_enter() check potentially sees stale data and dereferences a NULL pointer.
Cleanup the data after the cpu is dead.
--- kernel/time/tick-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/tick-sched.c +1 -1
@@ -765,7 +765,7 @@ void tick_cancel_sched_timer(int cpu)hrtimer_cancel (&ts->sched_timer);# endif - ts->nohz_mode = NOHZ_MODE_INACTIVE; + memset(ts, 0, sizeof(*ts)); }#endif
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 8/184 kbuild: Fix gcc -x syntax
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jean Delvare <[email protected]>
This is upstream commit b1e0d8b70fa31821ebca3965f2ef8619d7c5e316 backported to the 2.6.32.x stable branch.
The correct syntax for gcc -x is "gcc -x assembler", not "gcc -xassembler". Even though the latter happens to work, the former is what is documented in the manual page and thus what gcc wrappers such as icecream do expect.
This isn't a cosmetic change. The missing space prevents icecream from recognizing compilation tasks it can't handle, leading to silent kernel miscompilations.
Besides me, credits go to Michael Matz and Dirk Mueller for investigating the miscompilation issue and tracking it down to this incorrect -x parameter syntax.
--- arch/mips/Makefile | 2 +- arch/mips/kernel/Makefile | 2 +- scripts/Kbuild.include | 12 ++++++------ scripts/gcc-version.sh | 6 +++--- scripts/gcc-x86_32-has-stack-protector.sh | 2 +- scripts/gcc-x86_64-has-stack-protector.sh | 2 +- scripts/kconfig/check.sh | 2 +- scripts/kconfig/lxdialog/check-lxdialog.sh | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-)
arch/mips/Makefile +1 -1
@@ -657,7 +657,7 @@ KBUILD_CPPFLAGS += -D"DATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)" LDFLAGS += -m $(ld-emul) ifdef CONFIG_MIPS -CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -xc /dev/null | \ +CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \ sed -e 's/^\#define /-D/' -e "s/ /='/" -e "s/$$/'/") ifdef CONFIG_64BIT
arch/mips/kernel/Makefile +1 -1
@@ -88,7 +88,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) +CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
scripts/Kbuild.include +6 -6
@@ -94,24 +94,24 @@ try-run = $(shell set -e; \ # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) as-option = $(call try-run,\ - $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2)) # as-instr # Usage: cflags-y += $(call as-instr,instr,option1,option2) as-instr = $(call try-run,\ - /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) + /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) cc-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) cc-option-yn = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) # cc-option-align # Prefix align with either -falign or -malign
@@ -121,7 +121,7 @@ cc-option-align = $(subst -functions=0,,\ # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) cc-disable-warning = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) + $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) # cc-version # Usage gcc-ver := $(call cc-version)
@@ -139,7 +139,7 @@ cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) cc-ldoption = $(call try-run,\ - $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) # ld-option # Usage: LDFLAGS += $(call ld-option, -X)
scripts/gcc-version.sh +3 -3
@@ -22,10 +22,10 @@ if [ ${#compiler} -eq 0 ]; then exit 1 fi -MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1) -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1) +MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1) + PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL else printf "%02d%02d\\n" $MAJOR $MINOR
scripts/gcc-x86_32-has-stack-protector.sh +1 -1
@@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else
scripts/gcc-x86_64-has-stack-protector.sh +1 -1
@@ -1,6 +1,6 @@ #!/bin/sh -echo "int foo(void) { char X[200]; return 3; }" | $* -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" if [ "$?" -eq "0" ] ; then echo y else
scripts/kconfig/check.sh +1 -1
@@ -1,6 +1,6 @@ #!/bin/sh # Needed for systems without gettext -$* -xc -o /dev/null - > /dev/null 2>&1 << EOF +$* -x c -o /dev/null - > /dev/null 2>&1 << EOF #include <libintl.h> int main() {
scripts/kconfig/lxdialog/check-lxdialog.sh +1 -1
@@ -36,7 +36,7 @@ trap "rm -f $tmp" 0 1 2 3 15 # Check if we can link to ncurses check() { - $cc -xc - -o $tmp 2>/dev/null <<'EOF' + $cc -x c - -o $tmp 2>/dev/null <<'EOF' #include CURSES_LOC main() {} EOF
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 9/184 gen_init_cpio: avoid stack overflow when expanding
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
commit 20f1de659b77364d55d4e7fad2ef657e7730323f upstream.
Fix possible overflow of the buffer used for expanding environment variables when building file list.
In the extremely unlikely case of an attacker having control over the environment variables visible to gen_init_cpio, control over the contents of the file gen_init_cpio parses, and gen_init_cpio was built without compiler hardening, the attacker can gain arbitrary execution control via a stack buffer overflow.
$ cat usr/crash.list
file foo ${BIG}${BIG}${BIG}${BIG}${BIG}${BIG} 0755 0 0
$ BIG=$(perl -e 'print "A" x 4096;') ./usr/gen_init_cpio usr/crash.list
*** buffer overflow detected ***: ./usr/gen_init_cpio terminatedThis also replaces the space-indenting with tabs.
Patch based on existing fix extracted from grsecurity.
--- usr/gen_init_cpio.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-)
usr/gen_init_cpio.c +23 -20
@@ -299,7 +299,7 @@ static int cpio_mkfile(const char *name, const char *location,int retval;int rc =-1 ;int namesize; -int i; +unsigned int i; mode |=S_IFREG ;
@@ -372,25 +372,28 @@ error:static char *cpio_replace_env (char *new_location) { -char expanded[PATH_MAX +1 ]; -char env_var[PATH_MAX +1 ]; -char *start; -char *end; - -for (start =NULL ; (start =strstr (new_location,"${" )); ) { - end =strchr (start,'}' ); -if (start < end) { - *env_var = *expanded ='\0' ; -strncat (env_var, start +2 , end - start -2 ); -strncat (expanded, new_location, start - new_location); -strncat (expanded,getenv (env_var),PATH_MAX ); -strncat (expanded, end +1 ,PATH_MAX ); -strncpy (new_location, expanded,PATH_MAX ); - }else -break ; - } - -return new_location; +char expanded[PATH_MAX +1 ]; +char env_var[PATH_MAX +1 ]; +char *start; +char *end; + +for (start =NULL ; (start =strstr (new_location,"${" )); ) { + end =strchr (start,'}' ); +if (start < end) { + *env_var = *expanded ='\0' ; +strncat (env_var, start +2 , end - start -2 ); +strncat (expanded, new_location, start - new_location); +strncat (expanded,getenv (env_var), +PATH_MAX -strlen (expanded)); +strncat (expanded, end +1 , +PATH_MAX -strlen (expanded)); +strncpy (new_location, expanded,PATH_MAX ); + new_location[PATH_MAX ] =0 ; + }else +break ; + } + +return new_location; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 10/184 usermodehelper: introduce umh_complete(sub_info)
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
commit b3449922502f5a161ee2b5022a33aec8472fbf18 upstream
Preparation. Add the new trivial helper, umh_complete(). Currently it simply does complete(sub_info->complete).
--- kernel/kmod.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/kmod.c +7 -2
@@ -206,6 +206,11 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info) }EXPORT_SYMBOL (call_usermodehelper_freeinfo); +static void umh_complete (struct subprocess_info *sub_info) +{ +complete (sub_info->complete); +} +/* Keventd can't block, but this (a child) can. */ static int wait_for_helper (void *data) {
@@ -245,7 +250,7 @@ static int wait_for_helper(void *data)if (sub_info->wait ==UMH_NO_WAIT )call_usermodehelper_freeinfo (sub_info);else -complete (sub_info->complete); +umh_complete (sub_info);return 0 ; }
@@ -280,7 +285,7 @@ static void __call_usermodehelper(struct work_struct *work)/* FALLTHROUGH */ case UMH_WAIT_EXEC : -complete (sub_info->complete); +umh_complete (sub_info); } }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 010/184] usermodehelper: introduce umh_complete(sub_info)
Quoted 11 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
commit
b3449922502f5a161ee2b5022a33aec8472fbf18upstreamPreparation. Add the new trivial helper,
umh_complete(). Currently it simply doescomplete(sub_info->complete).
Quoted 8 lines
Signed-off-by Oleg Nesterov <[email protected]>Cc Tetsuo Handa <[email protected]>Cc Rusty Russell <[email protected]>Cc Tejun Heo <[email protected]>Cc David Rientjes <[email protected]>Signed-off-by Andrew Morton <[email protected]>Signed-off-by Linus Torvalds <[email protected]>[dannf: Adjusted to apply to Debian's 2.6.32]
Dann's backports are mostly missing his Signed-off-by. (We don't usually bother with this in the Debian patch queue, but probably ought to do so when backporting.)
Ben.
Quoted 39 lines
Signed-off-by Willy Tarreau <[email protected]>--- kernel/kmod.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)kernel/kmod.c +7
-2@@ -206,6 +206,11 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info) }EXPORT_SYMBOL (call_usermodehelper_freeinfo); +static void umh_complete (struct subprocess_info *sub_info) +{ +complete (sub_info->complete); +} +/* Keventd can't block, but this (a child) can. */ static int wait_for_helper (void *data) {@@ -245,7 +250,7 @@ static int wait_for_helper(void *data)if (sub_info->wait ==UMH_NO_WAIT )call_usermodehelper_freeinfo (sub_info);else -complete (sub_info->complete); +umh_complete (sub_info);return 0 ; }@@ -280,7 +285,7 @@ static void __call_usermodehelper(struct work_struct *work)/* FALLTHROUGH */ case UMH_WAIT_EXEC : -complete (sub_info->complete); +umh_complete (sub_info); } }
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 010/184] usermodehelper: introduce umh_complete(sub_info)
Quoted 21 lines · Ben Hutchings
Quoted 11 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
commit
b3449922502f5a161ee2b5022a33aec8472fbf18upstreamPreparation. Add the new trivial helper,
umh_complete(). Currently it simply doescomplete(sub_info->complete).Quoted 8 lines
Signed-off-by Oleg Nesterov <[email protected]>Cc Tetsuo Handa <[email protected]>Cc Rusty Russell <[email protected]>Cc Tejun Heo <[email protected]>Cc David Rientjes <[email protected]>Signed-off-by Andrew Morton <[email protected]>Signed-off-by Linus Torvalds <[email protected]>[dannf: Adjusted to apply to Debian's 2.6.32]
Quoted 3 lines
Dann's backports are mostly missing his Signed-off-by. (We don't usually bother with this in the Debian patch queue, but probably ought to do so when backporting.)
Agreed, it would be cleaner. Dann, would you please pass me your s-o-b for this one before the release ?
Thanks,
Willy
PATCH 11/184 usermodehelper: implement UMH_KILLABLE
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
commit d0bd587a80960d7ba7e0c8396e154028c9045c54 upstream
Implement UMH_KILLABLE, should be used along with UMH_WAIT_EXEC/PROC. The caller must ensure that subprocess_info->path/etc can not go away until call_usermodehelper_freeinfo().
call_usermodehelper_exec(UMH_KILLABLE) does wait_for_completion_killable. If it fails, it uses xchg(&sub_info->complete, NULL) to serialize with umh_complete() which does the same xhcg() to access sub_info->complete.
If call_usermodehelper_exec wins, it can safely return. umh_complete() should get NULL and call call_usermodehelper_freeinfo().
Otherwise we know that umh_complete() was already called, in this case call_usermodehelper_exec() falls back to wait_for_completion() which should succeed "very soon".
Note: UMH_NO_WAIT == -1 but it obviously should not be used with UMH_KILLABLE. We delay the neccessary cleanup to simplify the back porting.
--- include/linux/kmod.h | 2 ++ kernel/kmod.c | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-)
include/linux/kmod.h +2 -0
@@ -64,6 +64,8 @@ enum umh_wait { UMH_WAIT_PROC = 1, /* wait for the process to complete */ }; +#define UMH_KILLABLE 4/* wait for EXEC/PROC killable */ +/* Actually execute the sub-process */ int call_usermodehelper_exec (struct subprocess_info *info,enum umh_wait wait);
kernel/kmod.c +25 -2
@@ -208,7 +208,15 @@ EXPORT_SYMBOL(call_usermodehelper_freeinfo);static void umh_complete (struct subprocess_info *sub_info) { -complete (sub_info->complete); +struct completion *comp =xchg (&sub_info->complete,NULL ); +/* +* See call_usermodehelper_exec(). If xchg() returns NULL +* we own sub_info, the UMH_KILLABLE caller has gone away. +*/ +if (comp) +complete (comp); +else +call_usermodehelper_freeinfo (sub_info); }/* Keventd can't block, but this (a child) can. */
@@ -264,6 +272,9 @@ static void __call_usermodehelper(struct work_struct *work)BUG_ON (atomic_read (&sub_info->cred->usage) !=1 ); +if (wait !=UMH_NO_WAIT ) + wait &= ~UMH_KILLABLE ; +/* CLONE_VFORK: wait until the usermode helper has execve'd * successfully We need the data structures to stay around * until that is done. */
@@ -525,9 +536,21 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,queue_work (khelper_wq, &sub_info->work);if (wait ==UMH_NO_WAIT )/* task has freed sub_info */ goto unlock; + +if (wait &UMH_KILLABLE ) { + retval =wait_for_completion_killable (&done); +if (!retval) + goto wait_done; + +/* umh_complete() will see NULL and free sub_info */ +if (xchg (&sub_info->complete,NULL )) + goto unlock; +/* fallthrough, umh_complete() was already called */ + } +wait_for_completion (&done); +wait_done: retval = sub_info->retval; - out:call_usermodehelper_freeinfo (sub_info); unlock:
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 12/184 usermodehelper: ____call_usermodehelper() doesnt
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
need do_exit()
From: Oleg Nesterov <[email protected]>
commit 5b9bd473e3b8a8c6c4ae99be475e6e9b27568555 upstream
Minor cleanup. ____call_usermodehelper() can simply return, no need to call do_exit() explicitely.
--- kernel/kmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/kmod.c +1 -1
@@ -193,7 +193,7 @@ static int ____call_usermodehelper(void *data)/* Exec failed? */ sub_info->retval = retval; -do_exit (0 ); +return 0 ; }void call_usermodehelper_freeinfo (struct subprocess_info *info)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 13/184 kmod: introduce call_modprobe() helper
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
commit 3e63a93b987685f02421e18b2aa452d20553a88b upstream
No functional changes. Move the call_usermodehelper code from __request_module() into the new simple helper, call_modprobe().
--- kernel/kmod.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
kernel/kmod.c +14 -7
@@ -53,6 +53,18 @@ static DECLARE_RWSEM(umhelper_sem);*/ char modprobe_path[KMOD_PATH_LEN ] ="/sbin/modprobe" ; +static int call_modprobe (char *module_name,int wait) +{ +static char *envp[] = {"HOME=/" , +"TERM=linux" , +"PATH=/sbin:/usr/sbin:/bin:/usr/bin" , +NULL }; + +char *argv[] = { modprobe_path,"-q" ,"--" , module_name,NULL }; + +return call_usermodehelper (modprobe_path, argv, envp, wait); +} +/** * __request_module - try to load a kernel module * @wait: wait (or not) for the operation to complete
@@ -74,11 +86,6 @@ int __request_module(bool wait, const char *fmt, ...)char module_name[MODULE_NAME_LEN ];unsigned int max_modprobes;int ret; -char *argv[] = { modprobe_path,"-q" ,"--" , module_name,NULL }; -static char *envp[] = {"HOME=/" , -"TERM=linux" , -"PATH=/sbin:/usr/sbin:/bin:/usr/bin" , -NULL };static atomic_t kmod_concurrent =ATOMIC_INIT (0 );#define MAX_KMOD_CONCURRENT 50/* Completely arbitrary value - KAO */ static int kmod_loop_msg;
@@ -121,8 +128,8 @@ int __request_module(bool wait, const char *fmt, ...)trace_module_request (module_name, wait, _RET_IP_); - ret =call_usermodehelper (modprobe_path, argv, envp, - wait ?UMH_WAIT_PROC :UMH_WAIT_EXEC ); + ret =call_modprobe (module_name, wait ?UMH_WAIT_PROC :UMH_WAIT_EXEC ); +atomic_dec (&kmod_concurrent);return ret; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 14/184 kmod: make __request_module() killable
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
commit 1cc684ab75123efe7ff446eb821d44375ba8fa30 upstream
As Tetsuo Handa pointed out, request_module() can stress the system while the oom-killed caller sleeps in TASK_UNINTERRUPTIBLE.
The task T uses "almost all" memory, then it does something which triggers request_module(). Say, it can simply call sys_socket(). This in turn needs more memory and leads to OOM. oom-killer correctly chooses T and kills it, but this can't help because it sleeps in TASK_UNINTERRUPTIBLE and after that oom-killer becomes "disabled" by the TIF_MEMDIE task T.
Make __request_module() killable. The only necessary change is that call_modprobe() should kmalloc argv and module_name, they can't live in the stack if we use UMH_KILLABLE. This memory is freed via call_usermodehelper_freeinfo()->cleanup.
--- kernel/kmod.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-)
kernel/kmod.c +34 -2
@@ -53,16 +53,48 @@ static DECLARE_RWSEM(umhelper_sem);*/ char modprobe_path[KMOD_PATH_LEN ] ="/sbin/modprobe" ; +static void free_modprobe_argv (char **argv,char **envp) +{ +kfree (argv[3 ]);/* check call_modprobe() */ +kfree (argv); +} +static int call_modprobe (char *module_name,int wait) {static char *envp[] = {"HOME=/" ,"TERM=linux" ,"PATH=/sbin:/usr/sbin:/bin:/usr/bin" ,NULL }; +struct subprocess_info *info; + +char **argv =kmalloc (sizeof (char *[5 ]),GFP_KERNEL ); +if (!argv) + goto out; -char *argv[] = { modprobe_path,"-q" ,"--" , module_name,NULL }; + module_name =kstrdup (module_name,GFP_KERNEL ); +if (!module_name) + goto free_argv; -return call_usermodehelper (modprobe_path, argv, envp, wait); + argv[0 ] = modprobe_path; + argv[1 ] ="-q" ; + argv[2 ] ="--" ; + argv[3 ] = module_name;/* check free_modprobe_argv() */ + argv[4 ] =NULL ; + + info =call_usermodehelper_setup (argv[0 ], argv, envp,GFP_ATOMIC ); +if (!info) + goto free_module_name; + +call_usermodehelper_setcleanup (info, free_modprobe_argv); + +return call_usermodehelper_exec (info, wait |UMH_KILLABLE ); + +free_module_name: +kfree (module_name); +free_argv: +kfree (argv); +out: +return -ENOMEM ; }/**
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 15/184 exec: do not leave bprm->interp on stack
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
commit b66c5984017533316fd1951770302649baf1aa33 upstream
If a series of scripts are executed, each triggering module loading via unprintable bytes in the script header, kernel stack contents can leak into the command line.
Normally execution of binfmt_script and binfmt_misc happens recursively. However, when modules are enabled, and unprintable bytes exist in the bprm->buf, execution will restart after attempting to load matching binfmt modules. Unfortunately, the logic in binfmt_script and binfmt_misc does not expect to get restarted. They leave bprm->interp pointing to their local stack. This means on restart bprm->interp is left pointing into unused stack memory which can then be copied into the userspace argv areas.
After additional study, it seems that both recursion and restart remains the desirable way to handle exec with scripts, misc, and modules. As such, we need to protect the changes to interp.
This changes the logic to require allocation for any changes to the bprm->interp. To avoid adding a new kmalloc to every exec, the default value is left as-is. Only when passing through binfmt_script or binfmt_misc does an allocation take place.
For a proof of concept, see DoTest.sh from:
http://www.halfdog.net/Security/2012/LinuxKernelBinfmtScriptStackDataDisclosure/
--- fs/binfmt_misc.c | 5 ++++- fs/binfmt_script.c | 4 +++- fs/exec.c | 15 +++++++++++++++ include/linux/binfmts.h | 1 + 4 files changed, 23 insertions(+), 2 deletions(-)
fs/binfmt_misc.c +4 -1
@@ -176,7 +176,10 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) goto _error; bprm->argc ++; - bprm->interp = iname;/* for binfmt_script */ +/* Update interp in case binfmt_script needs it. */ + retval =bprm_change_interp (iname, bprm); +if (retval <0 ) + goto _error; interp_file =open_exec (iname); retval =PTR_ERR (interp_file);
fs/binfmt_script.c +3 -1
@@ -82,7 +82,9 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) retval =copy_strings_kernel (1 , &i_name, bprm);if (retval)return retval; bprm->argc++; - bprm->interp = interp; + retval =bprm_change_interp (interp, bprm); +if (retval <0 ) +return retval;/* * OK, now restart the process with the interpreter's dentry.
fs/exec.c +15 -0
@@ -1108,9 +1108,24 @@ void free_bprm(struct linux_binprm *bprm)mutex_unlock (¤t->cred_guard_mutex);abort_creds (bprm->cred); } +/* If a binfmt changed the interp, free it. */ +if (bprm->interp != bprm->filename) +kfree (bprm->interp);kfree (bprm); } +int bprm_change_interp (char *interp,struct linux_binprm *bprm) +{ +/* If a binfmt changed the interp, free it first. */ +if (bprm->interp != bprm->filename) +kfree (bprm->interp); + bprm->interp =kstrdup (interp,GFP_KERNEL ); +if (!bprm->interp) +return -ENOMEM ; +return 0 ; +} +EXPORT_SYMBOL (bprm_change_interp); +/* * install the new credentials for this executable */
include/linux/binfmts.h +1 -0
@@ -122,6 +122,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,unsigned long stack_top, int executable_stack);extern int bprm_mm_init (struct linux_binprm *bprm); +extern int bprm_change_interp (char *interp,struct linux_binprm *bprm);extern int copy_strings_kernel (int argc,char ** argv,struct linux_binprm *bprm);extern int prepare_bprm_creds (struct linux_binprm *bprm);extern void install_exec_creds (struct linux_binprm *bprm);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 16/184 exec: use -ELOOP for max recursion depth
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
commit d740269867021faf4ce38a449353d2b986c34a67 upstream
To avoid an explosion of request_module calls on a chain of abusive scripts, fail maximum recursion with -ELOOP instead of -ENOEXEC. As soon as maximum recursion depth is hit, the error will fail all the way back up the chain, aborting immediately.
This also has the side-effect of stopping the user's shell from attempting to reexecute the top-level file as a shell script. As seen in the dash source:
if (cmd != path_bshell && errno == ENOEXEC) {
*argv-- = cmd;
*argv = cmd = path_bshell;
goto repeat;
}The above logic was designed for running scripts automatically that lacked the "#!" header, not to re-try failed recursion. On a legitimate -ENOEXEC, things continue to behave as the shell expects.
Additionally, when tracking recursion, the binfmt handlers should not be involved. The recursion being tracked is the depth of calls through search_binary_handler(), so that function should be exclusively responsible for tracking the depth.
--- fs/binfmt_em86.c | 1 - fs/binfmt_misc.c | 6 ------ fs/binfmt_script.c | 4 +--- fs/exec.c | 10 +++++----- include/linux/binfmts.h | 2 -- 5 files changed, 6 insertions(+), 17 deletions(-)
fs/binfmt_em86.c +0 -1
@@ -43,7 +43,6 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)return -ENOEXEC ; } - bprm->recursion_depth++;/* Well, the bang-shell is implicit... */ allow_write_access (bprm->file);fput (bprm->file); bprm->file =NULL ;
fs/binfmt_misc.c +0 -6
@@ -116,10 +116,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)if (!enabled) goto _ret; - retval = -ENOEXEC ; -if (bprm->recursion_depth >BINPRM_MAX_RECURSION ) - goto _ret; -/* to keep locking time low, we copy the interpreter string */ read_lock (&entries_lock); fmt =check_file (bprm);
@@ -200,8 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)if (retval <0 ) goto _error; - bprm->recursion_depth++; - retval =search_binary_handler (bprm, regs);if (retval <0 ) goto _error;
fs/binfmt_script.c +1 -3
@@ -22,15 +22,13 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)char interp[BINPRM_BUF_SIZE ];int retval; -if ((bprm->buf[0 ] !='#' ) || (bprm->buf[1 ] !='!' ) || - (bprm->recursion_depth >BINPRM_MAX_RECURSION )) +if ((bprm->buf[0 ] !='#' ) || (bprm->buf[1 ] !='!' ))return -ENOEXEC ;/* * This section does the #! interpretation. * Sorta complicated, but hopefully it will work. -TYT */ - bprm->recursion_depth++;allow_write_access (bprm->file);fput (bprm->file); bprm->file =NULL ;
fs/exec.c +5 -5
@@ -1285,6 +1285,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)int try,retval;struct linux_binfmt *fmt; +/* This allows 4 levels of binfmt rewrites before failing hard. */ +if (depth >5 ) +return -ELOOP ; + retval =security_bprm_check (bprm);if (retval)return retval;
@@ -1306,12 +1310,8 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)if (!try_module_get (fmt->module))continue ;read_unlock (&binfmt_lock); + bprm->recursion_depth = depth +1 ; retval =fn (bprm, regs); -/* -* Restore the depth counter to its starting value -* in this call, so we don't have to rely on every -* load_binary function to restore it on return. -*/ bprm->recursion_depth = depth;if (retval >=0 ) {if (depth ==0 )
include/linux/binfmts.h +0 -2
@@ -71,8 +71,6 @@ extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,#define BINPRM_FLAGS_EXECFD_BIT 1#define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT) -#define BINPRM_MAX_RECURSION 4 -/* * This structure defines the functions that are used to load the binary formats that * linux accepts.
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 17/184 signal: always clear sa_restorer on execve
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Kees Cook <[email protected]>
commit 2ca39528c01a933f6689cd6505ce65bd6d68a530 upstream.
When the new signal handlers are set up, the location of sa_restorer is not cleared, leaking a parent process's address space location to children. This allows for a potential bypass of the parent's ASLR by examining the sa_restorer value returned when calling sigaction().
Based on what should be considered "secret" about addresses, it only matters across the exec not the fork (since the VMAs haven't changed until the exec). But since exec sets SIG_DFL and keeps sa_restorer, this is where it should be fixed.
Given the few uses of sa_restorer, a "set" function was not written since this would be the only use. Instead, we use __ARCH_HAS_SA_RESTORER, as already done in other places.
Example of the leak before applying this patch:
$ cat /proc/$$/maps ... 7fb9f3083000-7fb9f3238000 r-xp 00000000 fd:01 404469 .../libc-2.15.so ... $ ./leak ... 7f278bc74000-7f278be29000 r-xp 00000000 fd:01 404469 .../libc-2.15.so ... 1 0 (nil) 0x7fb9f30b94a0 2 4000000 (nil) 0x7f278bcaa4a0 3 4000000 (nil) 0x7f278bcaa4a0 4 0 (nil) 0x7fb9f30b94a0 ...
--- kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/signal.c +3 -0
@@ -320,6 +320,9 @@ flush_signal_handlers(struct task_struct *t, int force_default)if (force_default || ka->sa.sa_handler !=SIG_IGN ) ka->sa.sa_handler =SIG_DFL ; ka->sa.sa_flags =0 ; +#ifdef SA_RESTORER + ka->sa.sa_restorer =NULL ; +#endif sigemptyset (&ka->sa.sa_mask); ka++; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 18/184 ptrace: ptrace_resume() shouldnt wake up
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
!TASK_TRACED thread
From: Oleg Nesterov <[email protected]>
ptrace: ptrace_resume() shouldn't wake up !TASK_TRACED thread
CVE-2013-0871
It is not clear why ptrace_resume() does wake_up_process(). Unless the caller is PTRACE_KILL the tracee should be TASK_TRACED so we can use wake_up_state(__TASK_TRACED). If sys_ptrace() races with SIGKILL we do not need the extra and potentionally spurious wakeup.
If the caller is PTRACE_KILL, wake_up_process() is even more wrong. The tracee can sleep in any state in any place, and if we have a buggy code which doesn't handle a spurious wakeup correctly PTRACE_KILL can be used to exploit it. For example:
int main(void)
{
int child, status;
child = fork();
if (!child) {
int ret;
assert(ptrace(PTRACE_TRACEME, 0,0,0) == 0);
ret = pause();
printf("pause: %d %m\n", ret);
return 0x23;
}
sleep(1);
assert(ptrace(PTRACE_KILL, child, 0,0) == 0);
assert(child == wait(&status));
printf("wait: %x\n", status);
return 0;
}prints "pause: -1 Unknown error 514", -ERESTARTNOHAND leaks to the userland. In this case sys_pause() is buggy as well and should be fixed.
I do not know what was the original rationality behind PTRACE_KILL. The man page is simply wrong and afaics it was always wrong. Imho it should be deprecated, or may be it should do send_sig(SIGKILL) as Denys suggests, but in any case I do not think that the current behaviour was intentional.
Note: there is another problem, ptrace_resume() changes ->exit_code and this can race with SIGKILL too. Eventually we should change ptrace to not use ->exit_code.
--- kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/ptrace.c +1 -1
@@ -506,7 +506,7 @@ static int ptrace_resume(struct task_struct *child, long request, long data) } child->exit_code = data; -wake_up_process (child); +wake_up_state (child, __TASK_TRACED);return 0 ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 19/184 ptrace: introduce signal_wake_up_state() and
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
ptrace_signal_wake_up()
From: Oleg Nesterov <[email protected]>
ptrace: introduce signal_wake_up_state() and ptrace_signal_wake_up()
CVE-2013-0871
Cleanup and preparation for the next change.
signal_wake_up(resume => true) is overused. None of ptrace/jctl callers actually want to wakeup a TASK_WAKEKILL task, but they can't specify the necessary mask.
Turn signal_wake_up() into signal_wake_up_state(state), reintroduce signal_wake_up() as a trivial helper, and add ptrace_signal_wake_up() which adds __TASK_TRACED.
This way ptrace_signal_wake_up() can work "inside" ptrace_request() even if the tracee doesn't have the TASK_WAKEKILL bit set.
Conflicts:
kernel/ptrace.c
kernel/signal.c
--- include/linux/sched.h | 11 ++++++++++- kernel/ptrace.c | 2 +- kernel/signal.c | 12 +++--------- 3 files changed, 14 insertions(+), 11 deletions(-)
include/linux/sched.h +10 -1
@@ -2459,7 +2459,16 @@ static inline void thread_group_cputime_free(struct signal_struct *sig)extern void recalc_sigpending_and_wake (struct task_struct *t);extern void recalc_sigpending (void ); -extern void signal_wake_up (struct task_struct *t,int resume_stopped); +extern void signal_wake_up_state (struct task_struct *t,unsigned int state); + +static inline void signal_wake_up (struct task_struct *t,bool resume) +{ +signal_wake_up_state (t, resume ?TASK_WAKEKILL :0 ); +} +static inline void ptrace_signal_wake_up (struct task_struct *t,bool resume) +{ +signal_wake_up_state (t, resume ? __TASK_TRACED :0 ); +}/* * Wrappers for p->thread_info->cpu access. No-op on UP.
kernel/ptrace.c +1 -1
@@ -56,7 +56,7 @@ static void ptrace_untrace(struct task_struct *child) child->signal->group_stop_count)__set_task_state (child,TASK_STOPPED ); else - signal_wake_up(child, 1); +ptrace_signal_wake_up (child ,true ); }spin_unlock (&child->sighand->siglock); }
kernel/signal.c +3 -9
@@ -516,23 +516,17 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)* No need to set need_resched since signal event passing * goes through ->blocked */ -void signal_wake_up (struct task_struct *t,int resume) +void signal_wake_up_state (struct task_struct *t,unsigned int state) { -unsigned int mask; -set_tsk_thread_flag (t,TIF_SIGPENDING ); -/* -* For SIGKILL, we want to wake it up in the stopped/traced/killable +* TASK_WAKEKILL also means wake it up in the stopped/traced/killable * case. We don't check t->state here because there is a race with it * executing another processor and just now entering stopped state. * By using wake_up_state, we ensure the process will wake up and * handle its death signal. */ - mask =TASK_INTERRUPTIBLE ; -if (resume) - mask |=TASK_WAKEKILL ; -if (!wake_up_state (t, mask)) +if (!wake_up_state (t, state |TASK_INTERRUPTIBLE ))kick_process (t); }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 20/184 ptrace: ensure arch_ptrace/ptrace_request can never
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
race with SIGKILL
From: Oleg Nesterov <[email protected]>
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
CVE-2013-0871
putreg() assumes that the tracee is not running and pt_regs_access() can safely play with its stack. However a killed tracee can return from ptrace_stop() to the low-level asm code and do RESTORE_REST, this means that debugger can actually read/modify the kernel stack until the tracee does SAVE_REST again.
set_task_blockstep() can race with SIGKILL too and in some sense this race is even worse, the very fact the tracee can be woken up breaks the logic.
As Linus suggested we can clear TASK_WAKEKILL around the arch_ptrace() call, this ensures that nobody can ever wakeup the tracee while the debugger looks at it. Not only this fixes the mentioned problems, we can do some cleanups/simplifications in arch_ptrace() paths.
Probably ptrace_unfreeze_traced() needs more callers, for example it makes sense to make the tracee killable for oom-killer before access_process_vm().
While at it, add the comment into may_ptrace_stop() to explain why ptrace_stop() still can't rely on SIGKILL and signal_pending_state().
Conflicts:
arch/x86/kernel/step.c kernel/ptrace.c kernel/signal.c
--- kernel/ptrace.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++----------- kernel/signal.c | 4 ++++ 2 files changed, 55 insertions(+), 12 deletions(-)
kernel/ptrace.c +51 -12
@@ -80,6 +80,36 @@ void __ptrace_unlink(struct task_struct *child)ptrace_untrace (child); } +/* Ensure that nothing can wake it up, even SIGKILL */ +static bool ptrace_freeze_traced (struct task_struct *task) +{ +bool ret = false; + +spin_lock_irq (&task->sighand->siglock); +if (task_is_traced (task) && !__fatal_signal_pending (task)) { + task->state = __TASK_TRACED; + ret = true; + } +spin_unlock_irq (&task->sighand->siglock); + +return ret; +} + +static void ptrace_unfreeze_traced (struct task_struct *task) +{ +if (task->state != __TASK_TRACED) +return ; + +WARN_ON (!task->ptrace || task->parent != current); + +spin_lock_irq (&task->sighand->siglock); +if (__fatal_signal_pending (task)) +wake_up_state (task, __TASK_TRACED); +else + task->state =TASK_TRACED ; +spin_unlock_irq (&task->sighand->siglock); +} +/* * Check that we have indeed attached to the thing.. */
@@ -95,25 +125,29 @@ int ptrace_check_attach(struct task_struct *child, int kill)* be changed by us so it's not changing right after this. */ read_lock (&tasklist_lock); -if ((child->ptrace &PT_PTRACED ) && child->parent == current) { - ret =0 ; +if (child->ptrace && child->parent == current) { +WARN_ON (child->state == __TASK_TRACED);/* * child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ -spin_lock_irq (&child->sighand->siglock); -if (task_is_stopped (child)) - child->state =TASK_TRACED ; -else if (!task_is_traced (child) && !kill) - ret = -ESRCH ; -spin_unlock_irq (&child->sighand->siglock); +if (kill ||ptrace_freeze_traced (child)) + ret =0 ; }read_unlock (&tasklist_lock); -if (!ret && !kill) - ret =wait_task_inactive (child,TASK_TRACED ) ?0 : -ESRCH ; +if (!ret && !kill) { +if (!wait_task_inactive (child, __TASK_TRACED)) { +/* +* This can only happen if may_ptrace_stop() fails and +* ptrace_stop() changes ->state back to TASK_RUNNING, +* so we should not worry about leaking __TASK_TRACED. +*/ +WARN_ON (child->state == __TASK_TRACED); + ret = -ESRCH ; + } + } -/* All systems go.. */ return ret; }
@@ -637,6 +671,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data) goto out_put_task_struct; ret =arch_ptrace (child, request, addr, data); +if (ret || request !=PTRACE_DETACH ) +ptrace_unfreeze_traced (child); out_put_task_struct:put_task_struct (child);
@@ -752,8 +788,11 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, } ret =ptrace_check_attach (child, request ==PTRACE_KILL ); -if (!ret) +if (!ret) { ret =compat_arch_ptrace (child, request, addr, data); +if (ret || request !=PTRACE_DETACH ) +ptrace_unfreeze_traced (child); + } out_put_task_struct:put_task_struct (child);
kernel/signal.c +4 -0
@@ -1527,6 +1527,10 @@ static inline int may_ptrace_stop(void)* If SIGKILL was already sent before the caller unlocked * ->siglock we must see ->core_state != NULL. Otherwise it * is safe to enter schedule(). +* +* This is almost outdated, a task with the pending SIGKILL can't +* block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported +* after SIGKILL was already dequeued. */ if (unlikely (current->mm->core_state) &&unlikely (current->mm == current->parent->mm))
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
Quoted 9 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
race with SIGKILLFrom: Oleg Nesterov <[email protected]>
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
This patch actually introduce a regression in the Ubuntu kernel. You may want to include the fix below.
Cheers,
Signature · 1 line
Luis
Quoted 1 line
From
d06bbd59e5c7a0e0525af764a897028d6d352c36Mon Sep 17 00:00:00 2001
From: John Johansen <[email protected]>
Date: Thu, 21 Mar 2013 13:57:18 -0700
Subject: [PATCH] Fix ptrace when task is in task_is_stopped(), state
Quoted 1 line
From
d6a1da349c76ac2ebe4774d1da9fb7e660df01d3Mon Sep 17 00:00:00 2001
From: John Johansen <[email protected]>
Date: Thu, 21 Mar 2013 05:04:13 -0700
Subject: [PATCH] UBUNTU: SAUCE: Fix ptrace when task is in task_is_stopped()
state
This patch fixes a regression in ptrace, introduced by commit 9e74eb39 (backport of 9899d11f) which makes assumptions about ptrace behavior which are not true in the 2.6.32 kernel.
9899d11f makes the assumption that task_is_stopped() is not a valid state in ptrace because it is built on top of a series of patches which change how the TASK_STOPPED state is tracked (321fb561 which requires d79fdd6d and several other patches).
Because Lucid does not have the set of patches that make task_is_stopped() an invalid state in ptrace_check_attach, partially revert 9e74eb39 so that ptrace_check_attach() correctly handles task_is_stopped(). However we must replace the assignment of TASK_TRACED with __TASK_TRACED to ensure TASK_WAKEKILL is cleared.
--- kernel/ptrace.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
kernel/ptrace.c +9 -5
@@ -81,14 +81,18 @@ void __ptrace_unlink(struct task_struct *child) }/* Ensure that nothing can wake it up, even SIGKILL */ -static bool ptrace_freeze_traced (struct task_struct *task) +static bool ptrace_freeze_traced (struct task_struct *task,int kill) { -bool ret = false; +bool ret = true;spin_lock_irq (&task->sighand->siglock); -if (task_is_traced (task) && !__fatal_signal_pending (task)) { +if (task_is_stopped (task) && !__fatal_signal_pending (task)) task->state = __TASK_TRACED; - ret = true; +else if (!kill) { +if (task_is_traced (task) && !__fatal_signal_pending (task)) + task->state = __TASK_TRACED; +else + ret = false; }spin_unlock_irq (&task->sighand->siglock);
@@ -131,7 +135,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)* child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ -if (kill ||ptrace_freeze_traced (child)) +if (ptrace_freeze_traced (child, kill)) ret =0 ; }read_unlock (&tasklist_lock);
Signature · 1 line
1.8.1.2
Re: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
Quoted 9 lines · Luis Henriques
Quoted 7 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
race with SIGKILLFrom: Oleg Nesterov <[email protected]>
Quoted 7 lines
Quoted 2 lines
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
This patch actually introduce a regression in the Ubuntu kernel. You may want to include the fix below.
Thanks for letting me know, Luis. Queuing it now.
Willy
Oleg Nesterov
maintainerRe: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
In reply to Luis HenriquesQuoted 8 lines · Luis Henriques
Quoted 5 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
race with SIGKILL
Quoted 7 lines
Quoted 4 lines
From: Oleg Nesterov <[email protected]>
ptrace: ensure arch_ptrace/ptrace_request can never race with SIGKILL
This patch actually introduce a regression in the Ubuntu kernel. You may want to include the fix below.
Yes, 2.6.32 should also take care of TASK_STOPPED.
Quoted 26 lines
kernel/ptrace.c +8
-4@@ -81,14 +81,18 @@ void __ptrace_unlink(struct task_struct *child) }/* Ensure that nothing can wake it up, even SIGKILL */ -static bool ptrace_freeze_traced (struct task_struct *task) +static bool ptrace_freeze_traced (struct task_struct *task,int kill) { -bool ret = false; +bool ret = true;spin_lock_irq (&task->sighand->siglock); -if (task_is_traced (task) && !__fatal_signal_pending (task)) { +if (task_is_stopped (task) && !__fatal_signal_pending (task)) task->state = __TASK_TRACED; - ret = true; +else if (!kill) { +if (task_is_traced (task) && !__fatal_signal_pending (task)) + task->state = __TASK_TRACED; +else + ret = false; }spin_unlock_irq (&task->sighand->siglock);
kernel/ptrace.c int ptrace_check_attach(struct task_struct *child, int kill) · line 139
Quoted 6 lines
kernel/ptrace.c +1
-1@@ -131,7 +135,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)* child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ -if (kill ||ptrace_freeze_traced (child)) +if (ptrace_freeze_traced (child, kill)) ret =0 ;
I can't apply this patch, probably I misread it...
But it looks very wrong. It seems that ptrace_freeze_traced(kill => true) always succeeds? Even if task is TASK_RUNNING/UNINTERRUPTIBLE/etc ?
Note: I can make a _much_ simpler patch for 2.6.32, please let me know if you need it.
We can rely on sys_ptrace()->lock_kernel() and simply do lock/unlock if fatal_signal_pending() in ptrace_stop/do_signal_stop. This is not the same, this doesn't prevent wakeup(), but this should be enough.
Oleg.
Oleg Nesterov
maintainerRe: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
Quoted 7 lines · Oleg Nesterov
Note: I can make a _much_ simpler patch for 2.6.32, please let me know if you need it.
We can rely on sys_ptrace()->lock_kernel() and simply do lock/unlock if
fatal_signal_pending()in ptrace_stop/do_signal_stop. This is not the same, this doesn't preventwakeup(), but this should be enough.
Something like below. Untested/uncompiled. I think it should close the security problems.
Oleg.
kernel/signal.c +12 -0
@@ -1545,6 +1545,14 @@ static int sigkill_pending(struct task_ssigismember (&tsk->signal->shared_pending.signal,SIGKILL ); } +static void ptrace_sync (void ) +{ +if (fatal_signal_pending (current)) { +lock_kernel (); +unlock_kernel (); + } +} +/* * This must be called with current->sighand->siglock held. *
@@ -1603,6 +1611,7 @@ static void ptrace_stop(int exit_code, iread_unlock (&tasklist_lock);preempt_enable_no_resched ();schedule (); +ptrace_sync (); }else {/* * By the time we got the lock, our tracer went away.
@@ -1722,6 +1731,9 @@ static int do_signal_stop(int signr)schedule (); }while (try_to_freeze ()); +if (current->ptrace) +ptrace_sync (); +tracehook_finish_jctl (); current->exit_code =0 ;
Re: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
Hi Oleg,
Quoted 41 lines · Oleg Nesterov
Quoted 7 lines · Oleg Nesterov
Note: I can make a _much_ simpler patch for 2.6.32, please let me know if you need it.
We can rely on sys_ptrace()->lock_kernel() and simply do lock/unlock if
fatal_signal_pending()in ptrace_stop/do_signal_stop. This is not the same, this doesn't preventwakeup(), but this should be enough.Something like below. Untested/uncompiled. I think it should close the security problems.
Oleg.
kernel/signal.c +9
-0@@ -1545,6 +1545,14 @@ static int sigkill_pending(struct task_ssigismember (&tsk->signal->shared_pending.signal,SIGKILL ); } +static void ptrace_sync (void ) +{ +if (fatal_signal_pending (current)) { +lock_kernel (); +unlock_kernel (); + } +} +/* * This must be called with current->sighand->siglock held. * @@ -1603,6 +1611,7 @@ static void ptrace_stop(int exit_code, iread_unlock (&tasklist_lock);preempt_enable_no_resched ();schedule (); +ptrace_sync (); }else {/* * By the time we got the lock, our tracer went away.
kernel/signal.c static int do_signal_stop(int signr) · line 1739
Quoted 9 lines
kernel/signal.c +3
-0@@ -1722,6 +1731,9 @@ static int do_signal_stop(int signr)schedule (); }while (try_to_freeze ()); +if (current->ptrace) +ptrace_sync (); +tracehook_finish_jctl (); current->exit_code =0 ;
While I'm unable to tell whether the patch fixes the issue, I totally trust you on this. So if you have the time to propose a tested patch (or suggest me how to reliably test it), I'd gladly apply it instead.
Thanks!
Willy
Oleg Nesterov
maintainerRe: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
In reply to Oleg NesterovQuoted 33 lines · Oleg Nesterov
Quoted 22 lines · Luis Henriques
/* Ensure that nothing can wake it up, even SIGKILL */
kernel/ptrace.c +8
-4-static bool ptrace_freeze_traced (struct task_struct *task) +static bool ptrace_freeze_traced (struct task_struct *task,int kill) { -bool ret = false; +bool ret = true;spin_lock_irq (&task->sighand->siglock); -if (task_is_traced (task) && !__fatal_signal_pending (task)) { +if (task_is_stopped (task) && !__fatal_signal_pending (task)) task->state = __TASK_TRACED; - ret = true; +else if (!kill) { +if (task_is_traced (task) && !__fatal_signal_pending (task)) + task->state = __TASK_TRACED; +else + ret = false; }spin_unlock_irq (&task->sighand->siglock);kernel/ptrace.c int ptrace_check_attach(struct task_struct *child, int kill) · line 139
Quoted 6 lines
kernel/ptrace.c +1
-1@@ -131,7 +135,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)* child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ -if (kill ||ptrace_freeze_traced (child)) +if (ptrace_freeze_traced (child, kill)) ret =0 ;I can't apply this patch, probably I misread it...
Quoted 2 lines
But it looks very wrong. It seems that
ptrace_freeze_traced(kill => true)always succeeds? Even if task is TASK_RUNNING/UNINTERRUPTIBLE/etc ?
I am sorry for noise!
Yes I misread the patch. Now I actually applied both patches and I believe the fix is fine.
ptrace_freeze_traced(kill => true) succeeds, but this is correct. Somehow I confused this case with !kill.
Oleg.
Re: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never
Quoted 37 lines · Oleg Nesterov
Quoted 33 lines · Oleg Nesterov
Quoted 22 lines · Luis Henriques
/* Ensure that nothing can wake it up, even SIGKILL */
kernel/ptrace.c +8
-4-static bool ptrace_freeze_traced (struct task_struct *task) +static bool ptrace_freeze_traced (struct task_struct *task,int kill) { -bool ret = false; +bool ret = true;spin_lock_irq (&task->sighand->siglock); -if (task_is_traced (task) && !__fatal_signal_pending (task)) { +if (task_is_stopped (task) && !__fatal_signal_pending (task)) task->state = __TASK_TRACED; - ret = true; +else if (!kill) { +if (task_is_traced (task) && !__fatal_signal_pending (task)) + task->state = __TASK_TRACED; +else + ret = false; }spin_unlock_irq (&task->sighand->siglock);kernel/ptrace.c int ptrace_check_attach(struct task_struct *child, int kill) · line 139
Quoted 6 lines
kernel/ptrace.c +1
-1@@ -131,7 +135,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)* child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ -if (kill ||ptrace_freeze_traced (child)) +if (ptrace_freeze_traced (child, kill)) ret =0 ;I can't apply this patch, probably I misread it...
Quoted 2 lines
But it looks very wrong. It seems that
ptrace_freeze_traced(kill => true)always succeeds? Even if task is TASK_RUNNING/UNINTERRUPTIBLE/etc ?
Quoted 7 lines
I am sorry for noise!
Yes I misread the patch. Now I actually applied both patches and I believe the fix is fine.
ptrace_freeze_traced(kill => true)succeeds, but this is correct. Somehow I confused this case with !kill.
Great, thanks a lot for clarifying this, Oleg.
Cheers,
Signature · 1 line
Luis
PATCH 21/184 kernel/signal.c: stop info leak via the tkill and
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
the tgkill syscalls
From: Emese Revfy <[email protected]>
commit b9e146d8eb3b9ecae5086d373b50fa0c1f3e7f0f upstream.
This fixes a kernel memory contents leak via the tkill and tgkill syscalls for compat processes.
This is visible in the siginfo_t->_sifields._rt.si_sigval.sival_ptr field when handling signals delivered from tkill.
The place of the infoleak:
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
...
put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
...
}--- kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/signal.c +1 -1
@@ -2301,7 +2301,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)static int do_tkill (pid_t tgid,pid_t pid,int sig) { -struct siginfo info; +struct siginfo info = {}; info.si_signo = sig; info.si_errno =0 ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 22/184 signal: Define __ARCH_HAS_SA_RESTORER so we know
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
whether to clear sa_restorer
From: Ben Hutchings <[email protected]>
Vaguely based on upstream commit 574c4866e33d 'consolidate kernel-side struct sigaction declarations'.
flush_signal_handlers() needs to know whether sigaction::sa_restorer is defined, not whether SA_RESTORER is defined. Define the __ARCH_HAS_SA_RESTORER macro to indicate this.
--- arch/arm/include/asm/signal.h | 1 + arch/avr32/include/asm/signal.h | 1 + arch/cris/include/asm/signal.h | 1 + arch/h8300/include/asm/signal.h | 1 + arch/m32r/include/asm/signal.h | 1 + arch/m68k/include/asm/signal.h | 1 + arch/mn10300/include/asm/signal.h | 1 + arch/powerpc/include/asm/signal.h | 1 + arch/s390/include/asm/signal.h | 1 + arch/sparc/include/asm/signal.h | 1 + arch/x86/include/asm/signal.h | 2 ++ arch/xtensa/include/asm/signal.h | 1 + include/asm-generic/signal.h | 4 ++++ 13 files changed, 17 insertions(+)
arch/arm/include/asm/signal.h +1 -0
@@ -127,6 +127,7 @@ struct sigaction {__sigrestore_t sa_restorer;sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/avr32/include/asm/signal.h +1 -0
@@ -128,6 +128,7 @@ struct sigaction {__sigrestore_t sa_restorer;sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/cris/include/asm/signal.h +1 -0
@@ -122,6 +122,7 @@ struct sigaction {void (*sa_restorer)(void );sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/h8300/include/asm/signal.h +1 -0
@@ -121,6 +121,7 @@ struct sigaction {void (*sa_restorer)(void );sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/m32r/include/asm/signal.h +1 -0
@@ -123,6 +123,7 @@ struct sigaction {__sigrestore_t sa_restorer;sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/m68k/include/asm/signal.h +1 -0
@@ -119,6 +119,7 @@ struct sigaction {__sigrestore_t sa_restorer;sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/mn10300/include/asm/signal.h +1 -0
@@ -131,6 +131,7 @@ struct sigaction {__sigrestore_t sa_restorer;sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/powerpc/include/asm/signal.h +1 -0
@@ -109,6 +109,7 @@ struct sigaction {__sigrestore_t sa_restorer;sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/s390/include/asm/signal.h +1 -0
@@ -131,6 +131,7 @@ struct sigaction {void (*sa_restorer)(void );sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
arch/sparc/include/asm/signal.h +1 -0
@@ -191,6 +191,7 @@ struct __old_sigaction {unsigned long sa_flags;void (*sa_restorer)(void );/* not used by Linux/SPARC yet */ }; +#define __ARCH_HAS_SA_RESTORER typedef struct sigaltstack { void __user *ss_sp;
arch/x86/include/asm/signal.h +2 -0
@@ -125,6 +125,8 @@ typedef unsigned long sigset_t;extern void do_notify_resume (struct pt_regs *,void *,__u32 );# endif /* __KERNEL__ */ +#define __ARCH_HAS_SA_RESTORER +#ifdef __i386__# ifdef __KERNEL__ struct old_sigaction {
arch/xtensa/include/asm/signal.h +1 -0
@@ -133,6 +133,7 @@ struct sigaction {void (*sa_restorer)(void );sigset_t sa_mask;/* mask last for extensibility */ }; +#define __ARCH_HAS_SA_RESTORERstruct k_sigaction {struct sigaction sa;
include/asm-generic/signal.h +4 -0
@@ -99,6 +99,10 @@ typedef unsigned long old_sigset_t;#include <asm-generic/signal-defs.h> +#ifdef SA_RESTORER +#define __ARCH_HAS_SA_RESTORER +#endif +struct sigaction {__sighandler_t sa_handler;unsigned long sa_flags;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 23/184 kernel/signal.c: use __ARCH_HAS_SA_RESTORER instead
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
of SA_RESTORER
From: Andrew Morton <[email protected]>
commit 522cff142d7d2f9230839c9e1f21a4d8bcc22a4a upstream.
__ARCH_HAS_SA_RESTORER is the preferred conditional for use in 3.9 and later kernels, per Kees.
--- kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/signal.c +1 -1
@@ -320,7 +320,7 @@ flush_signal_handlers(struct task_struct *t, int force_default)if (force_default || ka->sa.sa_handler !=SIG_IGN ) ka->sa.sa_handler =SIG_DFL ; ka->sa.sa_flags =0 ; -#ifdef SA_RESTORER +#ifdef __ARCH_HAS_SA_RESTORER ka->sa.sa_restorer =NULL ;#endif sigemptyset (&ka->sa.sa_mask);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 24/184 wake_up_process() should be never used to wakeup a
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
TASK_STOPPED/TRACED task
From: Oleg Nesterov <[email protected]>
wake_up_process() should be never used to wakeup a TASK_STOPPED/TRACED task
CVE-2013-0871
wake_up_process() should never wakeup a TASK_STOPPED/TRACED task. Change it to use TASK_NORMAL and add the WARN_ON().
TASK_ALL has no other users, probably can be killed.
Conflicts:
kernel/sched/core.c
--- kernel/sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/sched.c +2 -1
@@ -2618,7 +2618,8 @@ out:*/ int wake_up_process (struct task_struct *p) { -return try_to_wake_up (p,TASK_ALL ,0 ); +WARN_ON (task_is_stopped_or_traced (p)); +return try_to_wake_up (p,TASK_NORMAL ,0 ); }EXPORT_SYMBOL (wake_up_process);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 25/184 coredump: prevent double-free on an error path in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
core dumper
From: Denys Vlasenko <[email protected]>
commit f34f9d186df35e5c39163444c43b4fc6255e39c5 upstream.
In !CORE_DUMP_USE_REGSET case, if elf_note_info_init fails to allocate memory for info->fields, it frees already allocated stuff and returns error to its caller, fill_note_info. Which in turn returns error to its caller, elf_core_dump. Which jumps to cleanup label and calls free_note_info, which will happily try to free all info->fields again. BOOM.
This is the fix.
--- fs/binfmt_elf.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-)
fs/binfmt_elf.c +4 -15
@@ -1699,30 +1699,19 @@ static int elf_note_info_init(struct elf_note_info *info)return 0 ; info->psinfo =kmalloc (sizeof (*info->psinfo),GFP_KERNEL );if (!info->psinfo) - goto notes_free; +return 0 ; info->prstatus =kmalloc (sizeof (*info->prstatus),GFP_KERNEL );if (!info->prstatus) - goto psinfo_free; +return 0 ; info->fpu =kmalloc (sizeof (*info->fpu),GFP_KERNEL );if (!info->fpu) - goto prstatus_free; +return 0 ;#ifdef ELF_CORE_COPY_XFPREGS info->xfpu =kmalloc (sizeof (*info->xfpu),GFP_KERNEL );if (!info->xfpu) - goto fpu_free; +return 0 ;#endif return 1 ; -#ifdef ELF_CORE_COPY_XFPREGS - fpu_free: -kfree (info->fpu); -#endif - prstatus_free: -kfree (info->prstatus); - psinfo_free: -kfree (info->psinfo); - notes_free: -kfree (info->notes); -return 0 ; } static int fill_note_info(struct elfhdr *elf, int phdrs,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 26/184 kernel/sys.c: call disable_nonboot_cpus() in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
kernel_restart()
From: Shawn Guo <[email protected]>
commit f96972f2dc6365421cf2366ebd61ee4cf060c8d5 upstream.
As kernel_power_off() calls disable_nonboot_cpus(), we may also want to have kernel_restart() call disable_nonboot_cpus(). Doing so can help machines that require boot cpu be the last alive cpu during reboot to survive with kernel restart.
This fixes one reboot issue seen on imx6q (Cortex-A9 Quad). The machine requires that the restart routine be run on the primary cpu rather than secondary ones. Otherwise, the secondary core running the restart routine will fail to come to online after reboot.
--- kernel/sys.c | 1 + 1 file changed, 1 insertion(+)
kernel/sys.c +1 -0
@@ -303,6 +303,7 @@ void kernel_restart_prepare(char *cmd)void kernel_restart (char *cmd) {kernel_restart_prepare (cmd); +disable_nonboot_cpus ();if (!cmd)printk (KERN_EMERG "Restarting system.\n" );else
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 27/184 ring-buffer: Fix race between integrity check and
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
readers
From: Steven Rostedt <[email protected]>
commit 9366c1ba13fbc41bdb57702e75ca4382f209c82f upstream.
The function rb_check_pages() was added to make sure the ring buffer's pages were sane. This check is done when the ring buffer size is modified as well as when the iterator is released (closing the "trace" file), as that was considered a non fast path and a good place to do a sanity check.
The problem is that the check does not have any locks around it. If one process were to read the trace file, and another were to read the raw binary file, the check could happen while the reader is reading the file.
The issues with this is that the check requires to clear the HEAD page before doing the full check and it restores it afterward. But readers require the HEAD page to exist before it can read the buffer, otherwise it gives a nasty warning and disables the buffer.
By adding the reader lock around the check, this keeps the race from happening.
--- kernel/trace/ring_buffer.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/ring_buffer.c +2 -0
@@ -2876,6 +2876,8 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)* Splice the empty reader page into the list around the head. */ reader =rb_set_head_page (cpu_buffer); +if (!reader) + goto out; cpu_buffer->reader_page->list.next = reader->list.next; cpu_buffer->reader_page->list.prev = reader->list.prev;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Steven Rostedt
maintainerRe: [ 027/184] ring-buffer: Fix race between integrity check and
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
readersFrom: Steven Rostedt <[email protected]>
commit
9366c1ba13fbc41bdb57702e75ca4382f209c82fupstream.
This isn't the right commit (thanks to Ben for bringing this to my attention).
That this commit SHA1 matches the change log but not the change. According to git blame, the change below is from:
54f7be5b831254199522523ccab4c3d954bbf576
ring-buffer: Fix NULL pointer if rb_set_head_page() fails
-- Steve
Quoted 40 lines
The function
rb_check_pages()was added to make sure the ring buffer's pages were sane. This check is done when the ring buffer size is modified as well as when the iterator is released (closing the "trace" file), as that was considered a non fast path and a good place to do a sanity check.The problem is that the check does not have any locks around it. If one process were to read the trace file, and another were to read the raw binary file, the check could happen while the reader is reading the file.
The issues with this is that the check requires to clear the HEAD page before doing the full check and it restores it afterward. But readers require the HEAD page to exist before it can read the buffer, otherwise it gives a nasty warning and disables the buffer.
By adding the reader lock around the check, this keeps the race from happening.
Signed-off-by Steven Rostedt <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>Signed-off-by Willy Tarreau <[email protected]>--- kernel/trace/ring_buffer.c | 2 ++ 1 file changed, 2 insertions(+)kernel/trace/ring_buffer.c +2
-0@@ -2876,6 +2876,8 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)* Splice the empty reader page into the list around the head. */ reader =rb_set_head_page (cpu_buffer); +if (!reader) + goto out; cpu_buffer->reader_page->list.next = reader->list.next; cpu_buffer->reader_page->list.prev = reader->list.prev;
Re: [ 027/184] ring-buffer: Fix race between integrity check and
Quoted 10 lines · Steven Rostedt
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
readersFrom: Steven Rostedt <[email protected]>
commit
9366c1ba13fbc41bdb57702e75ca4382f209c82fupstream.
Quoted 8 lines
This isn't the right commit (thanks to Ben for bringing this to my attention).
That this commit SHA1 matches the change log but not the change. According to git blame, the change below is from:
54f7be5b831254199522523ccab4c3d954bbf576
ring-buffer: Fix NULL pointer ifrb_set_head_page()fails
Ah yes indeed, thank you for bringing this up, Steve.
Willy
PATCH 28/184 genalloc: stop crashing the system when destroying a
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
pool
From: Thadeu Lima de Souza Cascardo <[email protected]>
commit eedce141cd2dad8d0cefc5468ef41898949a7031 upstream.
The genalloc code uses the bitmap API from include/linux/bitmap.h and lib/bitmap.c, which is based on long values. Both bitmap_set from lib/bitmap.c and bitmap_set_ll, which is the lockless version from genalloc.c, use BITMAP_LAST_WORD_MASK to set the first bits in a long in the bitmap.
That one uses (1 << bits) - 1, 0b111, if you are setting the first three bits. This means that the API counts from the least significant bits (LSB from now on) to the MSB. The LSB in the first long is bit 0, then. The same works for the lookup functions.
The genalloc code uses longs for the bitmap, as it should. In include/linux/genalloc.h, struct gen_pool_chunk has unsigned long bits[0] as its last member. When allocating the struct, genalloc should reserve enough space for the bitmap. This should be a proper number of longs that can fit the amount of bits in the bitmap.
However, genalloc allocates an integer number of bytes that fit the amount of bits, but may not be an integer amount of longs. 9 bytes, for example, could be allocated for 70 bits.
This is a problem in itself if the Least Significat Bit in a long is in the byte with the largest address, which happens in Big Endian machines. This means genalloc is not allocating the byte in which it will try to set or check for a bit.
This may end up in memory corruption, where genalloc will try to set the bits it has not allocated. In fact, genalloc may not set these bits because it may find them already set, because they were not zeroed since they were not allocated. And that's what causes a BUG when gen_pool_destroy is called and check for any set bits.
What really happens is that genalloc uses kmalloc_node with __GFP_ZERO on gen_pool_add_virt. With SLAB and SLUB, this means the whole slab will be cleared, not only the requested bytes. Since struct gen_pool_chunk has a size that is a multiple of 8, and slab sizes are multiples of 8, we get lucky and allocate and clear the right amount of bytes.
Hower, this is not the case with SLOB or with older code that did memset after allocating instead of using __GFP_ZERO.
So, a simple module as this (running 3.6.0), will cause a crash when rmmod'ed.
[root@phantom-lp2 foo]# cat foo.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/genalloc.h>
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1"); static struct gen_pool *foo_pool;
static __init int foo_init(void)
{
int ret;
foo_pool = gen_pool_create(10, -1);
if (!foo_pool)
return -ENOMEM;
ret = gen_pool_add(foo_pool, 0xa0000000, 32 << 10, -1);
if (ret) {
gen_pool_destroy(foo_pool);
return ret;
}
return 0;
}
static __exit void foo_exit(void)
{
gen_pool_destroy(foo_pool);
} module_init(foo_init);
module_exit(foo_exit);
[root@phantom-lp2 foo]# zcat /proc/config.gz | grep SLOB CONFIG_SLOB=y
[root@phantom-lp2 foo]# insmod ./foo.ko [root@phantom-lp2 foo]# rmmod foo
------------[ cut here ]------------
kernel BUG at lib/genalloc.c:243!
cpu 0x4: Vector: 700 (Program Check) at [c0000000bb0e7960]
pc: c0000000003cb50c: .gen_pool_destroy+0xac/0x110
lr: c0000000003cb4fc: .gen_pool_destroy+0x9c/0x110
sp: c0000000bb0e7be0
msr: 8000000000029032
current = 0xc0000000bb0e0000
paca = 0xc000000006d30e00 softe: 0 irq_happened: 0x01
pid = 13044, comm = rmmod
kernel BUG at lib/genalloc.c:243!
[c0000000bb0e7ca0] d000000004b00020 .foo_exit+0x20/0x38 [foo]
[c0000000bb0e7d20] c0000000000dff98 .SyS_delete_module+0x1a8/0x290
[c0000000bb0e7e30] c0000000000097d4 syscall_exit+0x0/0x94
--- Exception: c00 (System Call) at 000000800753d1a0
SP (fffd0b0e640) is in userspace--- lib/genalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/genalloc.c +1 -1
@@ -52,7 +52,7 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,struct gen_pool_chunk *chunk;int nbits = size >> pool->min_alloc_order;int nbytes =sizeof (struct gen_pool_chunk ) + - (nbits +BITS_PER_BYTE -1 ) /BITS_PER_BYTE ; +BITS_TO_LONGS (nbits) *sizeof (long ); chunk =kmalloc_node (nbytes,GFP_KERNEL | __GFP_ZERO, nid);if (unlikely (chunk ==NULL ))
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 29/184 kernel/resource.c: fix stack overflow in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
__reserve_region_with_split()
From: T Makphaibulchoke <[email protected]>
commit 4965f5667f36a95b41cda6638875bc992bd7d18b upstream.
Using a recursive call add a non-conflicting region in __reserve_region_with_split() could result in a stack overflow in the case that the recursive calls are too deep. Convert the recursive calls to an iterative loop to avoid the problem.
Tested on a machine containing 135 regions. The kernel no longer panicked with stack overflow.
Also tested with code arbitrarily adding regions with no conflict, embedding two consecutive conflicts and embedding two non-consecutive conflicts.
--- kernel/resource.c | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-)
kernel/resource.c +38 -12
@@ -533,6 +533,7 @@ static void __init __reserve_region_with_split(struct resource *root,struct resource *parent = root;struct resource *conflict;struct resource *res =kzalloc (sizeof (*res),GFP_ATOMIC ); +struct resource *next_res =NULL ;if (!res)return ;
@@ -542,21 +543,46 @@ static void __init __reserve_region_with_split(struct resource *root, res->end = end; res->flags =IORESOURCE_BUSY ; - conflict =__request_resource (parent, res); -if (!conflict) -return ; +while (1 ) { -/* failed, split and try again */ -kfree (res); + conflict =__request_resource (parent, res); +if (!conflict) { +if (!next_res) +break ; + res = next_res; + next_res =NULL ; +continue ; + } -/* conflict covered whole area */ -if (conflict->start <= start && conflict->end >= end) -return ; +/* conflict covered whole area */ +if (conflict->start <= res->start && + conflict->end >= res->end) { +kfree (res); +WARN_ON (next_res); +break ; + } + +/* failed, split and try again */ +if (conflict->start > res->start) { + end = res->end; + res->end = conflict->start -1 ; +if (conflict->end < end) { + next_res =kzalloc (sizeof (*next_res), +GFP_ATOMIC ); +if (!next_res) { +kfree (res); +break ; + } + next_res->name = name; + next_res->start = conflict->end +1 ; + next_res->end = end; + next_res->flags =IORESOURCE_BUSY ; + } + }else { + res->start = conflict->end +1 ; + } + } -if (conflict->start > start) -__reserve_region_with_split (root, start, conflict->start-1 , name); -if (conflict->end < end) -__reserve_region_with_split (root, conflict->end+1 , end, name); } void __init reserve_region_with_split(struct resource *root,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 30/184 Driver core: treat unregistered bus_types as having
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
no devices
From: Bjorn Helgaas <[email protected]>
commit 4fa3e78be7e985ca814ce2aa0c09cbee404efcf7 upstream.
A bus_type has a list of devices (klist_devices), but the list and the subsys_private structure that contains it are not initialized until the bus_type is registered with bus_register().
The panic/reboot path has fixups that look up devices in pci_bus_type. If we panic before registering pci_bus_type, the bus_type exists but the list does not, so mach_reboot_fixups() trips over a null pointer and panics again:
mach_reboot_fixups
pci_get_device
..
bus_find_device(&pci_bus_type, ...)
bus->p is NULLJoonsoo reported a problem when panicking before PCI was initialized. I think this patch should be sufficient to replace the patch he posted
here: https://lkml.org/lkml/2012/12/28/75 ("[PATCH] x86, reboot: skip reboot_fixups in early boot phase")
--- drivers/base/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/base/bus.c +2 -2
@@ -289,7 +289,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,struct device *dev;int error =0 ; -if (!bus) +if (!bus || !bus->p)return -EINVAL ; klist_iter_init_node(&bus->p->klist_devices, &i,
@@ -323,7 +323,7 @@ struct device *bus_find_device(struct bus_type *bus,struct klist_iter i;struct device *dev; -if (!bus) +if (!bus || !bus->p)return NULL ; klist_iter_init_node(&bus->p->klist_devices, &i,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 31/184 cgroup: remove incorrect dget/dput() pair in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
cgroup_create_dir()
From: Tejun Heo <[email protected]>
commit 175431635ec09b1d1bba04979b006b99e8305a83 upstream.
cgroup_create_dir() does weird dancing with dentry refcnt. On success, it gets and then puts it achieving nothing. On failure, it puts but there isn't no matching get anywhere leading to the following oops if cgroup_create_file() fails for whatever reason.
------------[ cut here ]------------ kernel BUG at /work/os/work/fs/dcache.c:552! invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: CPU 2 Pid: 697, comm: mkdir Not tainted 3.7.0-rc4-work+ #3 Bochs Bochs RIP: 0010:[<ffffffff811d9c0c>] [<ffffffff811d9c0c>] dput+0x1dc/0x1e0 RSP: 0018:ffff88001a3ebef8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88000e5b1ef8 RCX: 0000000000000403 RDX: 0000000000000303 RSI: 2000000000000000 RDI: ffff88000e5b1f58 RBP: ffff88001a3ebf18 R08: ffffffff82c76960 R09: 0000000000000001 R10: ffff880015022080 R11: ffd9bed70f48a041 R12: 00000000ffffffea R13: 0000000000000001 R14: ffff88000e5b1f58 R15: 00007fff57656d60 FS: 00007ff05fcb3800(0000) GS:ffff88001fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000004046f0 CR3: 000000001315f000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process mkdir (pid: 697, threadinfo ffff88001a3ea000, task ffff880015022080) Stack: ffff88001a3ebf48 00000000ffffffea 0000000000000001 0000000000000000 ffff88001a3ebf38 ffffffff811cc889 0000000000000001 ffff88000e5b1ef8 ffff88001a3ebf68 ffffffff811d1fc9 ffff8800198d7f18 ffff880019106ef8 Call Trace: [<ffffffff811cc889>] done_path_create+0x19/0x50 [<ffffffff811d1fc9>] sys_mkdirat+0x59/0x80 [<ffffffff811d2009>] sys_mkdir+0x19/0x20 [<ffffffff81be1e02>] system_call_fastpath+0x16/0x1b Code: 00 48 8d 90 18 01 00 00 48 89 93 c0 00 00 00 4c 89 a0 18 01 00 00 48 8b 83 a0 00 00 00 83 80 28 01 00 00 01 e8 e6 6f a0 00 eb 92 <0f> 0b 66 90 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 49 89 fe 41 RIP [<ffffffff811d9c0c>] dput+0x1dc/0x1e0 RSP <ffff88001a3ebef8> ---[ end trace 1277bcfd9561ddb0 ]---
Fix it by dropping the unnecessary dget/dput() pair.
--- kernel/cgroup.c | 2 -- 1 file changed, 2 deletions(-)
kernel/cgroup.c +0 -2
@@ -1992,9 +1992,7 @@ static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry, dentry->d_fsdata = cgrp;inc_nlink (parent->d_inode);rcu_assign_pointer (cgrp->dentry, dentry); -dget (dentry); } -dput (dentry);return error; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 32/184 Fix a dead loop in async_synchronize_full()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Li Zhong <[email protected]>
[Fixed upstream by commits 2955b47d2c1983998a8c5915cb96884e67f7cb53 and a4683487f90bfe3049686fc5c566bdc1ad03ace6 from Dan Williams, but they are much more intrusive than this tiny fix, according to Andrew - gregkh]
This patch tries to fix a dead loop in async_synchronize_full(), which could be seen when preemption is disabled on a single cpu machine.
void async_synchronize_full(void)
{
do {
async_synchronize_cookie(next_cookie);
} while (!list_empty(&async_running) || !list_empty(&async_pending));
}
async_synchronize_cookie() calls async_synchronize_cookie_domain() with &async_running as the default domain to synchronize.
However, there might be some works in the async_pending list from other domains. On a single cpu system, without preemption, there is no chance for the other works to finish, so async_synchronize_full() enters a dead loop.
It seems async_synchronize_full() wants to synchronize all entries in all running lists(domains), so maybe we could just check the entry_count to know whether all works are finished.
Currently, async_synchronize_cookie_domain() expects a non-NULL running list ( if NULL, there would be NULL pointer dereference ), so maybe a NULL pointer could be used as an indication for the functions to synchronize all works in all domains.
--- kernel/async.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
kernel/async.c +9 -4
@@ -93,6 +93,13 @@ static async_cookie_t __lowest_in_progress(struct list_head *running) {struct async_entry *entry; +if (!running) {/* just check the entry count */ +if (atomic_read (&entry_count)) +return 0 ;/* smaller than any cookie */ +else +return next_cookie; + } +if (!list_empty (running)) { entry =list_first_entry (running, struct async_entry, list);
@@ -248,9 +255,7 @@ EXPORT_SYMBOL_GPL(async_schedule_domain);*/ void async_synchronize_full (void ) { -do { -async_synchronize_cookie (next_cookie); - }while (!list_empty (&async_running) || !list_empty (&async_pending)); +async_synchronize_cookie_domain (next_cookie,NULL ); }EXPORT_SYMBOL_GPL (async_synchronize_full);
@@ -270,7 +275,7 @@ EXPORT_SYMBOL_GPL(async_synchronize_full_domain);/** * async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing * @cookie: async_cookie_t to use as checkpoint -* @running: running list to synchronize on +* @running: running list to synchronize on, NULL indicates all lists * * This function waits until all asynchronous function calls for the * synchronization domain specified by the running list @list submitted
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 33/184 tracing: Dont call page_to_pfn() if page is NULL
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Wen Congyang <[email protected]>
commit 85f2a2ef1d0ab99523e0b947a2b723f5650ed6aa upstream.
When allocating memory fails, page is NULL. page_to_pfn() will cause the kernel panicked if we don't use sparsemem vmemmap.
--- include/trace/events/kmem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/trace/events/kmem.h +2 -2
@@ -293,7 +293,7 @@ TRACE_EVENT(mm_page_alloc,TP_printk ("page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s" , __entry->page, -page_to_pfn (__entry->page), + __entry->page ?page_to_pfn (__entry->page) :0 , __entry->order, __entry->migratetype,show_gfp_flags (__entry->gfp_flags))
@@ -319,7 +319,7 @@ TRACE_EVENT(mm_page_alloc_zone_locked,TP_printk ("page=%p pfn=%lu order=%u migratetype=%d percpu_refill=%d" , __entry->page, -page_to_pfn (__entry->page), + __entry->page ?page_to_pfn (__entry->page) :0 , __entry->order, __entry->migratetype, __entry->order ==0 )
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 34/184 tracing: Fix double free when function profile init
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
failed
From: Namhyung Kim <[email protected]>
commit 83e03b3fe4daffdebbb42151d5410d730ae50bd1 upstream.
On the failure path, stat->start and stat->pages will refer same page. So it'll attempt to free the same page again and get kernel panic.
--- kernel/trace/ftrace.c | 1 - 1 file changed, 1 deletion(-)
kernel/trace/ftrace.c +0 -1
@@ -469,7 +469,6 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat)free_page (tmp); } -free_page ((unsigned long )stat->pages); stat->pages =NULL ; stat->start =NULL ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 35/184 hugetlb: fix resv_map leak in error path
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Dave Hansen <[email protected]>
commit c50ac050811d6485616a193eb0f37bfbd191cc89 upstream
When called for anonymous (non-shared) mappings, hugetlb_reserve_pages() does a resv_map_alloc(). It depends on code in hugetlbfs's vm_ops->close() to release that allocation.
However, in the mmap() failure path, we do a plain unmap_region() without the remove_vma() which actually calls vm_ops->close().
This is a decent fix. This leak could get reintroduced if new code (say, after hugetlb_reserve_pages() in hugetlbfs_file_mmap()) decides to return an error. But, I think it would have to unroll the reservation anyway.
Christoph's test case:
http://marc.info/?l=linux-mm&m=133728900729735
This patch applies to 3.4 and later. A version for earlier kernels is at
https://lkml.org/lkml/2012/5/22/418.
--- mm/hugetlb.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
mm/hugetlb.c +22 -6
@@ -1772,6 +1772,15 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma)kref_get (&reservations->refs); } +static void resv_map_put (struct vm_area_struct *vma) +{ +struct resv_map *reservations =vma_resv_map (vma); + +if (!reservations) +return ; +kref_put (&reservations->refs, resv_map_release); +} +static void hugetlb_vm_op_close (struct vm_area_struct *vma) {struct hstate *h =hstate_vma (vma);
@@ -1788,7 +1797,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) reserve = (end - start) -region_count (&reservations->regions, start, end); -kref_put (&reservations->refs, resv_map_release); +resv_map_put (vma);if (reserve) {hugetlb_acct_memory (h, -reserve);
@@ -2472,12 +2481,16 @@ int hugetlb_reserve_pages(struct inode *inode,set_vma_resv_flags (vma,HPAGE_RESV_OWNER ); } -if (chg <0 ) -return chg; +if (chg <0 ) { + ret = chg; + goto out_err; + }/* There must be enough pages in the subpool for the mapping */ -if (hugepage_subpool_get_pages (spool, chg)) -return -ENOSPC ; +if (hugepage_subpool_get_pages (spool, chg)) { + ret = -ENOSPC ; + goto out_err; + }/* * Check enough hugepages are available for the reservation.
@@ -2486,7 +2499,7 @@ int hugetlb_reserve_pages(struct inode *inode, ret =hugetlb_acct_memory (h, chg);if (ret <0 ) {hugepage_subpool_put_pages (spool, chg); -return ret; + goto out_err; }/*
@@ -2503,6 +2516,9 @@ int hugetlb_reserve_pages(struct inode *inode,if (!vma || vma->vm_flags &VM_MAYSHARE )region_add (&inode->i_mapping->private_list, from, to);return 0 ; +out_err: +resv_map_put (vma); +return ret; }void hugetlb_unreserve_pages (struct inode *inode,long offset,long freed)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 36/184 mm: fix vma_resv_map() NULL pointer
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Dave Hansen <[email protected]>
commit 4523e1458566a0e8ecfaff90f380dd23acc44d27 upstream
hugetlb_reserve_pages() can be used for either normal file-backed hugetlbfs mappings, or MAP_HUGETLB. In the MAP_HUGETLB, semi-anonymous mode, there is not a VMA around. The new call to resv_map_put() assumed that there was, and resulted in a NULL pointer dereference:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000030
IP: vma_resv_map+0x9/0x30
PGD 141453067 PUD 1421e1067 PMD 0
Oops: 0000 [#1] PREEMPT SMP
...
Pid: 14006, comm: trinity-child6 Not tainted 3.4.0+ #36
RIP: vma_resv_map+0x9/0x30
...
Process trinity-child6 (pid: 14006, threadinfo ffff8801414e0000, task ffff8801414f26b0)
Call Trace:
resv_map_put+0xe/0x40
hugetlb_reserve_pages+0xa6/0x1d0
hugetlb_file_setup+0x102/0x2c0
newseg+0x115/0x360
ipcget+0x1ce/0x310
sys_shmget+0x5a/0x60
system_call_fastpath+0x16/0x1bThis was reported by Dave Jones, but was reproducible with the libhugetlbfs test cases, so shame on me for not running them in the first place.
With this, the oops is gone, and the output of libhugetlbfs's run_tests.py is identical to plain 3.4 again.
[ Marked for stable, since this was introduced by commit c50ac050811d
("hugetlb: fix resv_map leak in error path") which was also marked for stable ]
--- mm/hugetlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
mm/hugetlb.c +2 -1
@@ -2517,7 +2517,8 @@ int hugetlb_reserve_pages(struct inode *inode,region_add (&inode->i_mapping->private_list, from, to);return 0 ; out_err: -resv_map_put (vma); +if (vma) +resv_map_put (vma);return ret; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 37/184 mm: Fix PageHead when !CONFIG_PAGEFLAGS_EXTENDED
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Christoffer Dall <[email protected]>
commit ad4b3fb7ff9940bcdb1e4cd62bd189d10fa636ba upstream.
Unfortunately with !CONFIG_PAGEFLAGS_EXTENDED, (!PageHead) is false, and (PageHead) is true, for tail pages. If this is indeed the intended behavior, which I doubt because it breaks cache cleaning on some ARM systems, then the nomenclature is highly problematic.
This patch makes sure PageHead is only true for head pages and PageTail is only true for tail pages, and neither is true for non-compound pages.
[ This buglet seems ancient - seems to have been introduced back in Apr
2008 in commit 6a1e7f777f61: "pageflags: convert to the use of new macros". And the reason nobody noticed is because the PageHead() tests are almost all about just sanity-checking, and only used on pages that are actual page heads. The fact that the old code returned
true for tail pages too was thus not really noticeable. - Linus ]
--- include/linux/page-flags.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
include/linux/page-flags.h +7 -1
@@ -362,7 +362,7 @@ static inline int PageCompound(struct page *page)* pages on the LRU and/or pagecache. */ TESTPAGEFLAG(Compound, compound) -__PAGEFLAG (Head, compound) +__SETPAGEFLAG(Head, compound) __CLEARPAGEFLAG(Head, compound)/* * PG_reclaim is used in combination with PG_compound to mark the
@@ -374,8 +374,14 @@ __PAGEFLAG(Head, compound)* PG_compound & PG_reclaim => Tail page * PG_compound & ~PG_reclaim => Head page */ +#define PG_head_mask ((1L << PG_compound))#define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim)) +static inline int PageHead (struct page *page) +{ +return ((page->flags & PG_head_tail_mask) == PG_head_mask); +} +static inline int PageTail (struct page *page) {return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 38/184 mm: bugfix: set current->reclaim_state to NULL while
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
returning from kswapd()
From: Takamori Yamaguchi <[email protected]>
commit b0a8cc58e6b9aaae3045752059e5e6260c0b94bc upstream.
In kswapd(), set current->reclaim_state to NULL before returning, as current->reclaim_state holds reference to variable on kswapd()'s stack.
In rare cases, while returning from kswapd() during memory offlining, __free_slab() and freepages() can access the dangling pointer of current->reclaim_state.
--- mm/vmscan.c | 2 ++ 1 file changed, 2 insertions(+)
mm/vmscan.c +2 -0
@@ -2241,6 +2241,8 @@ static int kswapd(void *p)balance_pgdat (pgdat, order); } } + + current->reclaim_state =NULL ;return 0 ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 39/184 mm: fix invalidate_complete_page2() lock ordering
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Hugh Dickins <[email protected]>
commit ec4d9f626d5908b6052c2973f37992f1db52e967 upstream.
In fuzzing with trinity, lockdep protested "possible irq lock inversion dependency detected" when isolate_lru_page() reenabled interrupts while still holding the supposedly irq-safe tree_lock:
invalidate_inode_pages2
invalidate_complete_page2
spin_lock_irq(&mapping->tree_lock)
clear_page_mlock
isolate_lru_page
spin_unlock_irq(&zone->lru_lock)isolate_lru_page() is correct to enable interrupts unconditionally:invalidate_complete_page2() is incorrect to call clear_page_mlock() while holding tree_lock, which is supposed to nest inside lru_lock.
Both truncate_complete_page() and invalidate_complete_page() call clear_page_mlock() before taking tree_lock to remove page from radix_tree.
I guess invalidate_complete_page2() preferred to test PageDirty (again)
under tree_lock before committing to the munlock; but since the page has already been unmapped, its state is already somewhat inconsistent, and no worse if clear_page_mlock() moved up.
--- mm/truncate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
mm/truncate.c +2 -1
@@ -376,11 +376,12 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)if (page_has_private (page) && !try_to_release_page (page,GFP_KERNEL ))return 0 ; +clear_page_mlock (page); +spin_lock_irq (&mapping->tree_lock);if (PageDirty (page)) goto failed; -clear_page_mlock (page);BUG_ON (page_has_private (page));__remove_from_page_cache (page);spin_unlock_irq (&mapping->tree_lock);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 40/184 mempolicy: fix a race in shared_policy_replace()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Mel Gorman <[email protected]>
commit b22d127a39ddd10d93deee3d96e643657ad53a49 upstream.
shared_policy_replace() use of sp_alloc() is unsafe. 1) sp_node cannot be dereferenced if sp->lock is not held and 2) another thread can modify sp_node between spin_unlock for allocating a new sp node and next spin_lock. The bug was introduced before 2.6.12-rc2.
Kosaki's original patch for this problem was to allocate an sp node and policy within shared_policy_replace and initialise it when the lock is reacquired. I was not keen on this approach because it partially duplicates sp_alloc(). As the paths were sp->lock is taken are not that performance critical this patch converts sp->lock to sp->mutex so it can sleep when calling sp_alloc().
--- include/linux/mempolicy.h | 2 +- mm/mempolicy.c | 37 ++++++++++++++++--------------------- 2 files changed, 17 insertions(+), 22 deletions(-)
include/linux/mempolicy.h +1 -1
@@ -180,7 +180,7 @@ struct sp_node {struct shared_policy {struct rb_root root; -spinlock_t lock; +struct mutex mutex; };void mpol_shared_policy_init (struct shared_policy *sp,struct mempolicy *mpol);
mm/mempolicy.c +16 -21
@@ -1759,7 +1759,7 @@ int __mpol_equal(struct mempolicy *a, struct mempolicy *b)*/ /* lookup first element intersecting start-end */ -/* Caller holds sp->lock */ +/* Caller holds sp->mutex */ static struct sp_node *sp_lookup (struct shared_policy *sp,unsigned long start,unsigned long end) {
@@ -1823,13 +1823,13 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)if (!sp->root.rb_node)return NULL ; -spin_lock (&sp->lock); +mutex_lock (&sp->mutex); sn =sp_lookup (sp, idx, idx+1 );if (sn) {mpol_get (sn->policy); pol = sn->policy; } -spin_unlock (&sp->lock); +mutex_unlock (&sp->mutex);return pol; }
@@ -1860,10 +1860,10 @@ static struct sp_node *sp_alloc(unsigned long start, unsigned long end,static int shared_policy_replace (struct shared_policy *sp,unsigned long start,unsigned long end,struct sp_node *new) { -struct sp_node *n, *new2 =NULL ; +struct sp_node *n; +int ret =0 ; -restart: -spin_lock (&sp->lock); +mutex_lock (&sp->mutex); n =sp_lookup (sp, start, end);/* Take care of old policies in the same range. */ while (n && n->start < end) {
@@ -1876,16 +1876,14 @@ restart: }else {/* Old policy spanning whole new range. */ if (n->end > end) { +struct sp_node *new2; + new2 =sp_alloc (end, n->end, n->policy);if (!new2) { -spin_unlock (&sp->lock); - new2 =sp_alloc (end, n->end, n->policy); -if (!new2) -return -ENOMEM ; - goto restart; + ret = -ENOMEM ; + goto out; } n->end = start;sp_insert (sp, new2); - new2 =NULL ;break ; }else n->end = start;
@@ -1896,12 +1894,9 @@ restart: }if (new)sp_insert (sp, new); -spin_unlock (&sp->lock); -if (new2) { -mpol_put (new2->policy); -kmem_cache_free (sn_cache, new2); - } -return 0 ; +out: +mutex_unlock (&sp->mutex); +return ret; }/**
@@ -1919,7 +1914,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)int ret; sp->root =RB_ROOT ;/* empty tree == default mempolicy */ -spin_lock_init (&sp->lock); +mutex_init (&sp->mutex);if (mpol) {struct vm_area_struct pvma;
@@ -1987,7 +1982,7 @@ void mpol_free_shared_policy(struct shared_policy *p)if (!p->root.rb_node)return ; -spin_lock (&p->lock); +mutex_lock (&p->mutex); next =rb_first (&p->root);while (next) { n = rb_entry(next, struct sp_node, nd);
@@ -1996,7 +1991,7 @@ void mpol_free_shared_policy(struct shared_policy *p)mpol_put (n->policy);kmem_cache_free (sn_cache, n); } -spin_unlock (&p->lock); +mutex_unlock (&p->mutex); }/* assumes fs == KERNEL_DS */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 41/184 ALSA: hda - More ALC663 fixes and support of
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
compatible chips
From: Kailang Yang <[email protected]>
commit ebb83eeb6469bedda83b4dc6f23ddf93eb32b347 upstream.
1. Add more ASUS NB model.
2. Fixed alc663_m51va_setup
M51VA has Digital Mic that NID is 0x12. The record source index is 0x9 for ALC663.
So, to modify the alc663_m51va_setup function to index 0x9 and add analog Mic aupport function alc663_mode1_setup.
3. Add ASUS mode7 and mode8 modules for ALC663
[jn: backport to 2.6.32.y to address http://bugs.debian.org/688564]
--- sound/pci/hda/patch_realtek.c | 306 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 282 insertions(+), 24 deletions(-)
sound/pci/hda/patch_realtek.c +282 -24
@@ -131,8 +131,8 @@ enum {enum {ALC269_BASIC ,ALC269_QUANTA_FL1 , -ALC269_ASUS_EEEPC_P703 , -ALC269_ASUS_EEEPC_P901 , +ALC269_ASUS_AMIC , +ALC269_ASUS_DMIC ,ALC269_FUJITSU ,ALC269_LIFEBOOK ,ALC269_AUTO ,
@@ -188,6 +188,8 @@ enum {ALC663_ASUS_MODE4 ,ALC663_ASUS_MODE5 ,ALC663_ASUS_MODE6 , +ALC663_ASUS_MODE7 , +ALC663_ASUS_MODE8 ,ALC272_DELL ,ALC272_DELL_ZM1 , ALC272_SAMSUNG_NC10,
@@ -13234,10 +13236,12 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = {/* toggle speaker-output according to the hp-jack state */ static void alc269_speaker_automute (struct hda_codec *codec) { +struct alc_spec *spec = codec->spec; +unsigned int nid = spec->autocfg.hp_pins[0 ];unsigned int present;unsigned char bits; - present =snd_hda_codec_read (codec,0x15 ,0 , + present =snd_hda_codec_read (codec, nid,0 ,AC_VERB_GET_PIN_SENSE ,0 ) &0x80000000 ; bits = present ?AMP_IN_MUTE (0 ) :0 ; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
@@ -13463,8 +13467,8 @@ static void alc269_auto_init(struct hda_codec *codec)static const char *alc269_models[ALC269_MODEL_LAST ] = { [ALC269_BASIC ] ="basic" , [ALC269_QUANTA_FL1 ] ="quanta" , - [ALC269_ASUS_EEEPC_P703 ] ="eeepc-p703" , - [ALC269_ASUS_EEEPC_P901 ] ="eeepc-p901" , + [ALC269_ASUS_AMIC ] ="asus-amic" , + [ALC269_ASUS_DMIC ] ="asus-dmic" , [ALC269_FUJITSU ] ="fujitsu" , [ALC269_LIFEBOOK ] ="lifebook" , [ALC269_AUTO ] ="auto" ,
@@ -13473,18 +13477,41 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {static struct snd_pci_quirk alc269_cfg_tbl[] = {SND_PCI_QUIRK (0x17aa ,0x3bf8 ,"Quanta FL1" ,ALC269_QUANTA_FL1 ),SND_PCI_QUIRK (0x1043 ,0x8330 ,"ASUS Eeepc P703 P900A" , -ALC269_ASUS_EEEPC_P703 ), -SND_PCI_QUIRK (0x1043 ,0x1883 ,"ASUS F81Se" ,ALC269_ASUS_EEEPC_P703 ), -SND_PCI_QUIRK (0x1043 ,0x16a3 ,"ASUS F5Q" ,ALC269_ASUS_EEEPC_P703 ), -SND_PCI_QUIRK (0x1043 ,0x1723 ,"ASUS P80" ,ALC269_ASUS_EEEPC_P703 ), -SND_PCI_QUIRK (0x1043 ,0x1773 ,"ASUS U20A" ,ALC269_ASUS_EEEPC_P703 ), -SND_PCI_QUIRK (0x1043 ,0x1743 ,"ASUS U80" ,ALC269_ASUS_EEEPC_P703 ), -SND_PCI_QUIRK (0x1043 ,0x1653 ,"ASUS U50" ,ALC269_ASUS_EEEPC_P703 ), +ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1133 ,"ASUS UJ20ft" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1273 ,"ASUS UL80JT" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1283 ,"ASUS U53Jc" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x12b3 ,"ASUS N82Jv" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x13a3 ,"ASUS UL30Vt" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1373 ,"ASUS G73JX" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1383 ,"ASUS UJ30Jc" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x13d3 ,"ASUS N61JA" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1413 ,"ASUS UL50" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1443 ,"ASUS UL30" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1453 ,"ASUS M60Jv" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1483 ,"ASUS UL80" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x14f3 ,"ASUS F83Vf" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x14e3 ,"ASUS UL20" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1513 ,"ASUS UX30" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x15a3 ,"ASUS N60Jv" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x15b3 ,"ASUS N60Dp" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x15c3 ,"ASUS N70De" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x15e3 ,"ASUS F83T" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1643 ,"ASUS M60J" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1653 ,"ASUS U50" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1693 ,"ASUS F50N" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x16a3 ,"ASUS F5Q" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x16e3 ,"ASUS UX50" ,ALC269_ASUS_DMIC ), +SND_PCI_QUIRK (0x1043 ,0x1723 ,"ASUS P80" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1743 ,"ASUS U80" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1773 ,"ASUS U20A" ,ALC269_ASUS_AMIC ), +SND_PCI_QUIRK (0x1043 ,0x1883 ,"ASUS F81Se" ,ALC269_ASUS_AMIC ),SND_PCI_QUIRK (0x1043 ,0x831a ,"ASUS Eeepc P901" , -ALC269_ASUS_EEEPC_P901 ), +ALC269_ASUS_DMIC ),SND_PCI_QUIRK (0x1043 ,0x834a ,"ASUS Eeepc S101" , -ALC269_ASUS_EEEPC_P901 ), -SND_PCI_QUIRK (0x1043 ,0x16e3 ,"ASUS UX50" ,ALC269_ASUS_EEEPC_P901 ), +ALC269_ASUS_DMIC ), +SND_PCI_QUIRK (0x1043 ,0x8398 ,"ASUS P1005HA" ,ALC269_ASUS_DMIC ), +SND_PCI_QUIRK (0x1043 ,0x83ce ,"ASUS P1005HA" ,ALC269_ASUS_DMIC ),SND_PCI_QUIRK (0x1734 ,0x115d ,"FSC Amilo" ,ALC269_FUJITSU ),SND_PCI_QUIRK (0x10cf ,0x1475 ,"Lifebook ICH9M-based" ,ALC269_LIFEBOOK ), {}
@@ -13514,7 +13541,7 @@ static struct alc_config_preset alc269_presets[] = { .setup = alc269_quanta_fl1_setup, .init_hook = alc269_quanta_fl1_init_hook, }, - [ALC269_ASUS_EEEPC_P703] = { + [ALC269_ASUS_AMIC] = { .mixers = { alc269_eeepc_mixer }, .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs,
@@ -13528,7 +13555,7 @@ static struct alc_config_preset alc269_presets[] = { .setup = alc269_eeepc_amic_setup, .init_hook = alc269_eeepc_inithook, }, - [ALC269_ASUS_EEEPC_P901] = { + [ALC269_ASUS_DMIC] = { .mixers = { alc269_eeepc_mixer }, .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs,
@@ -16144,6 +16171,52 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = { { }/* end */ }; +static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { +HDA_COMPOSE_AMP_VAL (0x14 ,3 ,0 ,HDA_OUTPUT ), +HDA_COMPOSE_AMP_VAL (0x15 ,3 ,0 ,HDA_OUTPUT ), +HDA_COMPOSE_AMP_VAL (0x17 ,3 ,0 ,HDA_OUTPUT ), +HDA_COMPOSE_AMP_VAL (0x1b ,3 ,0 ,HDA_OUTPUT ), +HDA_COMPOSE_AMP_VAL (0x21 ,3 ,0 ,HDA_OUTPUT ), +0 + }, +}; + +static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { +HDA_COMPOSE_AMP_VAL (0x14 ,3 ,0 ,HDA_OUTPUT ), +HDA_COMPOSE_AMP_VAL (0x17 ,3 ,0 ,HDA_OUTPUT ), +0 + }, +}; + +static struct snd_kcontrol_new alc663_mode7_mixer[] = { +HDA_BIND_SW ("Master Playback Switch" , &alc663_asus_mode7_8_all_bind_switch), +HDA_BIND_VOL ("Speaker Playback Volume" , &alc663_asus_bind_master_vol), +HDA_BIND_SW ("Speaker Playback Switch" , &alc663_asus_mode7_8_sp_bind_switch), +HDA_CODEC_MUTE ("Headphone1 Playback Switch" ,0x1b ,0x0 ,HDA_OUTPUT ), +HDA_CODEC_MUTE ("Headphone2 Playback Switch" ,0x21 ,0x0 ,HDA_OUTPUT ), +HDA_CODEC_VOLUME ("IntMic Playback Volume" ,0x0b ,0x0 ,HDA_INPUT ), +HDA_CODEC_MUTE ("IntMic Playback Switch" ,0x0b ,0x0 ,HDA_INPUT ), +HDA_CODEC_VOLUME ("Mic Playback Volume" ,0x0b ,0x1 ,HDA_INPUT ), +HDA_CODEC_MUTE ("Mic Playback Switch" ,0x0b ,0x1 ,HDA_INPUT ), + { }/* end */ +}; + +static struct snd_kcontrol_new alc663_mode8_mixer[] = { +HDA_BIND_SW ("Master Playback Switch" , &alc663_asus_mode7_8_all_bind_switch), +HDA_BIND_VOL ("Speaker Playback Volume" , &alc663_asus_bind_master_vol), +HDA_BIND_SW ("Speaker Playback Switch" , &alc663_asus_mode7_8_sp_bind_switch), +HDA_CODEC_MUTE ("Headphone1 Playback Switch" ,0x15 ,0x0 ,HDA_OUTPUT ), +HDA_CODEC_MUTE ("Headphone2 Playback Switch" ,0x21 ,0x0 ,HDA_OUTPUT ), +HDA_CODEC_VOLUME ("Mic Playback Volume" ,0x0b ,0x0 ,HDA_INPUT ), +HDA_CODEC_MUTE ("Mic Playback Switch" ,0x0b ,0x0 ,HDA_INPUT ), + { }/* end */ +}; + +static struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface =SNDRV_CTL_ELEM_IFACE_MIXER ,
@@ -16431,6 +16504,45 @@ static struct hda_verb alc272_dell_init_verbs[] = { {} }; +static struct hda_verb alc663_mode7_init_verbs[] = { + {0x15 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_IN }, + {0x16 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_IN }, + {0x17 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_OUT }, + {0x17 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_OUT_UNMUTE }, + {0x1b ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_HP }, + {0x1b ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_OUT_UNMUTE }, + {0x1b ,AC_VERB_SET_CONNECT_SEL ,0x01 }, + {0x21 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_HP }, + {0x21 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_OUT_UNMUTE }, + {0x21 ,AC_VERB_SET_CONNECT_SEL ,0x01 },/* Headphone */ + {0x22 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_IN_MUTE (0 )}, + {0x22 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_IN_UNMUTE (9 )}, + {0x19 ,AC_VERB_SET_UNSOLICITED_ENABLE ,AC_USRSP_EN |ALC880_MIC_EVENT }, + {0x1b ,AC_VERB_SET_UNSOLICITED_ENABLE ,AC_USRSP_EN |ALC880_HP_EVENT }, + {0x21 ,AC_VERB_SET_UNSOLICITED_ENABLE ,AC_USRSP_EN |ALC880_HP_EVENT }, + {} +}; + +static struct hda_verb alc663_mode8_init_verbs[] = { + {0x12 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_IN }, + {0x15 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_HP }, + {0x15 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_OUT_UNMUTE }, + {0x15 ,AC_VERB_SET_CONNECT_SEL ,0x01 }, + {0x16 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_IN }, + {0x17 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_OUT }, + {0x17 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_OUT_UNMUTE }, + {0x1b ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_IN }, + {0x21 ,AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_HP }, + {0x21 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_OUT_UNMUTE }, + {0x21 ,AC_VERB_SET_CONNECT_SEL ,0x01 },/* Headphone */ + {0x22 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_IN_MUTE (0 )}, + {0x22 ,AC_VERB_SET_AMP_GAIN_MUTE ,AMP_IN_UNMUTE (9 )}, + {0x15 ,AC_VERB_SET_UNSOLICITED_ENABLE ,AC_USRSP_EN |ALC880_HP_EVENT }, + {0x18 ,AC_VERB_SET_UNSOLICITED_ENABLE ,AC_USRSP_EN |ALC880_MIC_EVENT }, + {0x21 ,AC_VERB_SET_UNSOLICITED_ENABLE ,AC_USRSP_EN |ALC880_HP_EVENT }, + {} +}; +static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {HDA_CODEC_VOLUME ("Capture Volume" ,0x09 ,0x0 ,HDA_INPUT ),HDA_CODEC_MUTE ("Capture Switch" ,0x09 ,0x0 ,HDA_INPUT ),
@@ -16626,6 +16738,54 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) } } +static void alc663_two_hp_m7_speaker_automute (struct hda_codec *codec) +{ +unsigned int present1, present2; + + present1 =snd_hda_codec_read (codec,0x1b ,0 , +AC_VERB_GET_PIN_SENSE ,0 ) + &AC_PINSENSE_PRESENCE ; + present2 =snd_hda_codec_read (codec,0x21 ,0 , +AC_VERB_GET_PIN_SENSE ,0 ) + &AC_PINSENSE_PRESENCE ; + +if (present1 || present2) { +snd_hda_codec_write_cache (codec,0x14 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,0 ); +snd_hda_codec_write_cache (codec,0x17 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,0 ); + }else { +snd_hda_codec_write_cache (codec,0x14 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_OUT ); +snd_hda_codec_write_cache (codec,0x17 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_OUT ); + } +} + +static void alc663_two_hp_m8_speaker_automute (struct hda_codec *codec) +{ +unsigned int present1, present2; + + present1 =snd_hda_codec_read (codec,0x21 ,0 , +AC_VERB_GET_PIN_SENSE ,0 ) + &AC_PINSENSE_PRESENCE ; + present2 =snd_hda_codec_read (codec,0x15 ,0 , +AC_VERB_GET_PIN_SENSE ,0 ) + &AC_PINSENSE_PRESENCE ; + +if (present1 || present2) { +snd_hda_codec_write_cache (codec,0x14 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,0 ); +snd_hda_codec_write_cache (codec,0x17 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,0 ); + }else { +snd_hda_codec_write_cache (codec,0x14 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_OUT ); +snd_hda_codec_write_cache (codec,0x17 ,0 , +AC_VERB_SET_PIN_WIDGET_CONTROL ,PIN_OUT ); + } +} +static void alc663_m51va_unsol_event (struct hda_codec *codec,unsigned int res) {
@@ -16645,7 +16805,7 @@ static void alc663_m51va_setup(struct hda_codec *codec) spec->ext_mic.pin =0x18 ; spec->ext_mic.mux_idx =0 ; spec->int_mic.pin =0x12 ; - spec->int_mic.mux_idx =1 ; + spec->int_mic.mux_idx =9 ; spec->auto_mic =1 ; }
@@ -16657,7 +16817,17 @@ static void alc663_m51va_inithook(struct hda_codec *codec)/* ***************** Mode1 ******************************/ #define alc663_mode1_unsol_event alc663_m51va_unsol_event -#define alc663_mode1_setup alc663_m51va_setup + +static void alc663_mode1_setup (struct hda_codec *codec) +{ +struct alc_spec *spec = codec->spec; + spec->ext_mic.pin =0x18 ; + spec->ext_mic.mux_idx =0 ; + spec->int_mic.pin =0x19 ; + spec->int_mic.mux_idx =1 ; + spec->auto_mic =1 ; +} +#define alc663_mode1_inithook alc663_m51va_inithook/* ***************** Mode2 ******************************/
@@ -16674,7 +16844,7 @@ static void alc662_mode2_unsol_event(struct hda_codec *codec, } } -#define alc662_mode2_setup alc663_m51va_setup +#define alc662_mode2_setup alc663_mode1_setupstatic void alc662_mode2_inithook (struct hda_codec *codec) {
@@ -16695,7 +16865,7 @@ static void alc663_mode3_unsol_event(struct hda_codec *codec, } } -#define alc663_mode3_setup alc663_m51va_setup +#define alc663_mode3_setup alc663_mode1_setupstatic void alc663_mode3_inithook (struct hda_codec *codec) {
@@ -16716,7 +16886,7 @@ static void alc663_mode4_unsol_event(struct hda_codec *codec, } } -#define alc663_mode4_setup alc663_m51va_setup +#define alc663_mode4_setup alc663_mode1_setupstatic void alc663_mode4_inithook (struct hda_codec *codec) {
@@ -16737,7 +16907,7 @@ static void alc663_mode5_unsol_event(struct hda_codec *codec, } } -#define alc663_mode5_setup alc663_m51va_setup +#define alc663_mode5_setup alc663_mode1_setupstatic void alc663_mode5_inithook (struct hda_codec *codec) {
@@ -16758,7 +16928,7 @@ static void alc663_mode6_unsol_event(struct hda_codec *codec, } } -#define alc663_mode6_setup alc663_m51va_setup +#define alc663_mode6_setup alc663_mode1_setupstatic void alc663_mode6_inithook (struct hda_codec *codec) {
@@ -16766,6 +16936,50 @@ static void alc663_mode6_inithook(struct hda_codec *codec)alc_mic_automute (codec); } +/* ***************** Mode7 ******************************/ +static void alc663_mode7_unsol_event (struct hda_codec *codec, +unsigned int res) +{ +switch (res >>26 ) { +case ALC880_HP_EVENT : +alc663_two_hp_m7_speaker_automute (codec); +break ; +case ALC880_MIC_EVENT : +alc_mic_automute (codec); +break ; + } +} + +#define alc663_mode7_setup alc663_mode1_setup + +static void alc663_mode7_inithook (struct hda_codec *codec) +{ +alc663_two_hp_m7_speaker_automute (codec); +alc_mic_automute (codec); +} + +/* ***************** Mode8 ******************************/ +static void alc663_mode8_unsol_event (struct hda_codec *codec, +unsigned int res) +{ +switch (res >>26 ) { +case ALC880_HP_EVENT : +alc663_two_hp_m8_speaker_automute (codec); +break ; +case ALC880_MIC_EVENT : +alc_mic_automute (codec); +break ; + } +} + +#define alc663_mode8_setup alc663_m51va_setup + +static void alc663_mode8_inithook (struct hda_codec *codec) +{ +alc663_two_hp_m8_speaker_automute (codec); +alc_mic_automute (codec); +} +static void alc663_g71v_hp_automute (struct hda_codec *codec) {unsigned int present;
@@ -16904,6 +17118,8 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC663_ASUS_MODE4] = "asus-mode4", [ALC663_ASUS_MODE5] = "asus-mode5", [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC663_ASUS_MODE7] = "asus-mode7", + [ALC663_ASUS_MODE8] = "asus-mode8", [ALC272_DELL] = "dell", [ALC272_DELL_ZM1] = "dell-zm1", [ALC272_SAMSUNG_NC10] = "samsung-nc10",
@@ -16920,12 +17136,22 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {SND_PCI_QUIRK (0x1043 ,0x11d3 ,"ASUS NB" ,ALC663_ASUS_MODE1 ),SND_PCI_QUIRK (0x1043 ,0x11f3 ,"ASUS NB" ,ALC662_ASUS_MODE2 ),SND_PCI_QUIRK (0x1043 ,0x1203 ,"ASUS NB" ,ALC663_ASUS_MODE1 ), +SND_PCI_QUIRK (0x1043 ,0x1303 ,"ASUS G60J" ,ALC663_ASUS_MODE1 ), +SND_PCI_QUIRK (0x1043 ,0x1333 ,"ASUS G60Jx" ,ALC663_ASUS_MODE1 ),SND_PCI_QUIRK (0x1043 ,0x1339 ,"ASUS NB" ,ALC662_ASUS_MODE2 ), +SND_PCI_QUIRK (0x1043 ,0x13e3 ,"ASUS N71JA" ,ALC663_ASUS_MODE7 ), +SND_PCI_QUIRK (0x1043 ,0x1463 ,"ASUS N71" ,ALC663_ASUS_MODE7 ), +SND_PCI_QUIRK (0x1043 ,0x14d3 ,"ASUS G72" ,ALC663_ASUS_MODE8 ), +SND_PCI_QUIRK (0x1043 ,0x1563 ,"ASUS N90" ,ALC663_ASUS_MODE3 ), +SND_PCI_QUIRK (0x1043 ,0x15d3 ,"ASUS N50SF F50SF" ,ALC663_ASUS_MODE1 ),SND_PCI_QUIRK (0x1043 ,0x16c3 ,"ASUS NB" ,ALC662_ASUS_MODE2 ), +SND_PCI_QUIRK (0x1043 ,0x16f3 ,"ASUS K40C K50C" ,ALC662_ASUS_MODE2 ), +SND_PCI_QUIRK (0x1043 ,0x1733 ,"ASUS N81De" ,ALC663_ASUS_MODE1 ),SND_PCI_QUIRK (0x1043 ,0x1753 ,"ASUS NB" ,ALC662_ASUS_MODE2 ),SND_PCI_QUIRK (0x1043 ,0x1763 ,"ASUS NB" ,ALC663_ASUS_MODE6 ),SND_PCI_QUIRK (0x1043 ,0x1765 ,"ASUS NB" ,ALC663_ASUS_MODE6 ),SND_PCI_QUIRK (0x1043 ,0x1783 ,"ASUS NB" ,ALC662_ASUS_MODE2 ), +SND_PCI_QUIRK (0x1043 ,0x1793 ,"ASUS F50GX" ,ALC663_ASUS_MODE1 ),SND_PCI_QUIRK (0x1043 ,0x17b3 ,"ASUS F70SL" ,ALC663_ASUS_MODE3 ),SND_PCI_QUIRK (0x1043 ,0x17c3 ,"ASUS UX20" ,ALC663_ASUS_M51VA ), SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
@@ -17208,6 +17434,36 @@ static struct alc_config_preset alc662_presets[] = { .setup = alc663_mode6_setup, .init_hook = alc663_mode6_inithook, }, + [ALC663_ASUS_MODE7] = { + .mixers = { alc663_mode7_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc663_mode7_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc663_mode7_unsol_event, + .setup = alc663_mode7_setup, + .init_hook = alc663_mode7_inithook, + }, + [ALC663_ASUS_MODE8] = { + .mixers = { alc663_mode8_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc663_mode8_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc663_mode8_unsol_event, + .setup = alc663_mode8_setup, + .init_hook = alc663_mode8_inithook, + }, [ALC272_DELL] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc272_auto_capture_mixer,
@@ -17676,7 +17932,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 }, + { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 }, { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, + { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 42/184 ALSA: hda - Add a pin-fix for FSC Amilo Pi1505
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
FSC Amilo Pi 1505 has a buggy BIOS and doesn't set up the HP and speaker pins properly. Add the pinfix entry for that.
Reference: Novell bnc#557403
https://bugzilla.novell.com/show_bug.cgi?id=557403
[2.6.32: additional background from Jonathan below]
Quoted 18 lines
Hi Willy,
Please consider
cfc9b06f0befALSA: hda - Add a pin-fix for FSC Amilo Pi1505for application to the 2.6.32.y tree. Without this patch, the Amilo Pi 1505's internal speaker is silent unless a jack is plugged into its headphone jack.
Jose Manuel Castroagudin noticed[1] that 2.6.30 is not affected, so this seems to be a regression.
The patch was applied upstream during the 2.6.33 merge window, where it worked. That said, I didn't manage to track down anyone with a Pi1505 to test it against 2.6.32, so thoughts from alsa folks on whether this is appropriate for 2.6.32.y would be useful.
Quoted 4 lines
Hope that helps,
Jonathan[1] http://bugs.debian.org/599582 has many more details.
--- sound/pci/hda/patch_realtek.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
sound/pci/hda/patch_realtek.c +23 -0
@@ -14713,6 +14713,27 @@ static struct alc_config_preset alc861_presets[] = { }, }; +/* Pin config fixes */ +enum { +PINFIX_FSC_AMILO_PI1505 , +}; + +static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = { + {0x0b ,0x0221101f },/* HP */ + {0x0f ,0x90170310 },/* speaker */ + { } +}; + +static const struct alc_fixup alc861_fixups[] = { + [PINFIX_FSC_AMILO_PI1505 ] = { + .pins = alc861_fsc_amilo_pi1505_pinfix + }, +}; + +static struct snd_pci_quirk alc861_fixup_tbl[] = { +SND_PCI_QUIRK (0x1734 ,0x10c7 ,"FSC Amilo Pi1505" ,PINFIX_FSC_AMILO_PI1505 ), + {} +};static int patch_alc861 (struct hda_codec *codec) {
@@ -14736,6 +14757,8 @@ static int patch_alc861(struct hda_codec *codec) board_config =ALC861_AUTO ; } +alc_pick_fixup (codec, alc861_fixup_tbl, alc861_fixups); +if (board_config ==ALC861_AUTO ) {/* automatic parse from the BIOS config */ err =alc861_parse_auto_config (codec);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 43/184 ALSA: seq: Fix missing error handling in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
snd_seq_timer_open()
From: Takashi Iwai <[email protected]>
commit 66efdc71d95887b652a742a5dae51fa834d71465 upstream.
snd_seq_timer_open() didn't catch the whole error path but let through if the timer id is a slave. This may lead to Oops by accessing the uninitialized pointer.
BUG: unable to handle kernel NULL pointer dereference at 00000000000002ae IP: [<ffffffff819b3477>] snd_seq_timer_open+0xe7/0x130 PGD 785cd067 PUD 76964067 PMD 0 Oops: 0002 [#4] SMP CPU 0 Pid: 4288, comm: trinity-child7 Tainted: G D W 3.9.0-rc1+ #100 Bochs Bochs RIP: 0010:[<ffffffff819b3477>] [<ffffffff819b3477>] snd_seq_timer_open+0xe7/0x130 RSP: 0018:ffff88006ece7d38 EFLAGS: 00010246 RAX: 0000000000000286 RBX: ffff88007851b400 RCX: 0000000000000000 RDX: 000000000000ffff RSI: ffff88006ece7d58 RDI: ffff88006ece7d38 RBP: ffff88006ece7d98 R08: 000000000000000a R09: 000000000000fffe R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: ffff8800792c5400 R14: 0000000000e8f000 R15: 0000000000000007 FS: 00007f7aaa650700(0000) GS:ffff88007f800000(0000) GS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000000002ae CR3: 000000006efec000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process trinity-child7 (pid: 4288, threadinfo ffff88006ece6000, task ffff880076a8a290) Stack: 0000000000000286 ffffffff828f2be0 ffff88006ece7d58 ffffffff810f354d 65636e6575716573 2065756575712072 ffff8800792c0030 0000000000000000 ffff88006ece7d98 ffff8800792c5400 ffff88007851b400 ffff8800792c5520 Call Trace: [<ffffffff810f354d>] ? trace_hardirqs_on+0xd/0x10 [<ffffffff819b17e9>] snd_seq_queue_timer_open+0x29/0x70 [<ffffffff819ae01a>] snd_seq_ioctl_set_queue_timer+0xda/0x120 [<ffffffff819acb9b>] snd_seq_do_ioctl+0x9b/0xd0 [<ffffffff819acbe0>] snd_seq_ioctl+0x10/0x20 [<ffffffff811b9542>] do_vfs_ioctl+0x522/0x570 [<ffffffff8130a4b3>] ? file_has_perm+0x83/0xa0 [<ffffffff810f354d>] ? trace_hardirqs_on+0xd/0x10 [<ffffffff811b95ed>] sys_ioctl+0x5d/0xa0 [<ffffffff813663fe>] ? trace_hardirqs_on_thunk+0x3a/0x3f [<ffffffff81faed69>] system_call_fastpath+0x16/0x1b
--- sound/core/seq/seq_timer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
sound/core/seq/seq_timer.c +4 -4
@@ -291,10 +291,10 @@ int snd_seq_timer_open(struct snd_seq_queue *q) tid.device =SNDRV_TIMER_GLOBAL_SYSTEM ; err =snd_timer_open (&t, str, &tid, q->queue); } -if (err <0 ) { -snd_printk (KERN_ERR "seq fatal error: cannot create timer (%i)\n" , err); -return err; - } + } +if (err <0 ) { +snd_printk (KERN_ERR "seq fatal error: cannot create timer (%i)\n" , err); +return err; } t->callback = snd_seq_timer_interrupt; t->callback_data = q;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 44/184 ALSA: ice1712: Initialize card->private_data
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
properly
From: Sean Connor <[email protected]>
commit 69a4cfdd444d1fe5c24d29b3a063964ac165d2cd upstream.
Set card->private_data in snd_ice1712_create for fixing NULL dereference in snd_ice1712_remove().
--- sound/pci/ice1712/ice1712.c | 2 ++ 1 file changed, 2 insertions(+)
sound/pci/ice1712/ice1712.c +2 -0
@@ -2574,6 +2574,8 @@ static int __devinit snd_ice1712_create(struct snd_card *card,snd_ice1712_proc_init (ice);synchronize_irq (pci->irq); + card->private_data = ice; + err =pci_request_regions (pci,"ICE1712" );if (err <0 ) {kfree (ice);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 044/184] ALSA: ice1712: Initialize card->private_data
Quoted 11 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
properlyFrom: Sean Connor <[email protected]>
commit
69a4cfdd444d1fe5c24d29b3a063964ac165d2cdupstream.Set
card->private_datainsnd_ice1712_createfor fixing NULL dereference insnd_ice1712_remove().
This bug appears to have been introduced in Linux 3.8 and doesn't need fixing in 2.6.32.
Ben.
Quoted 21 lines
Signed-off-by Sean Connor <[email protected]>Signed-off-by Takashi Iwai <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>Signed-off-by Willy Tarreau <[email protected]>--- sound/pci/ice1712/ice1712.c | 2 ++ 1 file changed, 2 insertions(+)sound/pci/ice1712/ice1712.c +2
-0@@ -2574,6 +2574,8 @@ static int __devinit snd_ice1712_create(struct snd_card *card,snd_ice1712_proc_init (ice);synchronize_irq (pci->irq); + card->private_data = ice; + err =pci_request_regions (pci,"ICE1712" );if (err <0 ) {kfree (ice);
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 044/184] ALSA: ice1712: Initialize card->private_data
Hi Ben,
Quoted 9 lines · Ben Hutchings
Quoted 6 lines
From: Sean Connor <[email protected]>
commit
69a4cfdd444d1fe5c24d29b3a063964ac165d2cdupstream.Set
card->private_datainsnd_ice1712_createfor fixing NULL dereference insnd_ice1712_remove().This bug appears to have been introduced in Linux 3.8 and doesn't need fixing in 2.6.32.
Ah indeed that's true. Does it harm to have it or not ? because I'm still seeing a number of places where we have this in the driver :
struct snd_ice1712 *ice = ac97->private_data;
I'd like to be sure that no other function risks to dereference the same pointer. Also, I'm noting that 3.0/3.4 have this fix, while 3.2 does not. So I'm hesitant what to do with this patch.
Thanks,
Willy
Re: [ 044/184] ALSA: ice1712: Initialize card->private_data
At Fri, 7 Jun 2013 07:34:01 +0200,
Quoted 8 lines · Willy Tarreau
Hi Ben,
Quoted 4 lines · Ben Hutchings
Quoted 4 lines
From: Sean Connor <[email protected]>
commit
69a4cfdd444d1fe5c24d29b3a063964ac165d2cdupstream.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
Set
card->private_datainsnd_ice1712_createfor fixing NULL dereference insnd_ice1712_remove().This bug appears to have been introduced in Linux 3.8 and doesn't need fixing in 2.6.32.
Ah indeed that's true. Does it harm to have it or not ?
It's harmless.
Quoted 4 lines
because I'm
still seeing a number of places where we have this in the driver :struct snd_ice1712 *ice = ac97->private_data;
These are different object types. The reference of card->private_data was introduced recently as Ben pointed out.
Quoted 3 lines
I'd like to be sure that no other function risks to dereference the same pointer. Also, I'm noting that 3.0/3.4 have this fix, while 3.2 does not. So I'm hesitant what to do with this patch.
Just overlooked in 3.0/3.4 reviews :-<
But it's utterly harmless, we don't have to remove it from 3.0/3.4, I think.
For 2.6.32, better to get rid of it from the queue, if it's not too late.
thanks,
Takashi
Re: [ 044/184] ALSA: ice1712: Initialize card->private_data
Hi Takashi,
Quoted 7 lines · Takashi Iwai
Quoted 4 lines
Quoted 2 lines
This bug appears to have been introduced in Linux 3.8 and doesn't need fixing in 2.6.32.
Ah indeed that's true. Does it harm to have it or not ?
It's harmless.
Quoted 7 lines
Quoted 4 lines
because I'm
still seeing a number of places where we have this in the driver :struct snd_ice1712 *ice = ac97->private_data;These are different object types. The reference of
card->private_datawas introduced recently as Ben pointed out.
Ah sorry I was confused.
Quoted 11 lines
Quoted 3 lines
I'd like to be sure that no other function risks to dereference the same pointer. Also, I'm noting that 3.0/3.4 have this fix, while 3.2 does not. So I'm hesitant what to do with this patch.
Just overlooked in 3.0/3.4 reviews :-<
But it's utterly harmless, we don't have to remove it from 3.0/3.4, I think.
For 2.6.32, better to get rid of it from the queue, if it's not too late.
Perfect, thanks for the detailed explanation, I'm removing it now.
Best regards,
Willy
PATCH 45/184 ALSA: ac97 - Fix missing NULL check in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
snd_ac97_cvol_new()
From: Takashi Iwai <[email protected]>
commit 733a48e5ae5bf28b046fad984d458c747cbb8c21 upstream.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=44721
--- sound/pci/ac97/ac97_codec.c | 2 ++ 1 file changed, 2 insertions(+)
sound/pci/ac97/ac97_codec.c +2 -0
@@ -1252,6 +1252,8 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne tmp.index = ac97->num; kctl =snd_ctl_new1 (&tmp, ac97); } +if (!kctl) +return -ENOMEM ;if (reg >=AC97_PHONE && reg <=AC97_PCM )set_tlv_db_scale (kctl, db_scale_5bit_12db_max);else
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 46/184 x86, ioapic: initialize nr_ioapic_registers early in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
mp_register_ioapic()
From: Suresh Siddha <[email protected]>
Lin Bao reported that one of the HP platforms failed to boot 2.6.32 kernel, when the BIOS enabled interrupt-remapping and x2apic before handing over the control to the Linux kernel.
During boot, Linux kernel masks all the interrupt sources (8259, IO-APIC RTE's), setup the interrupt-remapping hardware with the OS controlled table and unmasks the 8259 interrupts but not the IO-APIC RTE's (as the newly setup interrupt-remapping table and the IO-APIC RTE's are not yet programmed by the kernel).
Shortly after this, IO-APIC RTE's and the interrupt-remapping table entries are programmed based on the ACPI tables etc. So the expectation is that any interrupt during this window will be dropped and not see the intermediate configuration.
In the reported problematic case, BIOS has configured the IO-APIC in virtual wire-B mode. Between the window of the kernel setting up new interrupt-remapping table and the IO-APIC RTE's are properly configured, an interrupt gets routed by the IO-APIC RTE (setup by the virtual wire-B configuration) and sees the empty interrupt-remapping table entry, resulting in vt-d fault causing the platform to generate NMI. And the OS panics on this unexpected NMI.
This problem doesn't happen with more recent kernels and closer look at the 2.6.32 kernel shows that the code which masks the IO-APIC RTE's is not working as expected as the nr_ioapic_registers for each IO-APIC is not yet initialized at this point. In the later kernels we initialize nr_ioapic_registers much before and everything works as expected.
For 2.6.[32..34] kernels, fix this issue by initializing nr_ioapic_registers early in mp_register_ioapic()
[ Relevant upstream commit info:
commit 7716a5c4ff5f1f3dc5e9edcab125cbf7fceef0af
Author: Eric W. Biederman <[email protected]>
Date: Tue Mar 30 01:07:12 2010 -0700
x86, ioapic: Move nr_ioapic_registers calculation to mp_register_ioapic.
As the upstream commit depends on quite a few prior commits and some followup fixes in the mainline, we just picked the smallest relevant hunk for fixing the issue at hand. Problematic platform uses ACPI for IO-APIC, VT-d enumeration etc and this hunk only touches the ACPI based platforms.
nr_ioapic_reigsters initialization in enable_IO_APIC() is still retained, so that other configurations like legacy MPS table based enumeration etc works with no change.
]
--- arch/x86/kernel/apic/io_apic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +7 -2
@@ -4262,6 +4262,7 @@ static int bad_ioapic(unsigned long address)void __init mp_register_ioapic (int id,u32 address,u32 gsi_base) {int idx =0 ; +int entries;if (bad_ioapic (address))return ;
@@ -4280,10 +4281,14 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)* Build basic GSI lookup table to facilitate gsi->io_apic lookups * and to prevent reprogramming of IOAPIC pins (PCI GSIs). */ + entries =io_apic_get_redir_entries (idx); mp_gsi_routing[idx].gsi_base = gsi_base; - mp_gsi_routing[idx].gsi_end = gsi_base + -io_apic_get_redir_entries (idx); + mp_gsi_routing[idx].gsi_end = gsi_base + entries; +/* +* The number of IO-APIC IRQ registers (== #pins): +*/ + nr_ioapic_registers[idx] = entries +1 ; printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " "GSI %d-%d\n", idx, mp_ioapics[idx].apicid, mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 47/184 x86: Dont use the EFI reboot method by default
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 Garrett <[email protected]>
Testing suggests that at least some Lenovos and some Intels will fail to reboot via EFI, attempting to jump to an unmapped physical address. In the long run we could handle this by providing a page table with a 1:1 mapping of physical addresses, but for now it's probably just easier to assume that ACPI or legacy methods will be present and reboot via those.
[2.6.32: additional background information from Jonathan below]
Quoted 34 lines
Please consider
f70e957cda22x86: Don't use the EFI reboot method by default,2011-07-06for application to the 2.6.32.y and 2.6.34.y trees. The patch was applied upstream late in the 3.0 cycle, so newer kernels don't need it.
In 2011, Keith Ward wrote[1]:
Quoted 4 lines
When attempting to reboot my my UEFI enabled system, the system hangs when calling reboot requiring me to manually reset the system via the reset switch.
Screenshot: http://twitgoo.com/29bq1c
Ben Hutchings writes[1]:
Quoted 6 lines
Version: 3.0.0-1
I also had this problem on my own system, but it is fixed now. I bisected the fix to:
commit
f70e957cda22d309c769805cbb932407a5232219Quoted 8 lines
Author: Matthew Garrett <[email protected]> Date: Wed Jul 6 16:52:37 2011 -0400x86: Don't use the EFI reboot method by default
which is basically equivalent to the workaround!
I'll also apply this fix to squeeze as it's so simple.
Quoted 8 lines
Keith Ward also wrote[1]:
Quoted 2 lines
It seems as if this has recently been reported at Ubuntu's Launchpad as well:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/721576There are a variety of reports of the same panic at that bug on 2.6.32.y-, 2.6.38.y-, and 2.6.39-based kernels. Passing "reboot=a,w" on the kernel command line avoids trouble for reporters.
--- arch/x86/kernel/efi.c | 3 --- 1 file changed, 3 deletions(-)
arch/x86/kernel/efi.c +0 -3
@@ -459,9 +459,6 @@ void __init efi_init(void) x86_platform.set_wallclock = efi_set_rtc_mmss;#endif -/* Setup for EFI runtime service */ - reboot_type =BOOT_EFI ; -#if EFI_DEBUG print_efi_memmap ();#endif
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 48/184 x86, random: make ARCH_RANDOM prompt if EMBEDDED,
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
not EXPERT
From: Romain Francoise <[email protected]>
Before v2.6.38 CONFIG_EXPERT was known as CONFIG_EMBEDDED but the Kconfig entry was not changed to match when upstream commit 628c6246d47b85f5357298601df2444d7f4dd3fd ("x86, random: Architectural inlines to get random integers with RDRAND") was backported.
--- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/Kconfig +1 -1
@@ -1430,7 +1430,7 @@ config ARCH_USES_PG_UNCACHED config ARCH_RANDOM def_bool y - prompt "x86 architectural random number generator" if EXPERT + prompt "x86 architectural random number generator" if EMBEDDED ---help--- Enable the x86 architectural RDRAND instruction (Intel Bull Mountain technology) to generate random numbers.
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 49/184 x86/xen: dont assume %ds is usable in xen_iret for
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
32-bit PVOPS.
From: Jan Beulich <[email protected]>
This fixes CVE-2013-0228 / XSA-42
Drew Jones while working on CVE-2013-0190 found that that unprivileged guest user in 32bit PV guest can use to crash the > guest with the panic like this:
-------------
general protection fault: 0000 [#1] SMP last sysfs file: /sys/devices/vbd-51712/block/xvda/dev Modules linked in: sunrpc ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4
iptable_filter ip_tables ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 xen_netfront ext4 mbcache jbd2 xen_blkfront dm_mirror dm_region_hash dm_log dm_mod [last
unloaded: scsi_wait_scan]
Pid: 1250, comm: r Not tainted 2.6.32-356.el6.i686 #1
EIP: 0061:[<c0407462>] EFLAGS: 00010086 CPU: 0
EIP is at xen_iret+0x12/0x2b
EAX: eb8d0000 EBX: 00000001 ECX: 08049860 EDX: 00000010
ESI: 00000000 EDI: 003d0f00 EBP: b77f8388 ESP: eb8d1fe0
DS: 0000 ES: 007b FS: 0000 GS: 00e0 SS: 0069
Process r (pid: 1250, ti=eb8d0000 task=c2953550 task.ti=eb8d0000)
Stack: 00000000 0027f416 00000073 00000206 b77f8364 0000007b 00000000 00000000 Call Trace: Code: c3 8b 44 24 18 81 4c 24 38 00 02 00 00 8d 64 24 30 e9 03 00 00 00 8d 76 00 f7 44 24 08 00 00 02 80 75 33 50 b8 00 e0 ff ff 21 e0 <8b> 40 10 8b 04 85 a0 f6 ab c0 8b 80 0c b0 b3 c0 f6 44 24 0d 02 EIP: [<c0407462>] xen_iret+0x12/0x2b SS:ESP 0069:eb8d1fe0 general protection fault: 0000 [#2] ---[ end trace ab0d29a492dcd330 ]--- Kernel panic - not syncing: Fatal exception Pid: 1250, comm: r Tainted: G D --------------- 2.6.32-356.el6.i686 #1 Call Trace: [<c08476df>] ? panic+0x6e/0x122 [<c084b63c>] ? oops_end+0xbc/0xd0 [<c084b260>] ? do_general_protection+0x0/0x210 [<c084a9b7>] ? error_code+0x73/ -------------
Petr says: "
I've analysed the bug and I think that xen_iret() cannot cope with mangled DS, in this case zeroed out (null selector/descriptor) by either xen_failsafe_callback() or RESTORE_REGS because the corresponding LDT entry was invalidated by the reproducer. "
Jan took a look at the preliminary patch and came up a fix that solves this problem:
"This code gets called after all registers other than those handled by IRET got already restored, hence a null selector in %ds or a non-null one that got loaded from a code or read-only data descriptor would cause a kernel mode fault (with the potential of crashing the kernel as a whole, if panic_on_oops is set)."
The way to fix this is to realize that the we can only relay on the registers that IRET restores. The two that are guaranteed are the %cs and %ss as they are always fixed GDT selectors. Also they are inaccessible from user mode - so they cannot be altered. This is the approach taken in this patch.
Another alternative option suggested by Jan would be to relay on the subtle realization that using the %ebp or %esp relative references uses the %ss segment. In which case we could switch from using %eax to %ebp and would not need the %ss over-rides. That would also require one extra instruction to compensate for the one place where the register is used as scaled index. However Andrew pointed out that is too subtle and if further work was to be done in this code-path it could escape folks attention and lead to accidents.
--- arch/x86/xen/xen-asm_32.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
arch/x86/xen/xen-asm_32.S +7 -7
@@ -88,11 +88,11 @@ ENTRY(xen_iret) */ #ifdef CONFIG_SMP GET_THREAD_INFO(%eax) - movl TI_cpu(%eax), %eax - movl __per_cpu_offset(,%eax,4), %eax - mov per_cpu__xen_vcpu(%eax), %eax + movl %ss:TI_cpu(%eax), %eax + movl %ss:__per_cpu_offset(,%eax,4), %eax + mov %ss:per_cpu__xen_vcpu(%eax), %eax #else - movl per_cpu__xen_vcpu, %eax + movl %ss:per_cpu__xen_vcpu, %eax #endif /* check IF state we're restoring */
@@ -105,11 +105,11 @@ ENTRY(xen_iret) * resuming the code, so we don't have to be worried about * being preempted to another CPU. */ - setz XEN_vcpu_info_mask(%eax) + setz %ss:XEN_vcpu_info_mask(%eax) xen_iret_start_crit: /* check for unmasked and pending */ - cmpw $0x0001, XEN_vcpu_info_pending(%eax) + cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax) /* * If there's something pending, mask events again so we can
@@ -117,7 +117,7 @@ xen_iret_start_crit: * touch XEN_vcpu_info_mask. */ jne 1f - movb $1, XEN_vcpu_info_mask(%eax) + movb $1, %ss:XEN_vcpu_info_mask(%eax) 1: popl %eax
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 049/184] x86/xen: dont assume %ds is usable in xen_iret for
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
32-bit PVOPS.From: Jan Beulich <[email protected]>
commit 13d2b4d11d69a92574a55bfd985cfb0ca77aebdc upstream.
Quoted 124 lines
This fixes CVE-2013-0228 / XSA-42
Drew Jones while working on CVE-2013-0190 found that that unprivileged guest user in 32bit PV guest can use to crash the > guest with the panic like this:
-------------
general protection fault: 0000 [#1] SMP last sysfs file: /sys/devices/vbd-51712/block/xvda/dev Modules linked in: sunrpc ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4
iptable_filterip_tablesip6t_REJECTnf_conntrack_ipv6nf_defrag_ipv6xt_statenf_conntrackip6table_filterip6_tablesipv6xen_netfrontext4 mbcache jbd2xen_blkfrontdm_mirrordm_region_hashdm_logdm_mod[last
unloaded:scsi_wait_scan]Pid: 1250, comm: r Not tainted 2.6.32-356.el6.i686 #1
EIP: 0061:[<c0407462>] EFLAGS: 00010086 CPU: 0
EIP is atxen_iret+0x12/0x2b
EAX:eb8d0000EBX: 00000001 ECX: 08049860 EDX: 00000010
ESI: 00000000 EDI:003d0f00EBP:b77f8388ESP:eb8d1fe0
DS: 0000 ES: 007b FS: 0000 GS: 00e0 SS: 0069
Process r (pid: 1250, ti=eb8d0000 task=c2953550 task.ti=eb8d0000)Stack: 00000000 0027f416 00000073 00000206 b77f8364 0000007b 00000000 00000000 Call Trace: Code: c3 8b 44 24 18 81 4c 24 38 00 02 00 00 8d 64 24 30 e9 03 00 00 00 8d 76 00 f7 44 24 08 00 00 02 80 75 33 50 b8 00 e0 ff ff 21 e0 <8b> 40 10 8b 04 85 a0 f6 ab c0 8b 80 0c b0 b3 c0 f6 44 24 0d 02 EIP: [<c0407462>] xen_iret+0x12/0x2b SS:ESP 0069:eb8d1fe0 general protection fault: 0000 [#2] ---[ end trace ab0d29a492dcd330 ]--- Kernel panic - not syncing: Fatal exception Pid: 1250, comm: r Tainted: G D --------------- 2.6.32-356.el6.i686 #1 Call Trace: [<c08476df>] ? panic+0x6e/0x122 [<c084b63c>] ? oops_end+0xbc/0xd0 [<c084b260>] ? do_general_protection+0x0/0x210 [<c084a9b7>] ? error_code+0x73/ -------------Petr says: "
I've analysed the bug and I think thatxen_iret()cannot cope with mangled DS, in this case zeroed out (null selector/descriptor) by eitherxen_failsafe_callback()orRESTORE_REGSbecause the corresponding LDT entry was invalidated by the reproducer. "Jan took a look at the preliminary patch and came up a fix that solves this problem:
"This code gets called after all registers other than those handled by IRET got already restored, hence a null selector in %ds or a non-null one that got loaded from a code or read-only data descriptor would cause a kernel mode fault (with the potential of crashing the kernel as a whole, if
panic_on_oopsis set)."The way to fix this is to realize that the we can only relay on the registers that IRET restores. The two that are guaranteed are the %cs and %ss as they are always fixed GDT selectors. Also they are inaccessible from user mode - so they cannot be altered. This is the approach taken in this patch.
Another alternative option suggested by Jan would be to relay on the subtle realization that using the %ebp or %esp relative references uses the %ss segment. In which case we could switch from using %eax to %ebp and would not need the %ss over-rides. That would also require one extra instruction to compensate for the one place where the register is used as scaled index. However Andrew pointed out that is too subtle and if further work was to be done in this code-path it could escape folks attention and lead to accidents.
Reviewed-by Petr Matousek <[email protected]>Reported-by Petr Matousek <[email protected]>Reviewed-by Andrew Cooper <[email protected]>Signed-off-by Jan Beulich <[email protected]>Signed-off-by Konrad Rzeszutek Wilk <[email protected]>[dannf: backported to Debian's 2.6.32]Signed-off-by Willy Tarreau <[email protected]>--- arch/x86/xen/xen-asm_32.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)arch/x86/xen/xen-asm_32.S +7
-7@@ -88,11 +88,11 @@ ENTRY(xen_iret) */ #ifdef CONFIG_SMP GET_THREAD_INFO(%eax) - movl TI_cpu(%eax), %eax - movl __per_cpu_offset(,%eax,4), %eax - mov per_cpu__xen_vcpu(%eax), %eax + movl %ss:TI_cpu(%eax), %eax + movl %ss:__per_cpu_offset(,%eax,4), %eax + mov %ss:per_cpu__xen_vcpu(%eax), %eax #else - movl per_cpu__xen_vcpu, %eax + movl %ss:per_cpu__xen_vcpu, %eax #endif /* check IF state we're restoring */@@ -105,11 +105,11 @@ ENTRY(xen_iret) * resuming the code, so we don't have to be worried about * being preempted to another CPU. */ - setz XEN_vcpu_info_mask(%eax) + setz %ss:XEN_vcpu_info_mask(%eax) xen_iret_start_crit: /* check for unmasked and pending */ - cmpw $0x0001, XEN_vcpu_info_pending(%eax) + cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax) /* * If there's something pending, mask events again so we can@@ -117,7 +117,7 @@ xen_iret_start_crit: * touch XEN_vcpu_info_mask. */ jne 1f - movb $1, XEN_vcpu_info_mask(%eax) + movb $1, %ss:XEN_vcpu_info_mask(%eax) 1: popl %eax
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 049/184] x86/xen: dont assume %ds is usable in xen_iret for
Quoted 9 lines · Ben Hutchings
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
32-bit PVOPS.From: Jan Beulich <[email protected]>
commit
13d2b4d11d69a92574a55bfd985cfb0ca77aebdcupstream.
Added, thanks Ben.
Willy
PATCH 50/184 x86/msr: Add capabilities check
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Alan Cox <[email protected]>
commit c903f0456bc69176912dee6dd25c6a66ee1aed00 upstream
At the moment the MSR driver only relies upon file system checks. This means that anything as root with any capability set can write to MSRs. Historically that wasn't very interesting but on modern processors the MSRs are such that writing to them provides several ways to execute arbitary code in kernel space. Sample code and documentation on doing this is circulating and MSR attacks are used on Windows 64bit rootkits already.
In the Linux case you still need to be able to open the device file so the impact is fairly limited and reduces the security of some capability and security model based systems down towards that of a generic "root owns the box" setup.
Therefore they should require CAP_SYS_RAWIO to prevent an elevation of capabilities. The impact of this is fairly minimal on most setups because they don't have heavy use of capabilities. Those using SELinux, SMACK or AppArmor rules might want to consider if their rulesets on the MSR driver could be tighter.
--- arch/x86/kernel/msr.c | 3 +++ 1 file changed, 3 insertions(+)
arch/x86/kernel/msr.c +3 -0
@@ -176,6 +176,9 @@ static int msr_open(struct inode *inode, struct file *file)struct cpuinfo_x86 *c = &cpu_data (cpu);int ret =0 ; +if (!capable (CAP_SYS_RAWIO )) +return -EPERM ; +lock_kernel (); cpu =iminor (file->f_path.dentry->d_inode);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 51/184 x86/mm: Check if PUD is large when validating a
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
kernel address
From: Mel Gorman <[email protected]>
commit 0ee364eb316348ddf3e0dfcd986f5f13f528f821 upstream.
A user reported the following oops when a backup process reads /proc/kcore:
BUG: unable to handle kernel paging request at ffffbb00ff33b000 IP: [<ffffffff8103157e>] kern_addr_valid+0xbe/0x110 [...] Call Trace: [<ffffffff811b8aaa>] read_kcore+0x17a/0x370 [<ffffffff811ad847>] proc_reg_read+0x77/0xc0 [<ffffffff81151687>] vfs_read+0xc7/0x130 [<ffffffff811517f3>] sys_read+0x53/0xa0 [<ffffffff81449692>] system_call_fastpath+0x16/0x1b
Investigation determined that the bug triggered when reading system RAM at the 4G mark. On this system, that was the first address using 1G pages for the virt->phys direct mapping so the PUD is pointing to a physical address, not a PMD page.
The problem is that the page table walker in kern_addr_valid() is not checking pud_large() and treats the physical address as if it was a PMD. If it happens to look like pmd_none then it'll silently fail, probably returning zeros instead of real data. If the data happens to look like a present PMD though, it will be walked resulting in the oops above.
This patch adds the necessary pud_large() check.
Unfortunately the problem was not readily reproducible and now they are running the backup program without accessing /proc/kcore so the patch has not been validated but I think it makes sense.
--- arch/x86/include/asm/pgtable.h | 5 +++++ arch/x86/mm/init_64.c | 3 +++ 2 files changed, 8 insertions(+)
arch/x86/include/asm/pgtable.h +5 -0
@@ -130,6 +130,11 @@ static inline unsigned long pmd_pfn(pmd_t pmd)return (pmd_val (pmd) &PTE_PFN_MASK ) >>PAGE_SHIFT ; } +static inline unsigned long pud_pfn (pud_t pud) +{ +return (pud_val (pud) &PTE_PFN_MASK ) >>PAGE_SHIFT ; +} +#define pte_page (pte) pfn_to_page(pte_pfn(pte))static inline int pmd_large (pmd_t pte)
arch/x86/mm/init_64.c +3 -0
@@ -839,6 +839,9 @@ int kern_addr_valid(unsigned long addr)if (pud_none (*pud))return 0 ; +if (pud_large (*pud)) +return pfn_valid (pud_pfn (*pud)); + pmd =pmd_offset (pud, addr);if (pmd_none (*pmd))return 0 ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 52/184 x86, mm, paravirt: Fix vmalloc_fault oops during
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
lazy MMU updates
From: Samu Kallio <[email protected]>
commit 1160c2779b826c6f5c08e5cc542de58fd1f667d5 upstream.
In paravirtualized x86_64 kernels, vmalloc_fault may cause an oops when lazy MMU updates are enabled, because set_pgd effects are being deferred.
One instance of this problem is during process mm cleanup with memory cgroups enabled. The chain of events is as follows:
- zap_pte_range enables lazy MMU updates
- zap_pte_range eventually calls mem_cgroup_charge_statistics, which accesses the vmalloc'd mem_cgroup per-cpu stat area
- vmalloc_fault is triggered which tries to sync the corresponding PGD entry with set_pgd, but the update is deferred
- vmalloc_fault oopses due to a mismatch in the PUD entries
The OOPs usually looks as so:
------------[ cut here ]------------ kernel BUG at arch/x86/mm/fault.c:396!
invalid opcode: 0000 [#1] SMP
.. snip ..
CPU 1
Pid: 10866, comm: httpd Not tainted 3.6.10-4.fc18.x86_64 #1
RIP: e030:[<ffffffff816271bf>] [<ffffffff816271bf>] vmalloc_fault+0x11f/0x208 .. snip .. Call Trace: [<ffffffff81627759>] do_page_fault+0x399/0x4b0 [<ffffffff81004f4c>] ? xen_mc_extend_args+0xec/0x110 [<ffffffff81624065>] page_fault+0x25/0x30 [<ffffffff81184d03>] ? mem_cgroup_charge_statistics.isra.13+0x13/0x50 [<ffffffff81186f78>] __mem_cgroup_uncharge_common+0xd8/0x350 [<ffffffff8118aac7>] mem_cgroup_uncharge_page+0x57/0x60 [<ffffffff8115fbc0>] page_remove_rmap+0xe0/0x150 [<ffffffff8115311a>] ? vm_normal_page+0x1a/0x80 [<ffffffff81153e61>] unmap_single_vma+0x531/0x870 [<ffffffff81154962>] unmap_vmas+0x52/0xa0 [<ffffffff81007442>] ? pte_mfn_to_pfn+0x72/0x100 [<ffffffff8115c8f8>] exit_mmap+0x98/0x170 [<ffffffff810050d9>] ? __raw_callee_save_xen_pmd_val+0x11/0x1e [<ffffffff81059ce3>] mmput+0x83/0xf0 [<ffffffff810624c4>] exit_mm+0x104/0x130 [<ffffffff8106264a>] do_exit+0x15a/0x8c0 [<ffffffff810630ff>] do_group_exit+0x3f/0xa0 [<ffffffff81063177>] sys_exit_group+0x17/0x20 [<ffffffff8162bae9>] system_call_fastpath+0x16/0x1b
Calling arch_flush_lazy_mmu_mode immediately after set_pgd makes the changes visible to the consistency checks.
RedHat-Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=914737
--- arch/x86/mm/fault.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/x86/mm/fault.c +4 -2
@@ -376,10 +376,12 @@ static noinline int vmalloc_fault(unsigned long address)if (pgd_none (*pgd_ref))return -1 ; -if (pgd_none (*pgd)) +if (pgd_none (*pgd)) {set_pgd (pgd, *pgd_ref); -else +arch_flush_lazy_mmu_mode (); + }else {BUG_ON (pgd_page_vaddr (*pgd) !=pgd_page_vaddr (*pgd_ref)); + }/* * Below here mismatches are bugs because these lower tables
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 53/184 xen/bootup: allow read_tscp call for Xen PV guests.
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Rzeszutek Wilk <[email protected]>
commit cd0608e71e9757f4dae35bcfb4e88f4d1a03a8ab upstream.
The hypervisor will trap it. However without this patch, we would crash as the .read_tscp is set to NULL. This patch fixes it and sets it to the native_read_tscp call.
--- arch/x86/xen/enlighten.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/xen/enlighten.c +2 -0
@@ -952,6 +952,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, + .read_tscp = native_read_tscp, + .iret = xen_iret, .irq_enable_sysexit = xen_sysexit,#ifdef CONFIG_X86_64
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 54/184 xen/bootup: allow {read|write}_cr8 pvops call.
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Rzeszutek Wilk <[email protected]>
commit 1a7bbda5b1ab0e02622761305a32dc38735b90b2 upstream.
We actually do not do anything about it. Just return a default value of zero and if the kernel tries to write anything but 0 we BUG_ON.
This fixes the case when an user tries to suspend the machine and it blows up in save_processor_state b/c 'read_cr8' is set to NULL and we get:
kernel BUG at /home/konrad/ssd/linux/arch/x86/include/asm/paravirt.h:100! invalid opcode: 0000 [#1] SMP
Pid: 2687, comm: init.late Tainted: G O 3.6.0upstream-00002-gac264ac-dirty #4 Bochs Bochs
RIP: e030:[<ffffffff814d5f42>] [<ffffffff814d5f42>] save_processor_state+0x212/0x270
.. snip..
Call Trace: [<ffffffff810733bf>] do_suspend_lowlevel+0xf/0xac [<ffffffff8107330c>] ? x86_acpi_suspend_lowlevel+0x10c/0x150 [<ffffffff81342ee2>] acpi_suspend_enter+0x57/0xd5
--- arch/x86/xen/enlighten.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
arch/x86/xen/enlighten.c +15 -1
@@ -776,7 +776,16 @@ static void xen_write_cr4(unsigned long cr4)native_write_cr4 (cr4); } - +#ifdef CONFIG_X86_64 +static inline unsigned long xen_read_cr8 (void ) +{ +return 0 ; +} +static inline void xen_write_cr8 (unsigned long val) +{ +BUG_ON (val); +} +#endif static int xen_write_msr_safe (unsigned int msr,unsigned low,unsigned high) {int ret;
@@ -942,6 +951,11 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .read_cr4_safe = native_read_cr4_safe, .write_cr4 = xen_write_cr4, +#ifdef CONFIG_X86_64 + .read_cr8 = xen_read_cr8, + .write_cr8 = xen_write_cr8, +#endif + .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 55/184 KVM: x86: fix for buffer overflow in handling of
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
MSR_KVM_SYSTEM_TIME (CVE-2013-1796)
From: Andy Honig <[email protected]>
commit c300aa64ddf57d9c5d9c898a64b36877345dd4a9 upstream.
If the guest sets the GPA of the time_page so that the request to update the time straddles a page then KVM will write onto an incorrect page. The write is done byusing kmap atomic to get a pointer to the page for the time structure and then performing a memcpy to that page starting at an offset that the guest controls. Well behaved guests always provide a 32-byte aligned address, however a malicious guest could use this to corrupt host kernel memory.
Tested: Tested against kvmclock unit test.
--- arch/x86/kvm/x86.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kvm/x86.c +5 -0
@@ -925,6 +925,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)/* ...but clean it before doing the actual write */ vcpu->arch.time_offset = data & ~(PAGE_MASK |1 ); +/* Check that the address is 32-byte aligned. */ +if (vcpu->arch.time_offset & + (sizeof (struct pvclock_vcpu_time_info ) -1 )) +break ; + vcpu->arch.time_page =gfn_to_page (vcpu->kvm, data >>PAGE_SHIFT );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 56/184 KVM: x86: relax MSR_KVM_SYSTEM_TIME alignment check
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Marcelo Tosatti <[email protected]>
RHEL5 i386 guests register non 32-byte aligned addresses:
kvm-clock: cpu 1, msr 0:3018aa5, secondary cpu clock
kvm-clock: cpu 2, msr 0:301f8e9, secondary cpu clock
kvm-clock: cpu 3, msr 0:302672d, secondary cpu clock
Check for an address+len that would cross page boundary instead.
--- arch/x86/kvm/x86.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/kvm/x86.c +4 -3
@@ -925,9 +925,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)/* ...but clean it before doing the actual write */ vcpu->arch.time_offset = data & ~(PAGE_MASK |1 ); -/* Check that the address is 32-byte aligned. */ -if (vcpu->arch.time_offset & - (sizeof (struct pvclock_vcpu_time_info ) -1 )) +/* Check that address+len does not cross page boundary */ +if ((vcpu->arch.time_offset + +sizeof (struct pvclock_vcpu_time_info ) -1 ) + &PAGE_MASK )break ; vcpu->arch.time_page =
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 056/184] KVM: x86: relax MSR_KVM_SYSTEM_TIME alignment check
Quoted 5 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Marcelo Tosatti <[email protected]>
This was fixed by commit 8f964525a121f2ff2df948dac908dcc65be21b5b upstream. This alternate fix avoids the need for extensive backporting.
Ben.
Quoted 34 lines
RHEL5 i386 guests register non 32-byte aligned addresses:
kvm-clock: cpu 1, msr 0:3018aa5, secondary cpu clock
kvm-clock: cpu 2, msr 0:301f8e9, secondary cpu clock
kvm-clock: cpu 3, msr 0:302672d, secondary cpu clockCheck for an address+len that would cross page boundary instead.
Signed-off-by Marcelo Tosatti <[email protected]>[dannf: backported to Debian's 2.6.32]Signed-off-by Willy Tarreau <[email protected]>--- arch/x86/kvm/x86.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)arch/x86/kvm/x86.c +4
-3@@ -925,9 +925,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)/* ...but clean it before doing the actual write */ vcpu->arch.time_offset = data & ~(PAGE_MASK |1 ); -/* Check that the address is 32-byte aligned. */ -if (vcpu->arch.time_offset & - (sizeof (struct pvclock_vcpu_time_info ) -1 )) +/* Check that address+len does not cross page boundary */ +if ((vcpu->arch.time_offset + +sizeof (struct pvclock_vcpu_time_info ) -1 ) + &PAGE_MASK )break ; vcpu->arch.time_page =
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 056/184] KVM: x86: relax MSR_KVM_SYSTEM_TIME alignment check
Quoted 9 lines · Ben Hutchings
Quoted 5 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Marcelo Tosatti <[email protected]>
This was fixed by commit
8f964525a121f2ff2df948dac908dcc65be21b5bupstream. This alternate fix avoids the need for extensive backporting.
Added, thank you Ben.
Willy
PATCH 57/184 KVM: Fix bounds checking in ioapic indirect register
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
reads (CVE-2013-1798)
From: Andy Honig <[email protected]>
commit a2c118bfab8bc6b8bb213abfc35201e441693d55 upstream.
If the guest specifies a IOAPIC_REG_SELECT with an invalid value and follows that with a read of the IOAPIC_REG_WINDOW KVM does not properly validate that request. ioapic_read_indirect contains an ASSERT(redir_index < IOAPIC_NUM_PINS), but the ASSERT has no effect in non-debug builds. In recent kernels this allows a guest to cause a kernel oops by reading invalid memory. In older kernels (pre-3.3) this allows a guest to read from large ranges of host memory.
Tested: tested against apic unit tests.
--- virt/kvm/ioapic.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
virt/kvm/ioapic.c +5 -2
@@ -71,9 +71,12 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,u32 redir_index = (ioapic->ioregsel -0x10 ) >>1 ;u64 redir_content; -ASSERT (redir_index <IOAPIC_NUM_PINS ); +if (redir_index <IOAPIC_NUM_PINS ) + redir_content = + ioapic->redirtbl[redir_index].bits; +else + redir_content = ~0ULL ; - redir_content = ioapic->redirtbl[redir_index].bits; result = (ioapic->ioregsel &0x1 ) ? (redir_content >>32 ) &0xffffffff : redir_content &0xffffffff ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 58/184 KVM: x86: invalid opcode oops on SET_SREGS with
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
OSXSAVE bit set (CVE-2012-4461)
From: Petr Matousek <[email protected]>
commit 6d1068b3a98519247d8ba4ec85cd40ac136dbdf9 upstream.
On hosts without the XSAVE support unprivileged local user can trigger oops similar to the one below by setting X86_CR4_OSXSAVE bit in guest cr4 register using KVM_SET_SREGS ioctl and later issuing KVM_RUN ioctl.
invalid opcode: 0000 [#2] SMP
Modules linked in: tun ip6table_filter ip6_tables ebtable_nat ebtables
...
Pid: 24935, comm: zoog_kvm_monito Tainted: G D 3.2.0-3-686-pae
EIP: 0060:[<f8b9550c>] EFLAGS: 00210246 CPU: 0
EIP is at kvm_arch_vcpu_ioctl_run+0x92a/0xd13 [kvm]
EAX: 00000001 EBX: 000f387e ECX: 00000000 EDX: 00000000
ESI: 00000000 EDI: 00000000 EBP: ef5a0060 ESP: d7c63e70
DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Process zoog_kvm_monito (pid: 24935, ti=d7c62000 task=ed84a0c0 task.ti=d7c62000)
Stack: 00000001 f70a1200 f8b940a9 ef5a0060 00000000 00200202 f8769009 00000000 ef5a0060 000f387e eda5c020 8722f9c8 00015bae 00000000 ed84a0c0 ed84a0c0 c12bf02d 0000ae80 ef7f8740 fffffffb f359b740 ef5a0060 f8b85dc1 0000ae80 Call Trace: [<f8b940a9>] ? kvm_arch_vcpu_ioctl_set_sregs+0x2fe/0x308 [kvm] ... [<c12bfb44>] ? syscall_call+0x7/0xb Code: 89 e8 e8 14 ee ff ff ba 00 00 04 00 89 e8 e8 98 48 ff ff 85 c0 74
1e 83 7d 48 00 75 18 8b 85 08 07 00 00 31 c9 8b 95 0c 07 00 00 <0f> 01 d1 c7 45 48 01 00 00 00 c7 45 1c 01 00 00 00 0f ae f0 89
EIP: [<f8b9550c>] kvm_arch_vcpu_ioctl_run+0x92a/0xd13 [kvm] SS:ESP 0068:d7c63e70
QEMU first retrieves the supported features via KVM_GET_SUPPORTED_CPUID and then sets them later. So guest's X86_FEATURE_XSAVE should be masked out on hosts without X86_FEATURE_XSAVE, making kvm_set_cr4 with X86_CR4_OSXSAVE fail. Userspaces that allow specifying guest cpuid with X86_FEATURE_XSAVE even on hosts that do not support it, might be susceptible to this attack from inside the guest as well.
Allow setting X86_CR4_OSXSAVE bit only if host has XSAVE support.
[bwh: Backported to 2.6.32: XSAVE is not supported at all, so always
deny setting OSXSAVE]
--- arch/x86/kvm/x86.c | 3 +++ 1 file changed, 3 insertions(+)
arch/x86/kvm/x86.c +3 -0
@@ -4719,6 +4719,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,int pending_vec, max_bits;struct descriptor_table dt; +if (sregs->cr4 &X86_CR4_OSXSAVE ) +return -EINVAL ; +vcpu_load (vcpu); dt.limit = sregs->idt.limit;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 058/184] KVM: x86: invalid opcode oops on SET_SREGS with
Quoted 46 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
OSXSAVE bit set (CVE-2012-4461)From: Petr Matousek <[email protected]>
commit
6d1068b3a98519247d8ba4ec85cd40ac136dbdf9upstream.On hosts without the XSAVE support unprivileged local user can trigger oops similar to the one below by setting
X86_CR4_OSXSAVEbit in guest cr4 register usingKVM_SET_SREGSioctl and later issuingKVM_RUNioctl.invalid opcode: 0000 [#2] SMP
Modules linked in: tun ip6table_filter ip6_tables ebtable_nat ebtables...
Pid: 24935, comm:zoog_kvm_monitoTainted: G D 3.2.0-3-686-pae
EIP: 0060:[<f8b9550c>] EFLAGS: 00210246 CPU: 0
EIP is atkvm_arch_vcpu_ioctl_run+0x92a/0xd13[kvm]
EAX: 00000001 EBX:000f387eECX: 00000000 EDX: 00000000
ESI: 00000000 EDI: 00000000 EBP:ef5a0060ESP:d7c63e70
DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Processzoog_kvm_monito(pid: 24935, ti=d7c62000 task=ed84a0c0 task.ti=d7c62000)Stack: 00000001 f70a1200 f8b940a9 ef5a0060 00000000 00200202 f8769009 00000000 ef5a0060 000f387e eda5c020 8722f9c8 00015bae 00000000 ed84a0c0 ed84a0c0 c12bf02d 0000ae80 ef7f8740 fffffffb f359b740 ef5a0060 f8b85dc1 0000ae80 Call Trace: [<f8b940a9>] ? kvm_arch_vcpu_ioctl_set_sregs+0x2fe/0x308 [kvm] ... [<c12bfb44>] ? syscall_call+0x7/0xb Code: 89 e8 e8 14 ee ff ff ba 00 00 04 00 89 e8 e8 98 48 ff ff 85 c0 741e 83 7d 48 00 75 18 8b 85 08 07 00 00 31 c9 8b 95 0c 07 00 00 <0f> 01 d1 c7 45 48 01 00 00 00 c7 45 1c 01 00 00 00 0f ae f0 89
EIP: [<f8b9550c>]kvm_arch_vcpu_ioctl_run+0x92a/0xd13[kvm] SS:ESP 0068:d7c63e70QEMU first retrieves the supported features via
KVM_GET_SUPPORTED_CPUIDand then sets them later. So guest'sX86_FEATURE_XSAVEshould be masked out on hosts withoutX86_FEATURE_XSAVE, makingkvm_set_cr4withX86_CR4_OSXSAVEfail. Userspaces that allow specifying guest cpuid withX86_FEATURE_XSAVEeven on hosts that do not support it, might be susceptible to this attack from inside the guest as well.
Quoted 6 lines
Allow setting
X86_CR4_OSXSAVEbit only if host has XSAVE support.Signed-off-by Petr Matousek <[email protected]>Signed-off-by Marcelo Tosatti <[email protected]>[bwh: Backported to 2.6.32: XSAVE is not supported at all, so always
deny setting OSXSAVE]
Quoted 19 lines
Signed-off-by Willy Tarreau <[email protected]>--- arch/x86/kvm/x86.c | 3 +++ 1 file changed, 3 insertions(+)arch/x86/kvm/x86.c +3
-0@@ -4719,6 +4719,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,int pending_vec, max_bits;struct descriptor_table dt; +if (sregs->cr4 &X86_CR4_OSXSAVE ) +return -EINVAL ; +vcpu_load (vcpu); dt.limit = sregs->idt.limit;
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 058/184] KVM: x86: invalid opcode oops on SET_SREGS with
Quoted 6 lines · Ben Hutchings
Quoted 4 lines
Signed-off-by Petr Matousek <[email protected]>Signed-off-by Marcelo Tosatti <[email protected]>[bwh: Backported to 2.6.32: XSAVE is not supported at all, so always
deny setting OSXSAVE]Signed-off-by Ben Hutchings <[email protected]>
added, thanks Ben.
Willy
PATCH 59/184 MCE: Fix vm86 handling for 32bit mce handler
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Andi Kleen <[email protected]>
commit a129a7c84582629741e5fa6f40026efcd7a65bd4 upstream.
When running on 32bit the mce handler could misinterpret vm86 mode as ring 0. This can affect whether it does recovery or not; it was possible to panic when recovery was actually possible.
Fix this by always forcing vm86 to look like ring 3.
[ Backport to 3.0 notes:
Things changed there slightly:
- move mce_get_rip() up. It fills up m->cs and m->ip values which are evaluated in mce_severity(). Therefore move it up right before the mce_severity call. This seem to be another bug in 3.0?
- Place the backport (fix m->cs in V86 case) to where m->cs gets filled which is mce_get_rip() in 3.0
]
--- arch/x86/kernel/cpu/mcheck/mce.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/mcheck/mce.c +8 -1
@@ -431,6 +431,13 @@ static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)if (regs && (m->mcgstatus & (MCG_STATUS_RIPV |MCG_STATUS_EIPV ))) { m->ip = regs->ip; m->cs = regs->cs; +/* +* When in VM86 mode make the cs look like ring 3 +* always. This is a lie, but it's better than passing +* the additional vm86 bit around everywhere. +*/ +if (v8086_mode (regs)) + m->cs |=3 ; }else { m->ip =0 ; m->cs =0 ;
@@ -968,6 +975,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)*/ add_taint (TAINT_MACHINE_CHECK ); +mce_get_rip (&m, regs); severity =mce_severity (&m, tolerant,NULL );/*
@@ -1006,7 +1014,6 @@ void do_machine_check(struct pt_regs *regs, long error_code)if (severity ==MCE_AO_SEVERITY &&mce_usable_address (&m))mce_ring_add (m.addr >>PAGE_SHIFT ); -mce_get_rip (&m, regs);mce_log (&m);if (severity > worst) {
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 60/184 ACPI / cpuidle: Fix NULL pointer issues when cpuidle
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
is disabled
From: Konrad Rzeszutek Wilk <[email protected]>
commit b88a634a903d9670aa5f2f785aa890628ce0dece upstream.
If cpuidle is disabled, that means that:
per_cpu(acpi_cpuidle_device, pr->id)
is set to NULL as the acpi_processor_power_init ends up failing at
retval = cpuidle_register_driver(&acpi_idle_driver)
(in acpi_processor_power_init) and never sets the per_cpu idle device. So when acpi_processor_hotplug on CPU online notification tries to reference said device it crashes:
cpu 3 spinlock event irq 62
BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: [<ffffffff81381013>] acpi_processor_setup_cpuidle_cx+0x3f/0x105 PGD a259b067 PUD ab38b067 PMD 0 Oops: 0002 [#1] SMP odules linked in: dm_multipath dm_mod xen_evtchn iscsi_boot_sysfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi libcrc32c crc32c nouveau mxm_wmi wmi radeon ttm sg sr_mod sd_mod cdrom ata_generic ata_piix libata crc32c_intel scsi_mod atl1c i915 fbcon tileblit font bitblit softcursor drm_kms_helper video xen_blkfront xen_netfront fb_sys_fops sysimgblt sysfillrect syscopyarea xenfs xen_privcmd mperf CPU 1 Pid: 3047, comm: bash Not tainted 3.8.0-rc3upstream-00250-g165c029 #1 MSI MS-7680/H61M-P23 (MS-7680) RIP: e030:[<ffffffff81381013>] [<ffffffff81381013>] acpi_processor_setup_cpuidle_cx+0x3f/0x105 RSP: e02b:ffff88001742dca8 EFLAGS: 00010202 RAX: 0000000000010be9 RBX: ffff8800a0a61800 RCX: ffff880105380000 RDX: 0000000000000003 RSI: 0000000000000200 RDI: ffff8800a0a61800 RBP: ffff88001742dce8 R08: ffffffff81812360 R09: 0000000000000200 R10: aaaaaaaaaaaaaaaa R11: 0000000000000001 R12: ffff8800a0a61800 R13: 00000000ffffff01 R14: 0000000000000000 R15: ffffffff81a907a0 FS: 00007fd6942f7700(0000) GS:ffff880105280000(0000) knlGS:0000000000000000 CS: e033 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000004 CR3: 00000000a6773000 CR4: 0000000000042660 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process bash (pid: 3047, threadinfo ffff88001742c000, task ffff880017944000) Stack: 0000000000000150 ffff880100f59e00 ffff88001742dcd8 ffff8800a0a61800 0000000000000000 00000000ffffff01 0000000000000000 ffffffff81a907a0 ffff88001742dd18 ffffffff813815b1 ffff88001742dd08 ffffffff810ae336 Call Trace: [<ffffffff813815b1>] acpi_processor_hotplug+0x7c/0x9f [<ffffffff810ae336>] ? schedule_delayed_work_on+0x16/0x20 [<ffffffff8137ee8f>] acpi_cpu_soft_notify+0x90/0xca [<ffffffff8166023d>] notifier_call_chain+0x4d/0x70 [<ffffffff810bc369>] __raw_notifier_call_chain+0x9/0x10 [<ffffffff81094a4b>] __cpu_notify+0x1b/0x30 [<ffffffff81652cf7>] _cpu_up+0x103/0x14b [<ffffffff81652e18>] cpu_up+0xd9/0xec [<ffffffff8164a254>] store_online+0x94/0xd0 [<ffffffff814122fb>] dev_attr_store+0x1b/0x20 [<ffffffff81216404>] sysfs_write_file+0xf4/0x170
This patch fixes it.
--- drivers/acpi/processor_idle.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/acpi/processor_idle.c +3 -0
@@ -1071,6 +1071,9 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)return -EINVAL ; } +if (!dev) +return -EINVAL ; + dev->cpu = pr->id;for (i =0 ; i <CPUIDLE_STATE_MAX ; i++) { dev->states[i].name[0 ] ='\0' ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 61/184 PCI/PM: Clean up PME state when removing a device
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "Rafael J. Wysocki" <[email protected]>
commit 249bfb83cf8ba658955f0245ac3981d941f746ee upstream.
Devices are added to pci_pme_list when drivers use pci_enable_wake() or pci_wake_from_d3(), but they aren't removed from the list unless the driver explicitly disables wakeup. Many drivers never disable wakeup, so their devices remain on the list even after they are removed, e.g., via hotplug. A subsequent PME poll will oops when it tries to touch the device.
This patch disables PME# on a device before removing it, which removes the device from pci_pme_list. This is safe even if the device never had PME# enabled.
This oops can be triggered by unplugging a Thunderbolt ethernet adapter on a Macbook Pro, as reported by Daniel below.
[bhelgaas: changelog]
Reference: http://lkml.kernel.org/r/CAMVG2svG21yiM1wkH4_2pen2n+cr2-Zv7TbH3Gj+8MwevZjDbw@mail.gmail.com
--- drivers/pci/remove.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/pci/remove.c +2 -0
@@ -19,6 +19,8 @@ static void pci_free_resources(struct pci_dev *dev)static void pci_stop_dev (struct pci_dev *dev) { +pci_pme_active (dev, false); +if (dev->is_added) {pci_proc_detach_device (dev);pci_remove_sysfs_dev_files (dev);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 061/184] PCI/PM: Clean up PME state when removing a device
Quoted 15 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "Rafael J. Wysocki" <[email protected]>
commit
249bfb83cf8ba658955f0245ac3981d941f746eeupstream.Devices are added to
pci_pme_listwhen drivers usepci_enable_wake()orpci_wake_from_d3(), but they aren't removed from the list unless the driver explicitly disables wakeup. Many drivers never disable wakeup, so their devices remain on the list even after they are removed, e.g., via hotplug. A subsequent PME poll will oops when it tries to touch the device.
Quoted 3 lines
This patch disables PME# on a device before removing it, which removes the device from
pci_pme_list. This is safe even if the device never had PME# enabled.
There's no such list in 2.6.32, so I don't think this is needed.
Ben.
Quoted 27 lines
This oops can be triggered by unplugging a Thunderbolt ethernet adapter on a Macbook Pro, as reported by Daniel below.
[bhelgaas: changelog]
Reference: http://lkml.kernel.org/r/CAMVG2svG21yiM1wkH4_2pen2n+cr2-Zv7TbH3Gj+8MwevZjDbw@mail.gmail.comReported-and-tested-by Daniel J Blueman <[email protected]>Signed-off-by Rafael J. Wysocki <[email protected]>Signed-off-by Bjorn Helgaas <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>Signed-off-by Willy Tarreau <[email protected]>--- drivers/pci/remove.c | 2 ++ 1 file changed, 2 insertions(+)drivers/pci/remove.c +2
-0@@ -19,6 +19,8 @@ static void pci_free_resources(struct pci_dev *dev)static void pci_stop_dev (struct pci_dev *dev) { +pci_pme_active (dev, false); +if (dev->is_added) {pci_proc_detach_device (dev);pci_remove_sysfs_dev_files (dev);
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 061/184] PCI/PM: Clean up PME state when removing a device
Quoted 16 lines · Ben Hutchings
Quoted 15 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: "Rafael J. Wysocki" <[email protected]>
commit
249bfb83cf8ba658955f0245ac3981d941f746eeupstream.Devices are added to
pci_pme_listwhen drivers usepci_enable_wake()orpci_wake_from_d3(), but they aren't removed from the list unless the driver explicitly disables wakeup. Many drivers never disable wakeup, so their devices remain on the list even after they are removed, e.g., via hotplug. A subsequent PME poll will oops when it tries to touch the device.
Quoted 5 lines
Quoted 3 lines
This patch disables PME# on a device before removing it, which removes the device from
pci_pme_list. This is safe even if the device never had PME# enabled.There's no such list in 2.6.32, so I don't think this is needed.
Dropped, thanks !
Willy
PATCH 62/184 alpha: Add irongate_io to PCI bus resources
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Jay Estabrook <[email protected]>
commit aa8b4be3ac049c8b1df2a87e4d1d902ccfc1f7a9 upstream.
Fixes a NULL pointer dereference at boot on UP1500.
--- arch/alpha/kernel/sys_nautilus.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/alpha/kernel/sys_nautilus.c +5 -0
@@ -189,6 +189,10 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr)extern void free_reserved_mem (void *,void *);extern void pcibios_claim_one_bus (struct pci_bus *); +static struct resource irongate_io = { + .name ="Irongate PCI IO" , + .flags =IORESOURCE_IO , +};static struct resource irongate_mem = { .name ="Irongate PCI MEM" , .flags =IORESOURCE_MEM ,
@@ -210,6 +214,7 @@ nautilus_init_pci(void) irongate =pci_get_bus_and_slot (0 ,0 ); bus->self = irongate; + bus->resource[0 ] = &irongate_io; bus->resource[1 ] = &irongate_mem;pci_bus_size_bridges (bus);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 63/184 PARISC: fix user-triggerable panic on parisc
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]>
commit 441a179dafc0f99fc8b3a8268eef66958621082e upstream.
int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset,
unsigned int sigsetsize)
{
sigset_t old_set, new_set;
int ret;
if (set && get_sigset32(set, &new_set, sigsetsize))...
static intget_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
{
compat_sigset_t s;
int r;
if (sz != sizeof *set) panic("put_sigset32()");In other words, rt_sigprocmask(69, (void *)69, 69) done by 32bit process will promptly panic the box.
--- arch/parisc/kernel/signal32.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/parisc/kernel/signal32.c +4 -2
@@ -68,7 +68,8 @@ put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) {compat_sigset_t s; -if (sz !=sizeof *set)panic ("put_sigset32()" ); +if (sz !=sizeof *set) +return -EINVAL ;sigset_64to32 (&s, set);return copy_to_user (up, &s,sizeof s);
@@ -80,7 +81,8 @@ get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)compat_sigset_t s;int r; -if (sz !=sizeof *set)panic ("put_sigset32()" ); +if (sz !=sizeof *set) +return -EINVAL ;if ((r =copy_from_user (&s, up, sz)) ==0 ) {sigset_32to64 (set, &s);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 64/184 serial: 8250, increase PASS_LIMIT
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 Slaby <[email protected]>
With virtual machines like qemu, it's pretty common to see "too much work for irq4" messages nowadays. This happens when a bunch of output is printed on the emulated serial console. This is caused by too low PASS_LIMIT. When ISR loops more than the limit, it spits the message.
I've been using a kernel with doubled the limit and I couldn't see no problems. Maybe it's time to get rid of the message now?
[2.6.32: background info from Ram Gupta]
Quoted 4 lines
I need a patch for serial driver that increases
PASS_LIMITmerged in 3.1. I am using 2.6.32 kernel which experiences kernel panic occasionally. It will be great if you can backport to 2.6.32 and 3.0 kernel. The commit ID ise7328ae1serial: 8250, increasePASS_LIMIT
--- drivers/serial/8250.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/serial/8250.c +1 -1
@@ -81,7 +81,7 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ #define DEBUG_INTR(fmt...) do { } while (0)#endif -#define PASS_LIMIT 256 +#define PASS_LIMIT 512#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 65/184 drivers/char/ipmi: memcpy, need additional 2 bytes
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
to avoid memory overflow
From: Chen Gang <[email protected]>
commit a5f2b3d6a738e7d4180012fe7b541172f8c8dcea upstream.
When calling memcpy, read_data and write_data need additional 2 bytes.
write_data:
for checking: "if (size > IPMI_MAX_MSG_LENGTH)"
for operating: "memcpy(bt->write_data + 3, data + 1, size - 1)"
read_data:
for checking: "if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH)"
for operating: "memcpy(data + 2, bt->read_data + 4, msg_len - 2)"--- drivers/char/ipmi/ipmi_bt_sm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/char/ipmi/ipmi_bt_sm.c +2 -2
@@ -95,9 +95,9 @@ struct si_sm_data {enum bt_states state;unsigned char seq;/* BT sequence number */ struct si_sm_io *io; -unsigned char write_data[IPMI_MAX_MSG_LENGTH ]; +unsigned char write_data[IPMI_MAX_MSG_LENGTH +2 ];/* +2 for memcpy */ int write_count; -unsigned char read_data[IPMI_MAX_MSG_LENGTH ]; +unsigned char read_data[IPMI_MAX_MSG_LENGTH +2 ];/* +2 for memcpy */ int read_count;int truncated;long timeout;/* microseconds countdown */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 66/184 w1: fix oops when w1_search is called from netlink
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
connector
From: Marcin Jurkowski <[email protected]>
commit 9d1817cab2f030f6af360e961cc69bb1da8ad765 upstream.
Quoted 5 lines · Sven Geggus
This is the bad commit I found doing git bisect:
04f482faf50535229a5a5c8d629cf963899f857cis the first bad commit commit04f482faf50535229a5a5c8d629cf963899f857cAuthor: Patrick McHardy <[email protected]> Date: Mon Mar 28 08:39:36 2011 +0000
Good job. I was too lazy to bisect for bad commit;)
Reading the code I found problematic kthread_should_stop call from netlink connector which causes the oops. After applying a patch, I've been testing owfs+w1 setup for nearly two days and it seems to work very reliable (no hangs, no memleaks etc).
More detailed description and possible fix is given below:
Function w1_search can be called from either kthread or netlink callback. While the former works fine, the latter causes oops due to kthread_should_stop invocation.
This patch adds a check if w1_search is serving netlink command, skipping kthread_should_stop invocation if so.
--- drivers/w1/w1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/w1/w1.c +2 -1
@@ -918,7 +918,8 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb tmp64 = (triplet_ret >>2 ); rn |= (tmp64 << i); -if (kthread_should_stop ()) { +/* ensure we're called from kthread and not by netlink callback */ +if (!dev->priv &&kthread_should_stop ()) {dev_dbg (&dev->dev,"Abort w1_search\n" );return ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 67/184 staging: comedi: ni_labpc: correct differential
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
channel sequence for AI commands
From: Ian Abbott <[email protected]>
Commit 4c4bc25d0fa6beaf054c0b4c3b324487f266c820 upstream.
Tuomas <tvainikk _at_ gmail _dot_ com> reported problems getting meaningful output from a Lab-PC+ in differential mode for AI cmds, but AI insn reads gave correct readings. He tracked it down to two problems, one of which is addressed by this patch.
It seems the setting of the channel bits for particular scanning modes was incorrect for differential mode. (Only half the number of channels are available in differential mode; comedi refers to them as channels 0, 1, 2 and 3, but the hardware documentation refers to them as channels 0, 2, 4 and 6.) In differential mode, the setting of the channel enable bits in the command1 register should depend on whether the scan enable bit is set. Effectively, we need to double the comedi channel number when the scan enable bit is not set in differential mode. The scan enable bit gets set when the AI scan mode is MODE_MULT_CHAN_UP or MODE_MULT_CHAN_DOWN, and gets cleared when the AI scan mode is MODE_SINGLE_CHAN or MODE_SINGLE_CHAN_INTERVAL. The existing test for whether the comedi channel number needs to be doubled in differential mode is incorrect in labpc_ai_cmd(). This patch corrects the test.
Thanks to Tuomas for suggesting the fix.
--- drivers/staging/comedi/drivers/ni_labpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/staging/comedi/drivers/ni_labpc.c +3 -1
@@ -1178,7 +1178,9 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)else channel =CR_CHAN (cmd->chanlist[0 ]);/* munge channel bits for differential / scan disabled mode */ -if (labpc_ai_scan_mode (cmd) !=MODE_SINGLE_CHAN && aref ==AREF_DIFF ) +if ((labpc_ai_scan_mode (cmd) ==MODE_SINGLE_CHAN || +labpc_ai_scan_mode (cmd) ==MODE_SINGLE_CHAN_INTERVAL ) && + aref ==AREF_DIFF ) channel *=2 ; devpriv->command1_bits |=ADC_CHAN_BITS (channel); devpriv->command1_bits |= thisboard->ai_range_code[range];
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 68/184 staging: comedi: ni_labpc: set up command4 register
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
*after* command3
From: Ian Abbott <[email protected]>
Commit 22056e2b46246d97ff0f7c6e21a77b8daa07f02c upstream.
Tuomas <tvainikk _at_ gmail _dot_ com> reported problems getting meaningful output from a Lab-PC+ in differential mode for AI cmds, but AI insn reads gave correct readings. He tracked it down to two problems, one of which is addressed by this patch.
It seems that writing to the command3 register after writing to the command4 register in labpc_ai_cmd() messes up the differential reference bit setting in the command4 register. Set up the command4 register after the command3 register (as in labpc_ai_rinsn()) to avoid the problem.
Thanks to Tuomas for suggesting the fix.
--- drivers/staging/comedi/drivers/ni_labpc.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-)
drivers/staging/comedi/drivers/ni_labpc.c +16 -15
@@ -1195,21 +1195,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->write_byte (devpriv->command1_bits, dev->iobase +COMMAND1_REG ); } -/* setup any external triggering/pacing (command4 register) */ - devpriv->command4_bits =0 ; -if (cmd->convert_src !=TRIG_EXT ) - devpriv->command4_bits |=EXT_CONVERT_DISABLE_BIT ; -/* XXX should discard first scan when using interval scanning -* since manual says it is not synced with scan clock */ -if (labpc_use_continuous_mode (cmd) ==0 ) { - devpriv->command4_bits |=INTERVAL_SCAN_EN_BIT ; -if (cmd->scan_begin_src ==TRIG_EXT ) - devpriv->command4_bits |=EXT_SCAN_EN_BIT ; - } -/* single-ended/differential */ -if (aref ==AREF_DIFF ) - devpriv->command4_bits |=ADC_DIFF_BIT ; - devpriv->write_byte (devpriv->command4_bits, dev->iobase +COMMAND4_REG ); devpriv->write_byte (cmd->chanlist_len, dev->iobase +INTERVAL_COUNT_REG );
@@ -1287,6 +1272,22 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT ; devpriv->write_byte (devpriv->command3_bits, dev->iobase +COMMAND3_REG ); +/* setup any external triggering/pacing (command4 register) */ + devpriv->command4_bits =0 ; +if (cmd->convert_src !=TRIG_EXT ) + devpriv->command4_bits |=EXT_CONVERT_DISABLE_BIT ; +/* XXX should discard first scan when using interval scanning +* since manual says it is not synced with scan clock */ +if (labpc_use_continuous_mode (cmd) ==0 ) { + devpriv->command4_bits |=INTERVAL_SCAN_EN_BIT ; +if (cmd->scan_begin_src ==TRIG_EXT ) + devpriv->command4_bits |=EXT_SCAN_EN_BIT ; + } +/* single-ended/differential */ +if (aref ==AREF_DIFF ) + devpriv->command4_bits |=ADC_DIFF_BIT ; + devpriv->write_byte (devpriv->command4_bits, dev->iobase +COMMAND4_REG ); +/* startup aquisition */ /* command2 reg */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 69/184 staging: comedi: comedi_test: fix race when
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
cancelling command
From: Ian Abbott <[email protected]>
commit c0729eeefdcd76db338f635162bf0739fd2c5f6f upstream.
�ric Piel reported a kernel oops in the "comedi_test" module. It was a NULL pointer dereference within waveform_ai_interrupt() (actually a timer function) that sometimes occurred when a running asynchronous command is cancelled (either by the COMEDI_CANCEL ioctl or by closing the device file).
This seems to be a race between the caller of waveform_ai_cancel() which on return from that function goes and tears down the running command, and the timer function which uses the command. In particular, async->cmd.chanlist gets freed (and the pointer set to NULL) by do_become_nonbusy() in "comedi_fops.c" but a previously scheduled waveform_ai_interrupt() timer function will dereference that pointer regardless, leading to the oops.
Fix it by replacing the del_timer() call in waveform_ai_cancel() with del_timer_sync().
--- drivers/staging/comedi/drivers/comedi_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/comedi/drivers/comedi_test.c +1 -1
@@ -450,7 +450,7 @@ static int waveform_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { devpriv->timer_running =0 ; -del_timer (&devpriv->timer); +del_timer_sync (&devpriv->timer);return 0 ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 70/184 staging: comedi: fix memory leak for saved channel
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
list
From: Ian Abbott <[email protected]>
commit c8cad4c89ee3b15935c532210ae6ebb5c0a2734d upstream.
When do_cmd_ioctl() allocates memory for the kernel copy of a channel list, it frees any previously allocated channel list in async->cmd.chanlist and replaces it with the new one. However, if the device is ever removed (or "detached") the cleanup code in cleanup_device() in "drivers.c" does not free this memory so it is lost.
A sensible place to free the kernel copy of the channel list is in do_become_nonbusy() as at that point the comedi asynchronous command associated with the channel list is no longer valid. Free the channel list in do_become_nonbusy() instead of do_cmd_ioctl() and clear the pointer to prevent it being freed more than once.
Note that cleanup_device() could be called at an inappropriate time while the comedi device is open, but that's a separate bug not related to this this patch.
--- drivers/staging/comedi/comedi_fops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/staging/comedi/comedi_fops.c +2 -1
@@ -1035,7 +1035,6 @@ static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file) goto cleanup; } -kfree (async->cmd.chanlist); async->cmd = user_cmd; async->cmd.data =NULL ;/* load channel/gain list */
@@ -1759,6 +1758,8 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)if (async) {comedi_reset_async_buf (async); async->inttrig =NULL ; +kfree (async->cmd.chanlist); + async->cmd.chanlist =NULL ; }else {printk (KERN_ERR "BUG: (?) do_become_nonbusy called with async=0\n" );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 71/184 staging: comedi: s626: dont dereference insn->data
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 b655c2c4782ed3e2e71d2608154e295a3e860311 upstream.
s626_enc_insn_config() is incorrectly dereferencing insn->data which is a pointer to user memory. It should be dereferencing the separate data parameter that points to a copy of the data in kernel memory.
--- drivers/staging/comedi/drivers/s626.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/comedi/drivers/s626.c +1 -1
@@ -2330,7 +2330,7 @@ static int s626_enc_insn_config(struct comedi_device *dev,/* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ k->SetMode (dev, k, Setup, TRUE); -Preload (dev, k, *(insn->data)); +Preload (dev, k, data[0 ]); k->PulseIndex (dev, k);SetLatchSource (dev, k, valueSrclatch); k->SetEnable (dev, k, (uint16_t ) (enab !=0 ));
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 72/184 staging: comedi: jr3_pci: fix iomem dereference
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 e1878957b4676a17cf398f7f5723b365e9a2ca48 upstream.
Correct a direct dereference of I/O memory to use an appropriate I/O memory access function. Note that the pointer being dereferenced is not currently tagged with __iomem but I plan to correct that for 3.7.
--- drivers/staging/comedi/drivers/jr3_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/comedi/drivers/jr3_pci.c +1 -1
@@ -917,7 +917,7 @@ static int jr3_pci_attach(struct comedi_device *dev, }/* Reset DSP card */ - devpriv->iobase->channel[0 ].reset =0 ; +writel (0 , &devpriv->iobase->channel[0 ].reset); result =comedi_load_firmware (dev,"jr3pci.idm" , jr3_download_firmware);printk ("Firmare load %d\n" , result);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 73/184 staging: comedi: dont dereference user memory for
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
INSN_INTTRIG
From: Ian Abbott <[email protected]>
commit 5d06e3df280bd230e2eadc16372e62818c63e894 upstream.
parse_insn() is dereferencing the user-space pointer insn->data directly when handling the INSN_INTTRIG comedi instruction. It shouldn't be using insn->data at all; it should be using the separate data pointer passed to the function. Fix it.
--- drivers/staging/comedi/comedi_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/comedi/comedi_fops.c +1 -1
@@ -809,7 +809,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = -EAGAIN ;break ; } - ret = s->async->inttrig (dev, s, insn->data[0 ]); + ret = s->async->inttrig (dev, s, data[0 ]);if (ret >=0 ) ret =1 ;break ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 74/184 staging: comedi: check s->async for poll(), read()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
and write()
From: Ian Abbott <[email protected]>
commit cc400e185c07c15a42d2635995f422de5b94b696 upstream.
Some low-level comedi drivers (incorrectly) point dev->read_subdev or dev->write_subdev to a subdevice that does not support asynchronous commands. Comedi's poll(), read() and write() file operation handlers assume these subdevices do support asynchronous commands. In particular, they assume s->async is valid (where s points to the read or write subdevice), which it won't be if it has been set incorrectly. This can lead to a NULL pointer dereference.
Check s->async is non-NULL in comedi_poll(), comedi_read() and comedi_write() to avoid the bug.
--- drivers/staging/comedi/comedi_fops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/staging/comedi/comedi_fops.c +4 -4
@@ -1498,7 +1498,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) mask =0 ; read_subdev =comedi_get_read_subdevice (dev_file_info); -if (read_subdev) { +if (read_subdev && read_subdev->async) {poll_wait (file, &read_subdev->async->wait_head, wait);if (!read_subdev->busy || comedi_buf_read_n_available(read_subdev->async) > 0
@@ -1508,7 +1508,7 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) } } write_subdev =comedi_get_write_subdevice (dev_file_info); -if (write_subdev) { +if (write_subdev && write_subdev->async) {poll_wait (file, &write_subdev->async->wait_head, wait);comedi_buf_write_alloc (write_subdev->async, write_subdev->async->prealloc_bufsz);
@@ -1550,7 +1550,7 @@ static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes, } s =comedi_get_write_subdevice (dev_file_info); -if (s ==NULL ) { +if (s ==NULL || s->async ==NULL ) { retval = -EIO ; goto done; }
@@ -1658,7 +1658,7 @@ static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes, } s =comedi_get_read_subdevice (dev_file_info); -if (s ==NULL ) { +if (s ==NULL || s->async ==NULL ) { retval = -EIO ; goto done; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 75/184 staging: comedi: das08: Correct AO output for
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
das08jr-16-ao
From: Ian Abbott <[email protected]>
commit 61ed59ed09e6ad2b8395178ea5ad5f653bba08e3 upstream.
Don't zero out bits 15..12 of the data value in das08jr_ao_winsn() as that knobbles the upper three-quarters of the output range for the 'das08jr-16-ao' board.
--- drivers/staging/comedi/drivers/das08.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/comedi/drivers/das08.c +1 -1
@@ -652,7 +652,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,int chan; lsb = data[0 ] &0xff ; - msb = (data[0 ] >>8 ) &0xf ; + msb = (data[0 ] >>8 ) &0xff ; chan =CR_CHAN (insn->chanspec);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 76/184 staging: vt6656: [BUG] out of bound array reference
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
in RFbSetPower.
From: Malcolm Priestley <[email protected]>
commit ab1dd9963137a1e122004d5378a581bf16ae9bc8 upstream.
Calling RFbSetPower with uCH zero value will cause out of bound array reference.
This causes 64 bit kernels to oops on boot.
Note: Driver does not function on 64 bit kernels and should be blacklisted on them.
--- drivers/staging/vt6656/rf.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/vt6656/rf.c +3 -0
@@ -769,6 +769,9 @@ BYTE byPwr = pDevice->byCCKPwr;return TRUE; } +if (uCH ==0 ) +return -EINVAL ; +switch (uRATE) {case RATE_1M :case RATE_2M :
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 77/184 libata: fix Null pointer dereference on disk error
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Xiaotian Feng <[email protected]>
commit 26cd4d65deba587f3cf2329b6869ce02bcbe68ec upstream.
Following oops were observed when disk error happened:
[ 4272.896937] sd 0:0:0:0: [sda] Unhandled error code [ 4272.896939] sd 0:0:0:0: [sda] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK [ 4272.896942] sd 0:0:0:0: [sda] CDB: Read(10): 28 00 00 5a de a7 00 00 08 00 [ 4272.896951] end_request: I/O error, dev sda, sector 5955239 [ 4291.574947] BUG: unable to handle kernel NULL pointer dereference at (null) [ 4291.658305] IP: [] ahci_activity_show+0x1/0x40 [ 4291.730090] PGD 76dbbc067 PUD 6c4fba067 PMD 0 [ 4291.783408] Oops: 0000 [#1] SMP [ 4291.822100] last sysfs file: /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/sw_activity [ 4291.934235] CPU 9 [ 4291.958301] Pid: 27942, comm: hwinfo ......
ata_scsi_find_dev could return NULL, so ata_scsi_activity_{show,store} should check if atadev is NULL.
--- drivers/ata/libata-scsi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/ata/libata-scsi.c +4 -2
@@ -338,7 +338,8 @@ ata_scsi_activity_show(struct device *dev, struct device_attribute *attr,struct ata_port *ap =ata_shost_to_port (sdev->host);struct ata_device *atadev =ata_scsi_find_dev (ap, sdev); -if (ap->ops->sw_activity_show && (ap->flags &ATA_FLAG_SW_ACTIVITY )) +if (atadev && ap->ops->sw_activity_show && + (ap->flags &ATA_FLAG_SW_ACTIVITY ))return ap->ops->sw_activity_show (atadev, buf);return -EINVAL ; }
@@ -353,7 +354,8 @@ ata_scsi_activity_store(struct device *dev, struct device_attribute *attr,enum sw_activity val;int rc; -if (ap->ops->sw_activity_store && (ap->flags &ATA_FLAG_SW_ACTIVITY )) { +if (atadev && ap->ops->sw_activity_store && + (ap->flags &ATA_FLAG_SW_ACTIVITY )) { val =simple_strtoul (buf,NULL ,0 );switch (val) {case OFF :case BLINK_ON :case BLINK_OFF :
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 78/184 scsi: Silence unnecessary warnings about ioctl to
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
partition
From: Jan Kara <[email protected]>
commit 6d9359280753d2955f86d6411047516a9431eb51 upstream.
Sometimes, warnings about ioctls to partition happen often enough that they form majority of the warnings in the kernel log and users complain. In some cases warnings are about ioctls such as SG_IO so it's not good to get rid of the warnings completely as they can ease debugging of userspace problems when ioctl is refused.
Since I have seen warnings from lots of commands, including some proprietary userspace applications, I don't think disallowing the ioctls for processes with CAP_SYS_RAWIO will happen in the near future if ever. So lets just stop warning for processes with CAP_SYS_RAWIO for which ioctl is allowed.
--- block/scsi_ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
block/scsi_ioctl.c +4 -1
@@ -720,11 +720,14 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)break ; } +if (capable (CAP_SYS_RAWIO )) +return 0 ; +/* In particular, rule out all resets and host-specific ioctls. */ printk_ratelimited (KERN_WARNING "%s: sending ioctl %x to a partition!\n" , current->comm, cmd); -return capable (CAP_SYS_RAWIO ) ?0 : -ENOTTY ; +return -ENOTTY ; }EXPORT_SYMBOL (scsi_verify_blk_ioctl);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 79/184 scsi: use __uX types for headers exported to user
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
space
From: Peter Korsgaard <[email protected]>
Commit 9e4f5e29 ("FC Pass Thru support") exported a number of header files in include/scsi to user space, but didn't change the uX types to the userspace-compatible __uX types. Without that you'll get compile errors when including them - E.G.:
include/scsi/scsi.h:145: error: expected specifier-qualifier-list before `u8'
--- include/scsi/scsi.h | 8 ++++---- include/scsi/scsi_netlink.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-)
include/scsi/scsi.h +4 -4
@@ -145,10 +145,10 @@ struct scsi_cmnd;/* defined in T10 SCSI Primary Commands-2 (SPC2) */ struct scsi_varlen_cdb_hdr { -u8 opcode;/* opcode always == VARIABLE_LENGTH_CMD */ -u8 control; -u8 misc[5 ]; -u8 additional_cdb_length;/* total cdb length - 8 */ +__u8 opcode;/* opcode always == VARIABLE_LENGTH_CMD */ +__u8 control; +__u8 misc[5 ]; +__u8 additional_cdb_length;/* total cdb length - 8 */ __be16 service_action;/* service specific data follows */ };
include/scsi/scsi_netlink.h +2 -2
@@ -105,8 +105,8 @@ struct scsi_nl_host_vendor_msg {* PCI : ID data is the 16 bit PCI Registered Vendor ID */ #define SCSI_NL_VID_TYPE_SHIFT 56 -#define SCSI_NL_VID_TYPE_MASK ((u64)0xFF << SCSI_NL_VID_TYPE_SHIFT) -#define SCSI_NL_VID_TYPE_PCI ((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT) +#define SCSI_NL_VID_TYPE_MASK ((__u64)0xFF << SCSI_NL_VID_TYPE_SHIFT) +#define SCSI_NL_VID_TYPE_PCI ((__u64)0x01 << SCSI_NL_VID_TYPE_SHIFT)#define SCSI_NL_VID_ID_MASK (~ SCSI_NL_VID_TYPE_MASK)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 80/184 fix crash in scsi_dispatch_cmd()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: James Bottomley <[email protected]>
USB surprise removal of sr is triggering an oops in scsi_dispatch_command(). What seems to be happening is that USB is hanging on to a queue reference until the last close of the upper device, so the crash is caused by surprise remove of a mounted CD followed by attempted unmount.
The problem is that USB doesn't issue its final commands as part of the SCSI teardown path, but on last close when the block queue is long gone. The long term fix is probably to make sr do the teardown in the same way as sd (so remove all the lower bits on ejection, but keep the upper disk alive until last close of user space). However, the current oops can be simply fixed by not allowing any commands to be sent to a dead queue.
--- block/blk-core.c | 3 +++ block/blk-exec.c | 7 +++++++ drivers/scsi/scsi_lib.c | 2 ++ 3 files changed, 12 insertions(+)
block/blk-core.c +3 -0
@@ -865,6 +865,9 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) {struct request *rq; +if (unlikely (test_bit (QUEUE_FLAG_DEAD , &q->queue_flags))) +return NULL ; +BUG_ON (rw !=READ && rw !=WRITE );spin_lock_irq (q->queue_lock);
block/blk-exec.c +7 -0
@@ -50,6 +50,13 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, {int where = at_head ?ELEVATOR_INSERT_FRONT :ELEVATOR_INSERT_BACK ; +if (unlikely (test_bit (QUEUE_FLAG_DEAD , &q->queue_flags))) { + rq->errors = -ENXIO ; +if (rq->end_io) + rq->end_io (rq, rq->errors); +return ; + } + rq->rq_disk = bd_disk; rq->end_io = done;WARN_ON (irqs_disabled ());
drivers/scsi/scsi_lib.c +2 -0
@@ -215,6 +215,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,int ret =DRIVER_ERROR <<24 ; req =blk_get_request (sdev->request_queue, write, __GFP_WAIT); +if (!req) +return ret;if (bufflen &&blk_rq_map_kern (sdev->request_queue, req, buffer, bufflen, __GFP_WAIT))
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 81/184 SCSI: bnx2i: Fixed NULL ptr deference for 1G bnx2
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
Linux iSCSI offload
From: Eddie Wai <[email protected]>
commit d6532207116307eb7ecbfa7b9e02c53230096a50 upstream.
This patch fixes the following kernel panic invoked by uninitialized fields in the chip initialization for the 1G bnx2 iSCSI offload.
One of the bits in the chip initialization is being used by the latest firmware to control overflow packets. When this control bit gets enabled erroneously, it would ultimately result in a bad packet placement which would cause the bnx2 driver to dereference a NULL ptr in the placement handler.
This can happen under certain stress I/O environment under the Linux iSCSI offload operation.
This change only affects Broadcom's 5709 chipset.
Unable to handle kernel NULL pointer dereference at 0000000000000008 RIP: [<ffffffff881f0e7d>] :bnx2:bnx2_poll_work+0xd0d/0x13c5 Pid: 0, comm: swapper Tainted: G ---- 2.6.18-333.el5debug #2 RIP: 0010:[<ffffffff881f0e7d>] [<ffffffff881f0e7d>] :bnx2:bnx2_poll_work+0xd0d/0x13c5 RSP: 0018:ffff8101b575bd50 EFLAGS: 00010216 RAX: 0000000000000005 RBX: ffff81007c5fb180 RCX: 0000000000000000 RDX: 0000000000000ffc RSI: 00000000817e8000 RDI: 0000000000000220 RBP: ffff81015bbd7ec0 R08: ffff8100817e9000 R09: 0000000000000000 R10: ffff81007c5fb180 R11: 00000000000000c8 R12: 000000007a25a010 R13: 0000000000000000 R14: 0000000000000005 R15: ffff810159f80558 FS: 0000000000000000(0000) GS:ffff8101afebc240(0000) knlGS:0000000000000000 CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b CR2: 0000000000000008 CR3: 0000000000201000 CR4: 00000000000006a0 Process swapper (pid: 0, threadinfo ffff8101b5754000, task ffff8101afebd820) Stack: 000000000000000b ffff810159f80000 0000000000000040 ffff810159f80520 ffff810159f80500 00cf00cf8008e84b ffffc200100939e0 ffff810009035b20 0000502900000000 000000be00000001 ffff8100817e7810 00d08101b575bea8 Call Trace: <IRQ> [<ffffffff8008e0d0>] show_schedstat+0x1c2/0x25b [<ffffffff881f1886>] :bnx2:bnx2_poll+0xf6/0x231 [<ffffffff8000c9b9>] net_rx_action+0xac/0x1b1 [<ffffffff800125a0>] __do_softirq+0x89/0x133 [<ffffffff8005e30c>] call_softirq+0x1c/0x28 [<ffffffff8006d5de>] do_softirq+0x2c/0x7d [<ffffffff8006d46e>] do_IRQ+0xee/0xf7 [<ffffffff8005d625>] ret_from_intr+0x0/0xa <EOI> [<ffffffff801a5780>] acpi_processor_idle_simple+0x1c5/0x341 [<ffffffff801a573d>] acpi_processor_idle_simple+0x182/0x341 [<ffffffff801a55bb>] acpi_processor_idle_simple+0x0/0x341 [<ffffffff80049560>] cpu_idle+0x95/0xb8 [<ffffffff80078b1c>] start_secondary+0x479/0x488
--- drivers/scsi/bnx2i/bnx2i_hwi.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/bnx2i/bnx2i_hwi.c +3 -0
@@ -1156,6 +1156,9 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)int rc =0 ;u64 mask64; +memset (&iscsi_init,0x00 ,sizeof (struct iscsi_kwqe_init1 )); +memset (&iscsi_init2,0x00 ,sizeof (struct iscsi_kwqe_init2 )); +bnx2i_adjust_qp_size (hba); iscsi_init.flags =
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 82/184 keys: fix race with concurrent
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
install_user_keyrings()
From: David Howells <[email protected]>
commit 0da9dfdd2cd9889201bc6f6f43580c99165cd087 upstream.
This fixes CVE-2013-1792.
There is a race in install_user_keyrings() that can cause a NULL pointer dereference when called concurrently for the same user if the uid and uid-session keyrings are not yet created. It might be possible for an unprivileged user to trigger this by calling keyctl() from userspace in parallel immediately after logging in.
Assume that we have two threads both executing lookup_user_key(), both looking for KEY_SPEC_USER_SESSION_KEYRING.
THREAD A THREAD B =============================== =============================== ==>call install_user_keyrings(); if (!cred->user->session_keyring) ==>call install_user_keyrings() ... user->uid_keyring = uid_keyring; if (user->uid_keyring) return 0; <== key = cred->user->session_keyring [== NULL] user->session_keyring = session_keyring; atomic_inc(&key->usage); [oops]
At the point thread A dereferences cred->user->session_keyring, thread B hasn't updated user->session_keyring yet, but thread A assumes it is populated because install_user_keyrings() returned ok.
The race window is really small but can be exploited if, for example, thread B is interrupted or preempted after initializing uid_keyring, but before doing setting session_keyring.
This couldn't be reproduced on a stock kernel. However, after placing systemtap probe on 'user->session_keyring = session_keyring;' that introduced some delay, the kernel could be crashed reliably.
Fix this by checking both pointers before deciding whether to return. Alternatively, the test could be done away with entirely as it is checked inside the mutex - but since the mutex is global, that may not be the best way.
--- security/keys/process_keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/keys/process_keys.c +1 -1
@@ -56,7 +56,7 @@ int install_user_keyrings(void)kenter ("%p{%u}" , user, user->uid); -if (user->uid_keyring) { +if (user->uid_keyring && user->session_keyring) {kleave (" = 0 [exist]" );return 0 ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 83/184 crypto: cryptd - disable softirqs in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
cryptd_queue_worker to prevent data corruption
From: Jussi Kivilinna <[email protected]>
commit 9efade1b3e981f5064f9db9ca971b4dc7557ae42 upstream.
cryptd_queue_worker attempts to prevent simultaneous accesses to crypto workqueue by cryptd_enqueue_request using preempt_disable/preempt_enable. However cryptd_enqueue_request might be called from softirq context, so add local_bh_disable/local_bh_enable to prevent data corruption and panics.
Bug report at http://marc.info/?l=linux-crypto-vger&m=134858649616319&w=2
v2:
- Disable software interrupts instead of hardware interrupts
--- crypto/cryptd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
crypto/cryptd.c +8 -3
@@ -116,13 +116,18 @@ static void cryptd_queue_worker(struct work_struct *work)struct crypto_async_request *req, *backlog; cpu_queue = container_of(work, struct cryptd_cpu_queue, work); -/* Only handle one request at a time to avoid hogging crypto -* workqueue. preempt_disable/enable is used to prevent -* being preempted by cryptd_enqueue_request() */ +/* +* Only handle one request at a time to avoid hogging crypto workqueue. +* preempt_disable/enable is used to prevent being preempted by +* cryptd_enqueue_request(). local_bh_disable/enable is used to prevent +* cryptd_enqueue_request() being accessed from software interrupts. +*/ +local_bh_disable ();preempt_disable (); backlog =crypto_get_backlog (&cpu_queue->queue); req =crypto_dequeue_request (&cpu_queue->queue);preempt_enable (); +local_bh_enable ();if (!req)return ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 84/184 xfrm_user: fix info leak in copy_to_user_state()
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]>
[ Upstream commit f778a636713a435d3a922c60b1622a91136560c1 ]
The memory reserved to dump the xfrm state includes the padding bytes of struct xfrm_usersa_info added by the compiler for alignment (7 for amd64, 3 for i386). Add an explicit memset(0) before filling the buffer to avoid the info leak.
--- net/xfrm/xfrm_user.c | 1 + 1 file changed, 1 insertion(+)
net/xfrm/xfrm_user.c +1 -0
@@ -506,6 +506,7 @@ out:static void copy_to_user_state (struct xfrm_state *x,struct xfrm_usersa_info *p) { +memset (p,0 ,sizeof (*p));memcpy (&p->id, &x->id,sizeof (p->id));memcpy (&p->sel, &x->sel,sizeof (p->sel));memcpy (&p->lft, &x->lft,sizeof (p->lft));
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 85/184 xfrm_user: fix info leak in copy_to_user_policy()
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]>
[ Upstream commit 7b789836f434c87168eab067cfbed1ec4783dffd ]
The memory reserved to dump the xfrm policy includes multiple padding bytes added by the compiler for alignment (padding bytes in struct xfrm_selector and struct xfrm_userpolicy_info). Add an explicit memset(0) before filling the buffer to avoid the heap info leak.
--- net/xfrm/xfrm_user.c | 1 + 1 file changed, 1 insertion(+)
net/xfrm/xfrm_user.c +1 -0
@@ -1076,6 +1076,7 @@ static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicystatic void copy_to_user_policy (struct xfrm_policy *xp,struct xfrm_userpolicy_info *p,int dir) { +memset (p,0 ,sizeof (*p));memcpy (&p->sel, &xp->selector,sizeof (p->sel));memcpy (&p->lft, &xp->lft,sizeof (p->lft));memcpy (&p->curlft, &xp->curlft,sizeof (p->curlft));
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 86/184 xfrm_user: fix info leak in copy_to_user_tmpl()
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]>
[ Upstream commit 1f86840f897717f86d523a13e99a447e6a5d2fa5 ]
The memory used for the template copy is a local stack variable. As struct xfrm_user_tmpl contains multiple holes added by the compiler for alignment, not initializing the memory will lead to leaking stack bytes to userland. Add an explicit memset(0) to avoid the info leak.
Initial version of the patch by Brad Spengler.
--- net/xfrm/xfrm_user.c | 1 + 1 file changed, 1 insertion(+)
net/xfrm/xfrm_user.c +1 -0
@@ -1178,6 +1178,7 @@ static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)struct xfrm_user_tmpl *up = &vec[i];struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; +memset (up,0 ,sizeof (*up));memcpy (&up->id, &kp->id,sizeof (up->id)); up->family = kp->encap_family;memcpy (&up->saddr, &kp->saddr,sizeof (up->saddr));
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 87/184 xfrm_user: return error pointer instead of NULL
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 864745d291b5ba80ea0bd0edcbe67273de368836 upstream.
When dump_one_state() returns an error, e.g. because of a too small buffer to dump the whole xfrm state, xfrm_state_netlink() returns NULL instead of an error pointer. But its callers expect an error pointer and therefore continue to operate on a NULL skbuff.
This could lead to a privilege escalation (execution of user code in kernel context) if the attacker has CAP_NET_ADMIN and is able to map address 0.
--- net/xfrm/xfrm_user.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/xfrm/xfrm_user.c +4 -2
@@ -647,6 +647,7 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, {struct xfrm_dump_info info;struct sk_buff *skb; +int err; skb =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_ATOMIC );if (!skb)
@@ -657,9 +658,10 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, info.nlmsg_seq = seq; info.nlmsg_flags =0 ; -if (dump_one_state (x,0 , &info)) { + err =dump_one_state (x,0 , &info); +if (err) {kfree_skb (skb); -return NULL ; +return ERR_PTR (err); }return skb;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 88/184 xfrm_user: return error pointer instead of NULL #2
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 c25463722509fef0ed630b271576a8c9a70236f3 upstream.
When dump_one_policy() returns an error, e.g. because of a too small buffer to dump the whole xfrm policy, xfrm_policy_netlink() returns NULL instead of an error pointer. But its caller expects an error pointer and therefore continues to operate on a NULL skbuff.
--- net/xfrm/xfrm_user.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/xfrm/xfrm_user.c +4 -2
@@ -1306,6 +1306,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, {struct xfrm_dump_info info;struct sk_buff *skb; +int err; skb =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL );if (!skb)
@@ -1316,9 +1317,10 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, info.nlmsg_seq = seq; info.nlmsg_flags =0 ; -if (dump_one_policy (xp, dir,0 , &info) <0 ) { + err =dump_one_policy (xp, dir,0 , &info); +if (err) {kfree_skb (skb); -return NULL ; +return ERR_PTR (err); }return skb;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 89/184 r8169: correct settings of rtl8102e.
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Hayes Wang <[email protected]>
Adjust and remove certain settings of RTL8102E which are for previous chips.
--- drivers/net/r8169.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-)
drivers/net/r8169.c +6 -14
@@ -3076,7 +3076,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_mwi_3; } - tp->cp_cmd = PCIMulRW | RxChkSum; + tp->cp_cmd = RxChkSum;if ((sizeof (dma_addr_t) >4 ) && !pci_set_dma_mask (pdev,DMA_BIT_MASK (64 )) && use_dac) {
@@ -3824,8 +3824,7 @@ static void rtl_hw_start_8168(struct net_device *dev) Cxpl_dbg_sel | \ ASF | \ PktCntrDisable | \ - PCIDAC | \ - PCIMulRW) + Mac_dbgo_sel)static void rtl_hw_start_8102e_1 (void __iomem *ioaddr,struct pci_dev *pdev) {
@@ -3855,8 +3854,6 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)if ((cfg1 &LEDS0 ) && (cfg1 &LEDS1 ))RTL_W8 (Config1, cfg1 & ~LEDS0 ); -RTL_W16 (CPlusCmd,RTL_R16 (CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK ); -rtl_ephy_init (ioaddr, e_info_8102e_1,ARRAY_SIZE (e_info_8102e_1)); }
@@ -3868,8 +3865,6 @@ static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)RTL_W8 (Config1,MEMMAP |IOMAP |VPD | PMEnable);RTL_W8 (Config3,RTL_R8 (Config3) & ~Beacon_en); - -RTL_W16 (CPlusCmd,RTL_R16 (CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK ); }static void rtl_hw_start_8102e_3 (void __iomem *ioaddr,struct pci_dev *pdev)
@@ -3895,6 +3890,8 @@ static void rtl_hw_start_8101(struct net_device *dev) } } +RTL_W8 (Cfg9346, Cfg9346_Unlock); +switch (tp->mac_version) {case RTL_GIGA_MAC_VER_07 :rtl_hw_start_8102e_1 (ioaddr, pdev);
@@ -3909,14 +3906,13 @@ static void rtl_hw_start_8101(struct net_device *dev)break ; } -RTL_W8 (Cfg9346, Cfg9346_Unlock); +RTL_W8 (Cfg9346, Cfg9346_Lock);RTL_W8 (EarlyTxThres, EarlyTxThld);rtl_set_rx_max_size (ioaddr, tp->rx_buf_sz); - tp->cp_cmd |=rtl_rw_cpluscmd (ioaddr) | PCIMulRW; - + tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK ;RTL_W16 (CPlusCmd, tp->cp_cmd);RTL_W16 (IntrMitigate,0x0000 );
@@ -3926,14 +3922,10 @@ static void rtl_hw_start_8101(struct net_device *dev)RTL_W8 (ChipCmd, CmdTxEnb | CmdRxEnb);rtl_set_rx_tx_config_registers (tp); -RTL_W8 (Cfg9346, Cfg9346_Lock); -RTL_R8 (IntrMask);rtl_set_rx_mode (dev); -RTL_W8 (ChipCmd, CmdTxEnb | CmdRxEnb); -RTL_W16 (MultiIntr,RTL_R16 (MultiIntr) &0xf000 );RTL_W16 (IntrMask, tp->intr_event);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 90/184 r8169: remove the obsolete and incorrect AMD
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
workaround
From: =?latin1?q?Timo=20Ter=E4s?= <[email protected]>
[ Upstream commit 5d0feaff230c0abfe4a112e6f09f096ed99e0b2d ]
This was introduced in commit 6dccd16 "r8169: merge with version 6.001.00 of Realtek's r8169 driver". I did not find the version 6.001.00 online, but in 6.002.00 or any later r8169 from Realtek this hunk is no longer present.
Also commit 05af214 "r8169: fix Ethernet Hangup for RTL8110SC rev d" claims to have fixed this issue otherwise.
The magic compare mask of 0xfffe000 is dubious as it masks parts of the Reserved part, and parts of the VLAN tag. But this does not make much sense as the VLAN tag parts are perfectly valid there. In matter of fact this seems to be triggered with any VLAN tagged packet as RxVlanTag bit is matched. I would suspect 0xfffe0000 was intended to test reserved part only.
Finally, this hunk is evil as it can cause more packets to be handled than what was NAPI quota causing net/core/dev.c:net_rx_action(): WARN_ON_ONCE(work > weight) to trigger, and mess up the NAPI state causing device to hang.
As result, any system using VLANs and having high receive traffic (so that NAPI poll budget limits rtl_rx) would result in device hang.
--- drivers/net/r8169.c | 7 ------- 1 file changed, 7 deletions(-)
drivers/net/r8169.c +0 -7
@@ -4571,13 +4571,6 @@ static int rtl8169_rx_interrupt(struct net_device *dev, dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; } - -/* Work around for AMD plateform. */ -if ((desc->opts2 &cpu_to_le32 (0xfffe000 )) && - (tp->mac_version ==RTL_GIGA_MAC_VER_05 )) { - desc->opts2 =0 ; - cur_rx++; - } } count = cur_rx - tp->cur_rx;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 91/184 r8169: Add support for D-Link 530T rev C1 (Kernel
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
Bug 38862)
From: Lennart Sorensen <[email protected]>
[ Upstream commit 93a3aa25933461d76141179fc94aa32d5f9d954a ]
The D-Link DGE-530T rev C1 is a re-badged Realtek 8169 named DLG10028C, unlike the previous revisions which were skge based. It is probably the same as the discontinued DGE-528T (0x4300) other than the PCI ID.
The PCI ID is 0x1186:0x4302.
Adding it to r8169.c where 0x1186:0x4300 is already found makes the card be detected and work.
This fixes https://bugzilla.kernel.org/show_bug.cgi?id=38862
--- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/r8169.c +1 -0
@@ -176,6 +176,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, { PCI_VENDOR_ID_LINKSYS, 0x1032,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 92/184 r8169: incorrect identifier for a 8168dp
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Francois Romieu <[email protected]>
Merge error.
See CFG_METHOD_8 (0x3c800000 + 0x00300000) since version 8.002.00 of Realtek's driver.
--- drivers/net/r8169.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/r8169.c +1 -1
@@ -1307,7 +1307,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },/* 8168C family. */ - { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 }, { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 }, { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 93/184 b43legacy: Fix crash on unload when firmware not
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
available
From: Larry Finger <[email protected]>
commit 2d838bb608e2d1f6cb4280e76748cb812dc822e7 upstream.
When b43legacy is loaded without the firmware being available, a following unload generates a kernel NULL pointer dereference BUG as follows:
[ 214.330789] BUG: unable to handle kernel NULL pointer dereference at 0000004c [ 214.330997] IP: [<c104c395>] drain_workqueue+0x15/0x170 [ 214.331179] *pde = 00000000 [ 214.331311] Oops: 0000 [#1] SMP [ 214.331471] Modules linked in: b43legacy(-) ssb pcmcia mac80211 cfg80211 af_packet mperf arc4 ppdev sr_mod cdrom sg shpchp yenta_socket pcmcia_rsrc pci_hotplug pcmcia_core battery parport_pc parport floppy container ac button edd autofs4 ohci_hcd ehci_hcd usbcore usb_common thermal processor scsi_dh_rdac scsi_dh_hp_sw scsi_dh_emc scsi_dh_alua scsi_dh fan thermal_sys hwmon ata_generic pata_ali libata [last unloaded: cfg80211] [ 214.333421] Pid: 3639, comm: modprobe Not tainted 3.6.0-rc6-wl+ #163 Source Technology VIC 9921/ALI Based Notebook [ 214.333580] EIP: 0060:[<c104c395>] EFLAGS: 00010246 CPU: 0 [ 214.333687] EIP is at drain_workqueue+0x15/0x170 [ 214.333788] EAX: c162ac40 EBX: cdfb8360 ECX: 0000002a EDX: 00002a2a [ 214.333890] ESI: 00000000 EDI: 00000000 EBP: cd767e7c ESP: cd767e5c [ 214.333957] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 214.333957] CR0: 8005003b CR2: 0000004c CR3: 0c96a000 CR4: 00000090 [ 214.333957] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ 214.333957] DR6: ffff0ff0 DR7: 00000400 [ 214.333957] Process modprobe (pid: 3639, ti=cd766000 task=cf802e90 task.ti=cd766000) [ 214.333957] Stack: [ 214.333957] 00000292 cd767e74 c12c5e09 00000296 00000296 cdfb8360 cdfb9220 00000000 [ 214.333957] cd767e90 c104c4fd cdfb8360 cdfb9220 cd682800 cd767ea4 d0c10184 cd682800 [ 214.333957] cd767ea4 cba31064 cd767eb8 d0867908 cba31064 d087e09c cd96f034 cd767ec4 [ 214.333957] Call Trace: [ 214.333957] [<c12c5e09>] ? skb_dequeue+0x49/0x60 [ 214.333957] [<c104c4fd>] destroy_workqueue+0xd/0x150 [ 214.333957] [<d0c10184>] ieee80211_unregister_hw+0xc4/0x100 [mac80211] [ 214.333957] [<d0867908>] b43legacy_remove+0x78/0x80 [b43legacy] [ 214.333957] [<d083654d>] ssb_device_remove+0x1d/0x30 [ssb] [ 214.333957] [<c126f15a>] __device_release_driver+0x5a/0xb0 [ 214.333957] [<c126fb07>] driver_detach+0x87/0x90 [ 214.333957] [<c126ef4c>] bus_remove_driver+0x6c/0xe0 [ 214.333957] [<c1270120>] driver_unregister+0x40/0x70 [ 214.333957] [<d083686b>] ssb_driver_unregister+0xb/0x10 [ssb] [ 214.333957] [<d087c488>] b43legacy_exit+0xd/0xf [b43legacy] [ 214.333957] [<c1089dde>] sys_delete_module+0x14e/0x2b0 [ 214.333957] [<c110a4a7>] ? vfs_write+0xf7/0x150 [ 214.333957] [<c1240050>] ? tty_write_lock+0x50/0x50 [ 214.333957] [<c110a6f8>] ? sys_write+0x38/0x70 [ 214.333957] [<c1397c55>] syscall_call+0x7/0xb [ 214.333957] Code: bc 27 00 00 00 00 a1 74 61 56 c1 55 89 e5 e8 a3 fc ff ff 5d c3 90 55 89 e5 57 56 89 c6 53 b8 40 ac 62 c1 83 ec 14 e8 bb b7 34 00 <8b> 46 4c 8d 50 01 85 c0 89 56 4c 75 03 83 0e 40 80 05 40 ac 62 [ 214.333957] EIP: [<c104c395>] drain_workqueue+0x15/0x170 SS:ESP 0068:cd767e5c [ 214.333957] CR2: 000000000000004c [ 214.341110] ---[ end trace c7e90ec026d875a6 ]---Index: wireless-testing/drivers/net/wireless/b43legacy/main.c
The problem is fixed by making certain that the ucode pointer is not NULL before deregistering the driver in mac80211.
--- drivers/net/wireless/b43legacy/main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wireless/b43legacy/main.c +2 -0
@@ -3870,6 +3870,8 @@ static void b43legacy_remove(struct ssb_device *dev)cancel_work_sync (&wldev->restart_work);B43legacy_WARN_ON (!wl); +if (!wldev->fw.ucode) +return ;/* NULL if fw never loaded */ if (wl->current_dev == wldev)ieee80211_unregister_hw (wl->hw);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 94/184 tg3: Avoid null pointer dereference in tg3_interrupt
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
in netconsole mode
From: Nithin Nayak Sujir <[email protected]>
[ Upstream commit 9c13cb8bb477a83b9a3c9e5a5478a4e21294a760 ]
When netconsole is enabled, logging messages generated during tg3_open can result in a null pointer dereference for the uninitialized tg3 status block. Use the irq_sync flag to disable polling in the early stages. irq_sync is cleared when the driver is enabling interrupts after all initialization is completed.
--- drivers/net/tg3.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/tg3.c +4 -0
@@ -4994,6 +4994,9 @@ static void tg3_poll_controller(struct net_device *dev)int i;struct tg3 *tp =netdev_priv (dev); +if (tg3_irq_sync (tp)) +return ; +for (i =0 ; i < tp->irq_cnt; i++)tg3_interrupt (tp->napi[i].irq_vec, &tp->napi[i]); }
@@ -13888,6 +13891,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->pm_cap = pm_cap; tp->rx_mode =TG3_DEF_RX_MODE ; tp->tx_mode =TG3_DEF_TX_MODE ; + tp->irq_sync =1 ;if (tg3_debug >0 ) tp->msg_enable = tg3_debug;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 95/184 IPoIB: Fix use-after-free of multicast object
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Patrick McHardy <[email protected]>
commit bea1e22df494a729978e7f2c54f7bda328f74bc3 upstream.
Fix a crash in ipoib_mcast_join_task(). (with help from Or Gerlitz)
Commit c8c2afe360b7 ("IPoIB: Use rtnl lock/unlock when changing device flags") added a call to rtnl_lock() in ipoib_mcast_join_task(), which is run from the ipoib_workqueue, and hence the workqueue can't be flushed from the context of ipoib_stop().
In the current code, ipoib_stop() (which doesn't flush the workqueue) calls ipoib_mcast_dev_flush(), which goes and deletes all the multicast entries. This takes place without any synchronization with a possible running instance of ipoib_mcast_join_task() for the same ipoib device, leading to a crash due to NULL pointer dereference.
Fix this by making sure that the workqueue is flushed before ipoib_mcast_dev_flush() is called. To make that possible, we move the RTNL-lock wrapped code to ipoib_mcast_join_finish().
--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-)
drivers/infiniband/ulp/ipoib/ipoib_main.c +1 -1
@@ -157,7 +157,7 @@ static int ipoib_stop(struct net_device *dev)netif_stop_queue (dev); -ipoib_ib_dev_down (dev,0 ); +ipoib_ib_dev_down (dev,1 );ipoib_ib_dev_stop (dev,0 );if (!test_bit (IPOIB_FLAG_SUBINTERFACE , &priv->flags)) {
drivers/infiniband/ulp/ipoib/ipoib_multicast.c +10 -9
@@ -188,7 +188,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, mcast->mcmember = *mcmember; -/* Set the cached Q_Key before we attach if it's the broadcast group */ +/* Set the multicast MTU and cached Q_Key before we attach if it's +* the broadcast group. +*/ if (!memcmp (mcast->mcmember.mgid.raw, priv->dev->broadcast +4 ,sizeof (union ib_gid ))) {spin_lock_irq (&priv->lock);
@@ -196,10 +198,17 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,spin_unlock_irq (&priv->lock);return -EAGAIN ; } + priv->mcast_mtu =IPOIB_UD_MTU (ib_mtu_enum_to_int (priv->broadcast->mcmember.mtu)); priv->qkey =be32_to_cpu (priv->broadcast->mcmember.qkey);spin_unlock_irq (&priv->lock); priv->tx_wr.wr.ud.remote_qkey = priv->qkey; set_qkey =1 ; + +if (!ipoib_cm_admin_enabled (dev)) { +rtnl_lock (); +dev_set_mtu (dev,min (priv->mcast_mtu, priv->admin_mtu)); +rtnl_unlock (); + } }if (!test_bit (IPOIB_MCAST_FLAG_SENDONLY , &mcast->flags)) {
@@ -588,14 +597,6 @@ void ipoib_mcast_join_task(struct work_struct *work)return ; } - priv->mcast_mtu =IPOIB_UD_MTU (ib_mtu_enum_to_int (priv->broadcast->mcmember.mtu)); - -if (!ipoib_cm_admin_enabled (dev)) { -rtnl_lock (); -dev_set_mtu (dev,min (priv->mcast_mtu, priv->admin_mtu)); -rtnl_unlock (); - } -ipoib_dbg_mcast (priv,"successfully joined all multicast groups\n" );clear_bit (IPOIB_MCAST_RUN , &priv->flags);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 96/184 telephony: ijx: buffer overflow in ixj_write_cid()
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]>
[Not needed in 3.8 or newer as this driver is removed there. - gregkh]
We get this from user space and nothing has been done to ensure that these strings are NUL terminated.
--- drivers/telephony/ixj.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
drivers/telephony/ixj.c +12 -12
@@ -3190,12 +3190,12 @@ static void ixj_write_cid(IXJ *j)ixj_fsk_alloc (j); -strcpy (sdmf1, j->cid_send.month); -strcat (sdmf1, j->cid_send.day); -strcat (sdmf1, j->cid_send.hour); -strcat (sdmf1, j->cid_send.min); -strcpy (sdmf2, j->cid_send.number); -strcpy (sdmf3, j->cid_send.name); +strlcpy (sdmf1, j->cid_send.month,sizeof (sdmf1)); +strlcat (sdmf1, j->cid_send.day,sizeof (sdmf1)); +strlcat (sdmf1, j->cid_send.hour,sizeof (sdmf1)); +strlcat (sdmf1, j->cid_send.min,sizeof (sdmf1)); +strlcpy (sdmf2, j->cid_send.number,sizeof (sdmf2)); +strlcpy (sdmf3, j->cid_send.name,sizeof (sdmf3)); len1 =strlen (sdmf1); len2 =strlen (sdmf2);
@@ -3340,12 +3340,12 @@ static void ixj_write_cidcw(IXJ *j)ixj_pre_cid (j); } j->flags.cidcw_ack =0 ; -strcpy (sdmf1, j->cid_send.month); -strcat (sdmf1, j->cid_send.day); -strcat (sdmf1, j->cid_send.hour); -strcat (sdmf1, j->cid_send.min); -strcpy (sdmf2, j->cid_send.number); -strcpy (sdmf3, j->cid_send.name); +strlcpy (sdmf1, j->cid_send.month,sizeof (sdmf1)); +strlcat (sdmf1, j->cid_send.day,sizeof (sdmf1)); +strlcat (sdmf1, j->cid_send.hour,sizeof (sdmf1)); +strlcat (sdmf1, j->cid_send.min,sizeof (sdmf1)); +strlcpy (sdmf2, j->cid_send.number,sizeof (sdmf2)); +strlcpy (sdmf3, j->cid_send.name,sizeof (sdmf3)); len1 =strlen (sdmf1); len2 =strlen (sdmf2);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 97/184 Bluetooth: Fix incorrect strncpy() in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
hidp_setup_hid()
From: Anderson Lizardo <[email protected]>
The length parameter should be sizeof(req->name) - 1 because there is no guarantee that string provided by userspace will contain the trailing '\0'.
Can be easily reproduced by manually setting req->name to 128 non-zero bytes prior to ioctl(HIDPCONNADD) and checking the device name setup on input subsystem:
$ cat /sys/devices/pnp0/00\:04/tty/ttyS0/hci0/hci0\:1/input8/name AAAAAA[...]AAAAAAAAf0:af:f0:af:f0:af
("f0:af:f0:af:f0:af" is the device bluetooth address, taken from "phys" field in struct hid_device due to overflow.)
--- net/bluetooth/hidp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/hidp/core.c +1 -1
@@ -778,7 +778,7 @@ static int hidp_setup_hid(struct hidp_session *session, hid->version = req->version; hid->country = req->country; -strncpy (hid->name, req->name,128 ); +strncpy (hid->name, req->name,sizeof (req->name) -1 );strncpy (hid->phys,batostr (&src),64 );strncpy (hid->uniq,batostr (&dst),64 );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 097/184] Bluetooth: Fix incorrect strncpy() in
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
hidp_setup_hid()From: Anderson Lizardo <[email protected]>
This is missing the upstream reference. It was commit 0a9ab9bdb3e891762553f667066190c1d22ad62b.
Ben.
Quoted 38 lines
The length parameter should be
sizeof(req->name)- 1 because there is no guarantee that string provided by userspace will contain the trailing '\0'.Can be easily reproduced by manually setting
req->nameto 128 non-zero bytes prior to ioctl(HIDPCONNADD) and checking the device name setup on input subsystem:$ cat /sys/devices/pnp0/00\:04/tty/ttyS0/hci0/hci0\:1/input8/name AAAAAA[...]AAAAAAAAf0:af:f0:af:f0:af("f0:af:f0:af:f0:af" is the device bluetooth address, taken from "phys" field in struct
hid_devicedue to overflow.)Signed-off-by Anderson Lizardo <[email protected]>Acked-by Marcel Holtmann <[email protected]>Signed-off-by Gustavo Padovan <[email protected]>[backported to 2.6.32 jmm]Signed-off-by Willy Tarreau <[email protected]>--- net/bluetooth/hidp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)net/bluetooth/hidp/core.c +1
-1@@ -778,7 +778,7 @@ static int hidp_setup_hid(struct hidp_session *session, hid->version = req->version; hid->country = req->country; -strncpy (hid->name, req->name,128 ); +strncpy (hid->name, req->name,sizeof (req->name) -1 );strncpy (hid->phys,batostr (&src),64 );strncpy (hid->uniq,batostr (&dst),64 );
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 097/184] Bluetooth: Fix incorrect strncpy() in
Quoted 10 lines · Ben Hutchings
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
hidp_setup_hid()From: Anderson Lizardo <[email protected]>
This is missing the upstream reference. It was commit
0a9ab9bdb3e891762553f667066190c1d22ad62b.
Fixed, thank you !
Willy
PATCH 98/184 Bluetooth: HCI - Fix info leak in getsockopt(HCI_FILTER)
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
[ Upstream commit e15ca9a0ef9a86f0477530b0f44a725d67f889ee ]
The HCI code fails to initialize the two padding bytes of struct hci_ufilter before copying it to userland -- that for leaking two bytes kernel stack. Add an explicit memset(0) before filling the structure to avoid the info leak.
--- net/bluetooth/hci_sock.c | 1 + 1 file changed, 1 insertion(+)
net/bluetooth/hci_sock.c +1 -0
@@ -576,6 +576,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char {struct hci_filter *f = &hci_pi (sk)->filter; +memset (&uf,0 ,sizeof (uf)); uf.type_mask = f->type_mask; uf.opcode = f->opcode; uf.event_mask[0 ] = *((u32 *) f->event_mask +0 );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 99/184 Bluetooth: RFCOMM - Fix info leak via getsockname()
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]>
[ Upstream commit 9344a972961d1a6d2c04d9008b13617bcb6ec2ef ]
The RFCOMM code fails to initialize the trailing padding byte of struct sockaddr_rc added for alignment. It that for leaks one byte kernel stack via the getsockname() syscall. Add an explicit memset(0) before filling the structure to avoid the info leak.
--- net/bluetooth/rfcomm/sock.c | 1 + 1 file changed, 1 insertion(+)
net/bluetooth/rfcomm/sock.c +1 -0
@@ -543,6 +543,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *BT_DBG ("sock %p, sk %p" , sock, sk); +memset (sa,0 ,sizeof (*sa)); sa->rc_family =AF_BLUETOOTH ; sa->rc_channel =rfcomm_pi (sk)->channel;if (peer)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 100/184 Bluetooth: RFCOMM - Fix missing msg_namelen update
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
in rfcomm_sock_recvmsg()
From: Mathias Krause <[email protected]>
[ Upstream commit e11e0455c0d7d3d62276a0c55d9dfbc16779d691 ]
If RFCOMM_DEFER_SETUP is set in the flags, rfcomm_sock_recvmsg() returns early with 0 without updating the possibly set msg_namelen member. This, in turn, leads to a 128 byte kernel stack leak in net/socket.c.
Fix this by updating msg_namelen in this case. For all other cases it will be handled in bt_sock_stream_recvmsg().
--- net/bluetooth/rfcomm/sock.c | 1 + 1 file changed, 1 insertion(+)
net/bluetooth/rfcomm/sock.c +1 -0
@@ -652,6 +652,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,if (test_and_clear_bit (RFCOMM_DEFER_SETUP , &d->flags)) {rfcomm_dlc_accept (d); + msg->msg_namelen =0 ;return 0 ; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 101/184 Bluetooth: L2CAP - Fix info leak via getsockname()
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 792039c73cf176c8e39a6e8beef2c94ff46522ed upstream.
The L2CAP code fails to initialize the l2_bdaddr_type member of struct sockaddr_l2 and the padding byte added for alignment. It that for leaks two bytes kernel stack via the getsockname() syscall. Add an explicit memset(0) before filling the structure to avoid the info leak.
--- net/bluetooth/l2cap.c | 1 + 1 file changed, 1 insertion(+)
net/bluetooth/l2cap.c +1 -0
@@ -1184,6 +1184,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *lBT_DBG ("sock %p, sk %p" , sock, sk); +memset (la,0 ,sizeof (struct sockaddr_l2 )); addr->sa_family =AF_BLUETOOTH ; *len =sizeof (struct sockaddr_l2 );
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 102/184 Bluetooth: fix possible info leak in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
bt_sock_recvmsg()
From: Mathias Krause <[email protected]>
In case the socket is already shutting down, bt_sock_recvmsg() returns with 0 without updating msg_namelen leading to net/socket.c leaking the local, uninitialized sockaddr_storage variable to userland -- 128 bytes of kernel stack memory.
Fix this by moving the msg_namelen assignment in front of the shutdown test.
--- net/bluetooth/af_bluetooth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/af_bluetooth.c +2 -2
@@ -240,14 +240,14 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,if (flags & (MSG_OOB ))return -EOPNOTSUPP ; + msg->msg_namelen =0 ; +if (!(skb =skb_recv_datagram (sk, flags, noblock, &err))) {if (sk->sk_shutdown &RCV_SHUTDOWN )return 0 ;return err; } - msg->msg_namelen =0 ; - copied = skb->len;if (len < copied) { msg->msg_flags |=MSG_TRUNC ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 102/184] Bluetooth: fix possible info leak in
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
bt_sock_recvmsg()From: Mathias Krause <[email protected]>
commit 4683f42fde3977bdb4e8a09622788cc8b5313778 upstream.
Quoted 40 lines
In case the socket is already shutting down,
bt_sock_recvmsg()returns with 0 without updatingmsg_namelenleading tonet/socket.cleaking the local, uninitializedsockaddr_storagevariable to userland -- 128 bytes of kernel stack memory.Fix this by moving the
msg_namelenassignment in front of the shutdown test.Cc Marcel Holtmann <[email protected]>Cc Gustavo Padovan <[email protected]>Cc Johan Hedberg <[email protected]>Signed-off-by Mathias Krause <[email protected]>Signed-off-by David S. Miller <[email protected]>[dannf: adjusted to apply to Debian's 2.6.32]Signed-off-by Willy Tarreau <[email protected]>--- net/bluetooth/af_bluetooth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)net/bluetooth/af_bluetooth.c +2
-2@@ -240,14 +240,14 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,if (flags & (MSG_OOB ))return -EOPNOTSUPP ; + msg->msg_namelen =0 ; +if (!(skb =skb_recv_datagram (sk, flags, noblock, &err))) {if (sk->sk_shutdown &RCV_SHUTDOWN )return 0 ;return err; } - msg->msg_namelen =0 ; - copied = skb->len;if (len < copied) { msg->msg_flags |=MSG_TRUNC ;
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 102/184] Bluetooth: fix possible info leak in
Quoted 9 lines · Ben Hutchings
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
bt_sock_recvmsg()From: Mathias Krause <[email protected]>
commit
4683f42fde3977bdb4e8a09622788cc8b5313778upstream.
Added, thank you.
Willy
PATCH 103/184 xhci: Make handover code more robust
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 Garrett <[email protected]>
commit e955a1cd086de4d165ae0f4c7be7289d84b63bdc upstream.
My test platform (Intel DX79SI) boots reliably under BIOS, but frequently crashes when booting via UEFI. I finally tracked this down to the xhci handoff code. It seems that reads from the device occasionally just return 0xff, resulting in xhci_find_next_cap_offset generating a value that's larger than the resource region. We then oops when attempting to read the value. Sanity checking that value lets us avoid the crash.
I've no idea what's causing the underlying problem, and xhci still doesn't actually *work* even with this, but the machine at least boots which will probably make further debugging easier.
This should be backported to kernels as old as 2.6.31, that contain the commit 66d4eadd8d067269ea8fead1a50fe87c2979a80d "USB: xhci: BIOS handoff and HW initialization."
--- drivers/usb/host/pci-quirks.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/usb/host/pci-quirks.c +10 -2
@@ -418,12 +418,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)void __iomem *op_reg_base;u32 val;int timeout; +int len =pci_resource_len (pdev,0 );if (!mmio_resource_enabled (pdev,0 ))return ; - base =ioremap_nocache (pci_resource_start (pdev,0 ), -pci_resource_len (pdev,0 )); + base =ioremap_nocache (pci_resource_start (pdev,0 ), len);if (base ==NULL )return ;
@@ -433,9 +433,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)*/ ext_cap_offset =xhci_find_next_cap_offset (base,XHCI_HCC_PARAMS_OFFSET ); do { + if ((ext_cap_offset + sizeof(val)) > len) { + /* We're reading garbage from the controller */ + dev_warn(&pdev->dev, + "xHCI controller failing to respond"); + return; + } + if (!ext_cap_offset) /* We've reached the end of the extended capabilities */ goto hc_init; + val = readl(base + ext_cap_offset); if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) break;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 104/184 USB: EHCI: go back to using the system clock for QH
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
unlinks
From: Alan Stern <[email protected]>
commit 004c19682884d4f40000ce1ded53f4a1d0b18206 upstream
This patch (as1477) fixes a problem affecting a few types of EHCI controller. Contrary to what one might expect, these controllers automatically stop their internal frame counter when no ports are enabled. Since ehci-hcd currently relies on the frame counter for determining when it should unlink QHs from the async schedule, those controllers run into trouble: The frame counter stops and the QHs never get unlinked.
Some systems have also experienced other problems traced back to commit b963801164618e25fbdc0cd452ce49c3628b46c8 (USB: ehci-hcd unlink speedups), which made the original switch from using the system clock to using the frame counter. It never became clear what the reason was for these problems, but evidently it is related to use of the frame counter.
To fix all these problems, this patch more or less reverts that commit and goes back to using the system clock. But this can't be done cleanly because other changes have since been made to the scan_async() subroutine. One of these changes involved the tricky logic that tries to avoid rescanning QHs that have already been seen when the scanning loop is restarted, which happens whenever an URB is given back. Switching back to clock-based unlinks would make this logic even more complicated.
Therefore the new code doesn't rescan the entire async list whenever a giveback occurs. Instead it rescans only the current QH and continues on from there. This requires the use of a separate pointer to keep track of the next QH to scan, since the current QH may be unlinked while the scanning is in progress. That new pointer must be global, so that it can be adjusted forward whenever the _next_ QH gets unlinked. (uhci-hcd uses this same trick.)
Simplification of the scanning loop removes a level of indentation, which accounts for the size of the patch. The amount of code changed is relatively small, and it isn't exactly a reversion of the b963801164 commit.
This fixes Bugzilla #32432.
--- drivers/usb/host/ehci-hcd.c | 8 ++--- drivers/usb/host/ehci-q.c | 82 ++++++++++++++++++++++----------------------- drivers/usb/host/ehci.h | 3 +- 3 files changed, 45 insertions(+), 48 deletions(-)
drivers/usb/host/ehci-hcd.c +3 -5
@@ -84,7 +84,8 @@ static const char hcd_name [] = "ehci_hcd";#define EHCI_IAA_MSECS 10/* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10)/* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20)/* async idle timeout */ -#define EHCI_SHRINK_FRAMES 5/* async qh unlink delay */ +#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) +/* 200-ms async qh unlink delay */ /* Initial IRQ latency: faster than hw default */ static int log2_irq_thresh =0 ;// 0 to 6
@@ -139,10 +140,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)break ;/* case TIMER_ASYNC_SHRINK: */ default : -/* add a jiffie since we synch against the -* 8 KHz uframe counter. -*/ - t =DIV_ROUND_UP (EHCI_SHRINK_FRAMES *HZ ,1000 ) +1 ; + t =EHCI_SHRINK_JIFFIES ;break ; }mod_timer (&ehci->watchdog, t + jiffies);
drivers/usb/host/ehci-q.c +40 -42
99 lines not on this page · raw message
drivers/usb/host/ehci.h +2 -1
@@ -74,6 +74,7 @@ struct ehci_hcd { /* one per controller *//* async schedule support */ struct ehci_qh *async;struct ehci_qh *reclaim; +struct ehci_qh *qh_scan_next; unsigned scanning : 1;/* periodic schedule support */
@@ -116,7 +117,6 @@ struct ehci_hcd { /* one per controller */struct timer_list iaa_watchdog;struct timer_list watchdog;unsigned long actions; -unsigned stamp;unsigned random_frame;unsigned long next_statechange;ktime_t last_periodic_enable;
@@ -335,6 +335,7 @@ struct ehci_qh {struct ehci_qh *reclaim;/* next to reclaim */ struct ehci_hcd *ehci; +unsigned long unlink_time;/* * Do NOT use atomic operations for QH refcounting. On some CPUs
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 105/184 USB: whiteheat: fix memory leak in error path
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit c129197c99550d356cf5f69b046994dd53cd1b9d upstream.
Make sure command buffer is deallocated in case of errors during attach.
--- drivers/usb/serial/whiteheat.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/whiteheat.c +1 -0
@@ -576,6 +576,7 @@ no_firmware:"%s: please contact [email protected]\n" , serial->type->description);kfree (result); +kfree (command);return -ENODEV ; no_command_private:
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 106/184 USB: serial: Fix memory leak in sierra_release()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Lennart Sorensen <[email protected]>
commit f7bc5051667b74c3861f79eed98c60d5c3b883f7 upstream.
I found a memory leak in sierra_release() (well sierra_probe() I guess) that looses 8 bytes each time the driver releases a device.
--- drivers/usb/serial/sierra.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/sierra.c +1 -0
@@ -925,6 +925,7 @@ static void sierra_release(struct usb_serial *serial)continue ;kfree (portdata); } +kfree (serial->private); }#ifdef CONFIG_PM
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 107/184 USB: mos7840: fix urb leak at release
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 65a4cdbb170e4ec1a7fa0e94936d47e24a17b0e8 upstream.
Make sure control urb is freed at release.
--- drivers/usb/serial/mos7840.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/mos7840.c +1 -0
@@ -2636,6 +2636,7 @@ static void mos7840_release(struct usb_serial *serial) mos7840_port =mos7840_get_port_private (serial->port[i]);dbg ("mos7840_port %d = %p" , i, mos7840_port);if (mos7840_port) { +usb_free_urb (mos7840_port->control_urb);kfree (mos7840_port->ctrl_buf);kfree (mos7840_port->dr);kfree (mos7840_port);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 108/184 USB: mos7840: fix port-device leak in error path
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 3eb55cc4ed88eee3b5230f66abcdbd2a91639eda upstream.
The driver set the usb-serial port pointers to NULL on errors in attach, effectively preventing usb-serial core from decrementing the port ref counters and releasing the port devices and associated data.
--- drivers/usb/serial/mos7840.c | 1 - 1 file changed, 1 deletion(-)
drivers/usb/serial/mos7840.c +0 -1
@@ -2569,7 +2569,6 @@ error:kfree (mos7840_port->ctrl_buf);usb_free_urb (mos7840_port->control_urb);kfree (mos7840_port); - serial->port[i] =NULL ; }return status; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 109/184 USB: garmin_gps: fix memory leak on disconnect
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 618aa1068df29c37a58045fe940f9106664153fd upstream.
Remove bogus disconnect test introduced by 95bef012e ("USB: more serial drivers writing after disconnect") which prevented queued data from being freed on disconnect.
The possible IO it was supposed to prevent is long gone.
--- drivers/usb/serial/garmin_gps.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/usb/serial/garmin_gps.c +1 -6
@@ -974,10 +974,7 @@ static void garmin_close(struct usb_serial_port *port)if (!serial)return ; -mutex_lock (&port->serial->disc_mutex); - -if (!port->serial->disconnected) -garmin_clear (garmin_data_p); +garmin_clear (garmin_data_p);/* shutdown our urbs */ usb_kill_urb (port->read_urb);
@@ -986,8 +983,6 @@ static void garmin_close(struct usb_serial_port *port)/* keep reset state so we know that we must start a new session */ if (garmin_data_p->state !=STATE_RESET ) garmin_data_p->state =STATE_DISCONNECTED ; - -mutex_unlock (&port->serial->disc_mutex); }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 110/184 USB: io_ti: Fix NULL dereference in chase_port()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Wolfgang Frisch <[email protected]>
commit 1ee0a224bc9aad1de496c795f96bc6ba2c394811 upstream
The tty is NULL when the port is hanging up.chase_port() needs to check for this.
This patch is intended for stable series.
The behavior was observed and tested in Linux 3.2 and 3.7.1.
Johan Hovold submitted a more elaborate patch for the mainline kernel.
[ 56.277883] usb 1-1: edge_bulk_in_callback - nonzero read bulk status received: -84 [ 56.278811] usb 1-1: USB disconnect, device number 3 [ 56.278856] usb 1-1: edge_bulk_in_callback - stopping read! [ 56.279562] BUG: unable to handle kernel NULL pointer dereference at 00000000000001c8 [ 56.280536] IP: [<ffffffff8144e62a>] _raw_spin_lock_irqsave+0x19/0x35 [ 56.281212] PGD 1dc1b067 PUD 1e0f7067 PMD 0 [ 56.282085] Oops: 0002 [#1] SMP [ 56.282744] Modules linked in: [ 56.283512] CPU 1 [ 56.283512] Pid: 25, comm: khubd Not tainted 3.7.1 #1 innotek GmbH VirtualBox/VirtualBox [ 56.283512] RIP: 0010:[<ffffffff8144e62a>] [<ffffffff8144e62a>] _raw_spin_lock_irqsave+0x19/0x35 [ 56.283512] RSP: 0018:ffff88001fa99ab0 EFLAGS: 00010046 [ 56.283512] RAX: 0000000000000046 RBX: 00000000000001c8 RCX: 0000000000640064 [ 56.283512] RDX: 0000000000010000 RSI: ffff88001fa99b20 RDI: 00000000000001c8 [ 56.283512] RBP: ffff88001fa99b20 R08: 0000000000000000 R09: 0000000000000000 [ 56.283512] R10: 0000000000000000 R11: ffffffff812fcb4c R12: ffff88001ddf53c0 [ 56.283512] R13: 0000000000000000 R14: 00000000000001c8 R15: ffff88001e19b9f4 [ 56.283512] FS: 0000000000000000(0000) GS:ffff88001fd00000(0000) knlGS:0000000000000000 [ 56.283512] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 56.283512] CR2: 00000000000001c8 CR3: 000000001dc51000 CR4: 00000000000006e0 [ 56.283512] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 56.283512] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 56.283512] Process khubd (pid: 25, threadinfo ffff88001fa98000, task ffff88001fa94f80) [ 56.283512] Stack: [ 56.283512] 0000000000000046 00000000000001c8 ffffffff810578ec ffffffff812fcb4c [ 56.283512] ffff88001e19b980 0000000000002710 ffffffff812ffe81 0000000000000001 [ 56.283512] ffff88001fa94f80 0000000000000202 ffffffff00000001 0000000000000296 [ 56.283512] Call Trace: [ 56.283512] [<ffffffff810578ec>] ? add_wait_queue+0x12/0x3c [ 56.283512] [<ffffffff812fcb4c>] ? usb_serial_port_work+0x28/0x28 [ 56.283512] [<ffffffff812ffe81>] ? chase_port+0x84/0x2d6 [ 56.283512] [<ffffffff81063f27>] ? try_to_wake_up+0x199/0x199 [ 56.283512] [<ffffffff81263a5c>] ? tty_ldisc_hangup+0x222/0x298 [ 56.283512] [<ffffffff81300171>] ? edge_close+0x64/0x129 [ 56.283512] [<ffffffff810612f7>] ? __wake_up+0x35/0x46 [ 56.283512] [<ffffffff8106135b>] ? should_resched+0x5/0x23 [ 56.283512] [<ffffffff81264916>] ? tty_port_shutdown+0x39/0x44 [ 56.283512] [<ffffffff812fcb4c>] ? usb_serial_port_work+0x28/0x28 [ 56.283512] [<ffffffff8125d38c>] ? __tty_hangup+0x307/0x351 [ 56.283512] [<ffffffff812e6ddc>] ? usb_hcd_flush_endpoint+0xde/0xed [ 56.283512] [<ffffffff8144e625>] ? _raw_spin_lock_irqsave+0x14/0x35 [ 56.283512] [<ffffffff812fd361>] ? usb_serial_disconnect+0x57/0xc2 [ 56.283512] [<ffffffff812ea99b>] ? usb_unbind_interface+0x5c/0x131 [ 56.283512] [<ffffffff8128d738>] ? __device_release_driver+0x7f/0xd5 [ 56.283512] [<ffffffff8128d9cd>] ? device_release_driver+0x1a/0x25 [ 56.283512] [<ffffffff8128d393>] ? bus_remove_device+0xd2/0xe7 [ 56.283512] [<ffffffff8128b7a3>] ? device_del+0x119/0x167 [ 56.283512] [<ffffffff812e8d9d>] ? usb_disable_device+0x6a/0x180 [ 56.283512] [<ffffffff812e2ae0>] ? usb_disconnect+0x81/0xe6 [ 56.283512] [<ffffffff812e4435>] ? hub_thread+0x577/0xe82 [ 56.283512] [<ffffffff8144daa7>] ? __schedule+0x490/0x4be [ 56.283512] [<ffffffff8105798f>] ? abort_exclusive_wait+0x79/0x79 [ 56.283512] [<ffffffff812e3ebe>] ? usb_remote_wakeup+0x2f/0x2f [ 56.283512] [<ffffffff812e3ebe>] ? usb_remote_wakeup+0x2f/0x2f [ 56.283512] [<ffffffff810570b4>] ? kthread+0x81/0x89 [ 56.283512] [<ffffffff81057033>] ? __kthread_parkme+0x5c/0x5c [ 56.283512] [<ffffffff8145387c>] ? ret_from_fork+0x7c/0xb0 [ 56.283512] [<ffffffff81057033>] ? __kthread_parkme+0x5c/0x5c [ 56.283512] Code: 8b 7c 24 08 e8 17 0b c3 ff 48 8b 04 24 48 83 c4 10 c3 53 48 89 fb 41 50 e8 e0 0a c3 ff 48 89 04 24 e8 e7 0a c3 ff ba 00 00 01 00 <f0> 0f c1 13 48 8b 04 24 89 d1 c1 ea 10 66 39 d1 74 07 f3 90 66 [ 56.283512] RIP [<ffffffff8144e62a>] _raw_spin_lock_irqsave+0x19/0x35 [ 56.283512] RSP <ffff88001fa99ab0> [ 56.283512] CR2: 00000000000001c8 [ 56.283512] ---[ end trace 49714df27e1679ce ]---
--- drivers/usb/serial/io_ti.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/serial/io_ti.c +3 -0
@@ -574,6 +574,9 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,wait_queue_t wait;unsigned long flags; +if (!tty) +return ; +if (!timeout) timeout = (HZ *EDGE_CLOSING_WAIT )/100 ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 111/184 USB: cdc-wdm: fix buffer 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: Oliver Neukum <[email protected]>
commit c0f5ecee4e741667b2493c742b60b6218d40b3aa upstream.
The buffer for responses must not overflow.
If this would happen, set a flag, drop the data and return an error after user space has read all remaining data.
--- drivers/usb/class/cdc-wdm.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-)
drivers/usb/class/cdc-wdm.c +20 -3
@@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);#define WDM_READ 4#define WDM_INT_STALL 5#define WDM_POLL_RUNNING 6 +#define WDM_OVERFLOW 10#define WDM_MAX 16
@@ -115,6 +116,7 @@ static void wdm_in_callback(struct urb *urb) {struct wdm_device *desc = urb->context;int status = urb->status; +int length = urb->actual_length;spin_lock (&desc->iuspin);
@@ -144,9 +146,17 @@ static void wdm_in_callback(struct urb *urb) } desc->rerr = status; - desc->reslength = urb->actual_length; -memmove (desc->ubuf + desc->length, desc->inbuf, desc->reslength); - desc->length += desc->reslength; +if (length + desc->length > desc->wMaxCommand) { +/* The buffer would overflow */ +set_bit (WDM_OVERFLOW , &desc->flags); + }else { +/* we may already be in overflow */ +if (!test_bit (WDM_OVERFLOW , &desc->flags)) { +memmove (desc->ubuf + desc->length, desc->inbuf, length); + desc->length += length; + desc->reslength = length; + } + }wake_up (&desc->wait);set_bit (WDM_READ , &desc->flags);
@@ -398,6 +408,11 @@ retry: rv = -ENODEV ; goto err; } +if (test_bit (WDM_OVERFLOW , &desc->flags)) { +clear_bit (WDM_OVERFLOW , &desc->flags); + rv = -ENOBUFS ; + goto err; + } i++;if (file->f_flags &O_NONBLOCK ) {if (!test_bit (WDM_READ , &desc->flags)) {
@@ -440,6 +455,7 @@ retry:spin_unlock_irq (&desc->iuspin); goto retry; } +if (!desc->reslength) {/* zero length read */ dev_dbg (&desc->intf->dev,"%s: zero length - clearing WDM_READ\n" , __func__);clear_bit (WDM_READ , &desc->flags);
@@ -844,6 +860,7 @@ static int wdm_post_reset(struct usb_interface *intf)struct wdm_device *desc =usb_get_intfdata (intf);int rv; +clear_bit (WDM_OVERFLOW , &desc->flags); rv =recover_from_urb_loss (desc);mutex_unlock (&desc->plock);return 0 ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 111/184] USB: cdc-wdm: fix buffer overflow
Quoted 8 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <[email protected]>
commit
c0f5ecee4e741667b2493c742b60b6218d40b3aaupstream.
Quoted 7 lines
The buffer for responses must not overflow.
If this would happen, set a flag, drop the data and return an error after user space has read all remaining data.Signed-off-by Oliver Neukum <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>[bwh: Backported to 2.6.32: adjust context]
Quoted 74 lines
Signed-off-by Willy Tarreau <[email protected]>--- drivers/usb/class/cdc-wdm.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-)drivers/usb/class/cdc-wdm.c +20
-3@@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);#define WDM_READ 4#define WDM_INT_STALL 5#define WDM_POLL_RUNNING 6 +#define WDM_OVERFLOW 10#define WDM_MAX 16@@ -115,6 +116,7 @@ static void wdm_in_callback(struct urb *urb) {struct wdm_device *desc = urb->context;int status = urb->status; +int length = urb->actual_length;spin_lock (&desc->iuspin);@@ -144,9 +146,17 @@ static void wdm_in_callback(struct urb *urb) } desc->rerr = status; - desc->reslength = urb->actual_length; -memmove (desc->ubuf + desc->length, desc->inbuf, desc->reslength); - desc->length += desc->reslength; +if (length + desc->length > desc->wMaxCommand) { +/* The buffer would overflow */ +set_bit (WDM_OVERFLOW , &desc->flags); + }else { +/* we may already be in overflow */ +if (!test_bit (WDM_OVERFLOW , &desc->flags)) { +memmove (desc->ubuf + desc->length, desc->inbuf, length); + desc->length += length; + desc->reslength = length; + } + }wake_up (&desc->wait);set_bit (WDM_READ , &desc->flags);@@ -398,6 +408,11 @@ retry: rv = -ENODEV ; goto err; } +if (test_bit (WDM_OVERFLOW , &desc->flags)) { +clear_bit (WDM_OVERFLOW , &desc->flags); + rv = -ENOBUFS ; + goto err; + } i++;if (file->f_flags &O_NONBLOCK ) {if (!test_bit (WDM_READ , &desc->flags)) {@@ -440,6 +455,7 @@ retry:spin_unlock_irq (&desc->iuspin); goto retry; } +if (!desc->reslength) {/* zero length read */ dev_dbg (&desc->intf->dev,"%s: zero length - clearing WDM_READ\n" , __func__);clear_bit (WDM_READ , &desc->flags);@@ -844,6 +860,7 @@ static int wdm_post_reset(struct usb_interface *intf)struct wdm_device *desc =usb_get_intfdata (intf);int rv; +clear_bit (WDM_OVERFLOW , &desc->flags); rv =recover_from_urb_loss (desc);mutex_unlock (&desc->plock);return 0 ;
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 111/184] USB: cdc-wdm: fix buffer overflow
Quoted 13 lines · Ben Hutchings
Quoted 12 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Neukum <[email protected]>
commit
c0f5ecee4e741667b2493c742b60b6218d40b3aaupstream.The buffer for responses must not overflow.
If this would happen, set a flag, drop the data and return an error after user space has read all remaining data.
Quoted 5 lines
Quoted 3 lines
Signed-off-by Oliver Neukum <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>[bwh: Backported to 2.6.32: adjust context]Signed-off-by Ben Hutchings <[email protected]>
Added, thanks.
willy
PATCH 112/184 epoll: prevent missed events on EPOLL_CTL_MOD
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 Wong <[email protected]>
commit 128dd1759d96ad36c379240f8b9463e8acfd37a1 upstream.
EPOLL_CTL_MOD sets the interest mask before calling f_op->poll() to ensure events are not missed. Since the modifications to the interest mask are not protected by the same lock as ep_poll_callback, we need to ensure the change is visible to other CPUs calling ep_poll_callback.
We also need to ensure f_op->poll() has an up-to-date view of past events which occured before we modified the interest mask. So this barrier also pairs with the barrier in wq_has_sleeper().
This should guarantee either ep_poll_callback or f_op->poll() (or both) will notice the readiness of a recently-ready/modified item.
This issue was encountered by Andreas Voellmy and Junchang(Jason) Wang in:
http://thread.gmane.org/gmane.linux.kernel/1408782/
--- fs/eventpoll.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
fs/eventpoll.c +21 -1
@@ -1183,10 +1183,30 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even* otherwise we might miss an event that happens between the * f_op->poll() call and the new event set registering. */ - epi->event.events = event->events; + epi->event.events = event->events;/* need barrier below */ epi->event.data = event->data;/* protected by mtx */ /* +* The following barrier has two effects: +* +* 1) Flush epi changes above to other CPUs. This ensures +* we do not miss events from ep_poll_callback if an +* event occurs immediately after we call f_op->poll(). +* We need this because we did not take ep->lock while +* changing epi above (but ep_poll_callback does take +* ep->lock). +* +* 2) We also need to ensure we do not miss _past_ events +* when calling f_op->poll(). This barrier also +* pairs with the barrier in wq_has_sleeper (see +* comments for wq_has_sleeper). +* +* This barrier will now guarantee ep_poll_callback or f_op->poll +* (or both) will notice the readiness of an item. +*/ +smp_mb (); + +/* * Get current event bits. We can safely use the file* here because * its usage count has been increased by the caller of this function. */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 113/184 fs/compat_ioctl.c: VIDEO_SET_SPU_PALETTE missing
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
error check
From: Kees Cook <[email protected]>
commit 12176503366885edd542389eed3aaf94be163fdb upstream.
The compat ioctl for VIDEO_SET_SPU_PALETTE was missing an error check while converting ioctl arguments. This could lead to leaking kernel stack contents into userspace.
Patch extracted from existing fix in grsecurity.
--- fs/compat_ioctl.c | 2 ++ 1 file changed, 2 insertions(+)
fs/compat_ioctl.c +2 -0
@@ -234,6 +234,8 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd, unsigned up = (struct compat_video_spu_palette __user *) arg; err =get_user (palp, &up->palette); err |=get_user (length, &up->length); +if (err) +return -EFAULT ; up_native =compat_alloc_user_space (sizeof (struct video_spu_palette )); err =put_user (compat_ptr (palp), &up_native->palette);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 114/184 fs/fscache/stats.c: fix memory leak
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Anurup m <[email protected]>
commit ec686c9239b4d472052a271c505d04dae84214cc upstream.
There is a kernel memory leak observed when the proc file /proc/fs/fscache/stats is read.
The reason is that in fscache_stats_open, single_open is called and the respective release function is not called during release. Hence fix with correct release function - single_release().
Addresses https://bugzilla.kernel.org/show_bug.cgi?id=57101
--- fs/fscache/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/fscache/stats.c +1 -1
@@ -276,5 +276,5 @@ const struct file_operations fscache_stats_fops = { .open = fscache_stats_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, };
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 115/184 sysfs: sysfs_pathname/sysfs_add_one: Use strlcat()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
instead of strcat()
From: Geert Uytterhoeven <[email protected]>
commit 66081a72517a131430dcf986775f3268aafcb546 upstream.
The warning check for duplicate sysfs entries can cause a buffer overflow when printing the warning, as strcat() doesn't check buffer sizes. Use strlcat() instead.
Since strlcat() doesn't return a pointer to the passed buffer, unlike strcat(), I had to convert the nested concatenation in sysfs_add_one() to an admittedly more obscure comma operator construct, to avoid emitting code for the concatenation if CONFIG_BUG is disabled.
--- fs/sysfs/dir.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
fs/sysfs/dir.c +8 -8
@@ -440,20 +440,18 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)/** * sysfs_pathname - return full path to sysfs dirent * @sd: sysfs_dirent whose path we want -* @path: caller allocated buffer +* @path: caller allocated buffer of size PATH_MAX * * Gives the name "/" to the sysfs_root entry; any path returned * is relative to wherever sysfs is mounted. -* -* XXX: does no error checking on @path size */ static char *sysfs_pathname (struct sysfs_dirent *sd,char *path) {if (sd->s_parent) {sysfs_pathname (sd->s_parent, path); -strcat (path,"/" ); +strlcat (path,"/" ,PATH_MAX ); } -strcat (path, sd->s_name); +strlcat (path, sd->s_name,PATH_MAX );return path; }
@@ -486,9 +484,11 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)char *path =kzalloc (PATH_MAX ,GFP_KERNEL );WARN (1 ,KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n" , - (path ==NULL ) ? sd->s_name : -strcat (strcat (sysfs_pathname (acxt->parent_sd, path),"/" ), - sd->s_name)); + (path ==NULL ) ? sd->s_name + : (sysfs_pathname (acxt->parent_sd, path), +strlcat (path,"/" ,PATH_MAX ), +strlcat (path, sd->s_name,PATH_MAX ), + path));kfree (path); }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 116/184 tmpfs: fix use-after-free of mempolicy object
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Greg Thelen <[email protected]>
commit 5f00110f7273f9ff04ac69a5f85bb535a4fd0987 upstream.
The tmpfs remount logic preserves filesystem mempolicy if the mpol=M option is not specified in the remount request. A new policy can be specified if mpol=M is given.
Before this patch remounting an mpol bound tmpfs without specifying mpol= mount option in the remount request would set the filesystem's mempolicy object to a freed mempolicy object.
To reproduce the problem boot a DEBUG_PAGEALLOC kernel and run:
# mkdir /tmp/x
# mount -t tmpfs -o size=100M,mpol=interleave nodev /tmp/x
# grep /tmp/x /proc/mounts
nodev /tmp/x tmpfs rw,relatime,size=102400k,mpol=interleave:0-3 0 0# mount -o remount,size=200M nodev /tmp/x
# grep /tmp/x /proc/mounts
nodev /tmp/x tmpfs rw,relatime,size=204800k,mpol=??? 0 0
# note ? garbage in mpol=... output above # dd if=/dev/zero of=/tmp/x/f count=1
# panic herePanic:
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [< (null)>] (null)
[...]
Oops: 0010 [#1] SMP DEBUG_PAGEALLOC
Call Trace:
mpol_shared_policy_init+0xa5/0x160
shmem_get_inode+0x209/0x270
shmem_mknod+0x3e/0xf0
shmem_create+0x18/0x20
vfs_create+0xb5/0x130
do_last+0x9a1/0xea0
path_openat+0xb3/0x4d0
do_filp_open+0x42/0xa0
do_sys_open+0xfe/0x1e0
compat_sys_open+0x1b/0x20
cstar_dispatch+0x7/0x1fNon-debug kernels will not crash immediately because referencing the dangling mpol will not cause a fault. Instead the filesystem will reference a freed mempolicy object, which will cause unpredictable behavior.
The problem boils down to a dropped mpol reference below if shmem_parse_options() does not allocate a new mpol:
config = *sbinfo
shmem_parse_options(data, &config, true) mpol_put(sbinfo->mpol)
sbinfo->mpol = config.mpol /* BUG: saves unreferenced mpol */
This patch avoids the crash by not releasing the mempolicy if shmem_parse_options() doesn't create a new mpol.
How far back does this issue go? I see it in both 2.6.36 and 3.3. I did not look back further.
--- mm/shmem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
mm/shmem.c +8 -2
@@ -2242,6 +2242,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)unsigned long inodes;int error = -EINVAL ; + config.mpol =NULL ;if (shmem_parse_options (data, &config, true))return error;
@@ -2269,8 +2270,13 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) sbinfo->max_inodes = config.max_inodes; sbinfo->free_inodes = config.max_inodes - inodes; -mpol_put (sbinfo->mpol); - sbinfo->mpol = config.mpol;/* transfers initial ref */ +/* +* Preserve previous mempolicy unless mpol remount option was specified. +*/ +if (config.mpol) { +mpol_put (sbinfo->mpol); + sbinfo->mpol = config.mpol;/* transfers initial ref */ + } out:spin_unlock (&sbinfo->stat_lock);return error;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 117/184 jbd: Delay discarding buffers in
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
journal_unmap_buffer
From: Jan Kara <[email protected]>
Delay discarding buffers in journal_unmap_buffer until we know that "add to orphan" operation has definitely been committed, otherwise the log space of committing transation may be freed and reused before truncate get committed, updates may get lost if crash happens.
This patch is a backport of JBD2 fix by dingdinghua <[email protected]>.
--- fs/jbd/commit.c | 10 +++++----- fs/jbd/transaction.c | 43 +++++++++++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 17 deletions(-)
fs/jbd/commit.c +5 -5
@@ -867,12 +867,12 @@ restart_loop:/* A buffer which has been freed while still being * journaled by a previous transaction may end up still * being dirty here, but we want to avoid writing back -* that buffer in the future now that the last use has -* been committed. That's not only a performance gain, -* it also stops aliasing problems if the buffer is left -* behind for writeback and gets reallocated for another +* that buffer in the future after the "add to orphan" +* operation been committed, That's not only a performance +* gain, it also stops aliasing problems if the buffer is +* left behind for writeback and gets reallocated for another * use in a different page. */ -if (buffer_freed (bh)) { +if (buffer_freed (bh) && !jh->b_next_transaction) {clear_buffer_freed (bh);clear_buffer_jbddirty (bh); }
fs/jbd/transaction.c +31 -12
68 lines not on this page · raw message
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 118/184 jbd: Fix assertion failure in commit code due to
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
lacking transaction credits
From: Jan Kara <[email protected]>
ext3 users of data=journal mode with blocksize < pagesize were occasionally hitting assertion failure in journal_commit_transaction() checking whether the transaction has at least as many credits reserved as buffers attached. The core of the problem is that when a file gets truncated, buffers that still need checkpointing or that are attached to the committing transaction are left with buffer_mapped set. When this happens to buffers beyond i_size attached to a page stradding i_size, subsequent write extending the file will see these buffers and as they are mapped (but underlying blocks were freed) things go awry from here.
The assertion failure just coincidentally (and in this case luckily as we would start corrupting filesystem) triggers due to journal_head not being properly cleaned up as well.
Under some rare circumstances this bug could even hit data=ordered mode users. There the assertion won't trigger and we would end up corrupting the filesystem.
We fix the problem by unmapping buffers if possible (in lots of cases we just need a buffer attached to a transaction as a place holder but it must not be written out anyway). And in one case, we just have to bite the bullet and wait for transaction commit to finish.
--- fs/jbd/commit.c | 45 +++++++++++++++++++++++++++--------- fs/jbd/transaction.c | 64 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 78 insertions(+), 31 deletions(-)
fs/jbd/commit.c +34 -11
@@ -85,7 +85,12 @@ nope:static void release_data_buffer (struct buffer_head *bh) {if (buffer_freed (bh)) { +WARN_ON_ONCE (buffer_dirty (bh));clear_buffer_freed (bh); +clear_buffer_mapped (bh); +clear_buffer_new (bh); +clear_buffer_req (bh); + bh->b_bdev =NULL ;release_buffer_page (bh); }else put_bh (bh);
@@ -864,17 +869,35 @@ restart_loop:* there's no point in keeping a checkpoint record for * it. */ -/* A buffer which has been freed while still being -* journaled by a previous transaction may end up still -* being dirty here, but we want to avoid writing back -* that buffer in the future after the "add to orphan" -* operation been committed, That's not only a performance -* gain, it also stops aliasing problems if the buffer is -* left behind for writeback and gets reallocated for another -* use in a different page. */ -if (buffer_freed (bh) && !jh->b_next_transaction) { -clear_buffer_freed (bh); -clear_buffer_jbddirty (bh); +/* +* A buffer which has been freed while still being journaled by +* a previous transaction. +*/ +if (buffer_freed (bh)) { +/* +* If the running transaction is the one containing +* "add to orphan" operation (b_next_transaction != +* NULL), we have to wait for that transaction to +* commit before we can really get rid of the buffer. +* So just clear b_modified to not confuse transaction +* credit accounting and refile the buffer to +* BJ_Forget of the running transaction. If the just +* committed transaction contains "add to orphan" +* operation, we can completely invalidate the buffer +* now. We are rather throughout in that since the +* buffer may be still accessible when blocksize < +* pagesize and it is attached to the last partial +* page. +*/ + jh->b_modified =0 ; +if (!jh->b_next_transaction) { +clear_buffer_freed (bh); +clear_buffer_jbddirty (bh); +clear_buffer_mapped (bh); +clear_buffer_new (bh); +clear_buffer_req (bh); + bh->b_bdev =NULL ; + } }if (buffer_jbddirty (bh)) {
fs/jbd/transaction.c +44 -20
118 lines not on this page · raw message
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 119/184 jbd: Fix lock ordering bug in journal_unmap_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: Jan Kara <[email protected]>
commit 25389bb207987b5774182f763b9fb65ff08761c8 upstream.
Commit 09e05d48 introduced a wait for transaction commit into journal_unmap_buffer() in the case we are truncating a buffer undergoing commit in the page stradding i_size on a filesystem with blocksize < pagesize. Sadly we forgot to drop buffer lock before waiting for transaction commit and thus deadlock is possible when kjournald wants to lock the buffer.
Fix the problem by dropping the buffer lock before waiting for transaction commit. Since we are still holding page lock (and that is OK), buffer cannot disappear under us.
--- fs/jbd/transaction.c | 2 ++ 1 file changed, 2 insertions(+)
fs/jbd/transaction.c +2 -0
@@ -1956,7 +1956,9 @@ retry:spin_unlock (&journal->j_list_lock);jbd_unlock_bh_state (bh);spin_unlock (&journal->j_state_lock); +unlock_buffer (bh);log_wait_commit (journal, tid); +lock_buffer (bh); goto retry; }/*
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 120/184 ext4: Fix fs corruption when make_indexed_dir()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
fails
From: Jan Kara <[email protected]>
When make_indexed_dir() fails (e.g. because of ENOSPC) after it has allocated block for index tree root, we did not properly mark all changed buffers dirty. This lead to only some of these buffers being written out and thus effectively corrupting the directory.
Fix the issue by marking all changed data dirty even in the error failure case.
--- fs/ext4/namei.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
fs/ext4/namei.c +12 -2
@@ -1458,9 +1458,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, frame->bh = bh; bh = bh2; de =do_split (handle,dir, &bh, frame, &hinfo, &retval); -dx_release (frames); -if (!(de)) +if (!de) { +/* +* Even if the block split failed, we have to properly write +* out all the changes we did so far. Otherwise we can end up +* with corrupted filesystem. +*/ +ext4_mark_inode_dirty (handle, dir); +ext4_handle_dirty_metadata (handle, dir, frame->bh); +ext4_handle_dirty_metadata (handle, dir, bh); +dx_release (frames);return retval; + } +dx_release (frames); retval =add_dirent_to_buf (handle, dentry, inode, de, bh);brelse (bh);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 121/184 ext4: dont dereference null pointer when
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
make_indexed_dir() fails
From: Allison Henderson <[email protected]>
Fix for a null pointer bug found while running punch hole tests
--- fs/ext4/namei.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/ext4/namei.c +4 -2
@@ -1457,6 +1457,10 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, frame->at = entries; frame->bh = bh; bh = bh2; + +ext4_handle_dirty_metadata (handle, dir, frame->bh); +ext4_handle_dirty_metadata (handle, dir, bh); + de =do_split (handle,dir, &bh, frame, &hinfo, &retval);if (!de) {/*
@@ -1465,8 +1469,6 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,* with corrupted filesystem. */ ext4_mark_inode_dirty (handle, dir); -ext4_handle_dirty_metadata (handle, dir, frame->bh); -ext4_handle_dirty_metadata (handle, dir, bh);dx_release (frames);return retval; }
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 122/184 ext4: Fix max file size and logical block counting
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
of extent format file
From: Lukas Czerner <[email protected]>
commit f17722f917b2f21497deb6edc62fb1683daa08e6 upstream
Kazuya Mio reported that he was able to hit BUG_ON(next == lblock) in ext4_ext_put_gap_in_cache() while creating a sparse file in extent format and fill the tail of file up to its end. We will hit the BUG_ON when we write the last block (2^32-1) into the sparse file.
The root cause of the problem lies in the fact that we specifically set s_maxbytes so that block at s_maxbytes fit into on-disk extent format, which is 32 bit long. However, we are not storing start and end block number, but rather start block number and length in blocks. It means that in order to cover extent from 0 to EXT_MAX_BLOCK we need EXT_MAX_BLOCK+1 to fit into len (because we counting block 0 as well) - and it does not.
The only way to fix it without changing the meaning of the struct ext4_extent members is, as Kazuya Mio suggested, to lower s_maxbytes by one fs block so we can cover the whole extent we can get by the on-disk extent format.
Also in many places EXT_MAX_BLOCK is used as length instead of maximum logical block number as the name suggests, it is all a bit messy. So this commit renames it to EXT_MAX_BLOCKS and change its usage in some places to actually be maximum number of blocks in the extent.
The bug which this commit fixes can be reproduced as follows:
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-2)) sync
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-1))
--- fs/ext4/ext4_extents.h | 7 +++++-- fs/ext4/extents.c | 39 +++++++++++++++++++-------------------- fs/ext4/move_extent.c | 10 +++++----- fs/ext4/super.c | 15 ++++++++++++--- 4 files changed, 41 insertions(+), 30 deletions(-)
fs/ext4/ext4_extents.h +5 -2
@@ -137,8 +137,11 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,#define EXT_BREAK 1#define EXT_REPEAT 2 -/* Maximum logical block in a file; ext4_extent's ee_block is __le32 */ -#define EXT_MAX_BLOCK 0xffffffff +/* +* Maximum number of logical blocks in a file; ext4_extent's ee_block is +* __le32. +*/ +#define EXT_MAX_BLOCKS 0xffffffff/* * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
fs/ext4/extents.c +19 -20
@@ -1331,7 +1331,7 @@ got_index:/* * ext4_ext_next_allocated_block: -* returns allocated block in subsequent extent or EXT_MAX_BLOCK. +* returns allocated block in subsequent extent or EXT_MAX_BLOCKS. * NOTE: it considers block number from index entry as * allocated block. Thus, index entries have to be consistent * with leaves.
@@ -1345,7 +1345,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) depth = path->p_depth;if (depth ==0 && path->p_ext ==NULL ) -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ;while (depth >=0 ) {if (depth == path->p_depth) {
@@ -1362,12 +1362,12 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) depth--; } -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ; }/* * ext4_ext_next_leaf_block: -* returns first allocated block from next leaf or EXT_MAX_BLOCK +* returns first allocated block from next leaf or EXT_MAX_BLOCKS */ static ext4_lblk_t ext4_ext_next_leaf_block (struct inode *inode,struct ext4_ext_path *path)
@@ -1379,7 +1379,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,/* zero-tree has no leaf blocks at all */ if (depth ==0 ) -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ;/* go to index block */ depth--;
@@ -1392,7 +1392,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode, depth--; } -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ; }/*
@@ -1572,13 +1572,13 @@ unsigned int ext4_ext_check_overlap(struct inode *inode,*/ if (b2 < b1) { b2 =ext4_ext_next_allocated_block (path); -if (b2 ==EXT_MAX_BLOCK ) +if (b2 ==EXT_MAX_BLOCKS ) goto out; }/* check for wrap through zero on extent logical start block*/ if (b1 + len1 < b1) { - len1 =EXT_MAX_BLOCK - b1; + len1 =EXT_MAX_BLOCKS - b1; newext->ee_len =cpu_to_le16 (len1); ret =1 ; }
@@ -1654,7 +1654,7 @@ repeat: fex =EXT_LAST_EXTENT (eh); next =ext4_ext_next_leaf_block (inode, path);if (le32_to_cpu (newext->ee_block) >le32_to_cpu (fex->ee_block) - && next !=EXT_MAX_BLOCK ) { + && next !=EXT_MAX_BLOCKS ) {ext_debug ("next leaf block - %d\n" , next);BUG_ON (npath !=NULL ); npath =ext4_ext_find_extent (inode, next,NULL );
@@ -1772,7 +1772,7 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,BUG_ON (func ==NULL );BUG_ON (inode ==NULL ); -while (block < last && block !=EXT_MAX_BLOCK ) { +while (block < last && block !=EXT_MAX_BLOCKS ) { num = last - block;/* find extent for this block */ down_read (&EXT4_I (inode)->i_data_sem);
@@ -1900,7 +1900,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,if (ex ==NULL ) {/* there is no extent yet, so gap is [0;-] */ lblock =0 ; - len =EXT_MAX_BLOCK ; + len =EXT_MAX_BLOCKS ;ext_debug ("cache gap(whole file):" ); }else if (block <le32_to_cpu (ex->ee_block)) { lblock = block;
@@ -2145,8 +2145,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, path[depth].p_ext = ex; a = ex_ee_block > start ? ex_ee_block : start; - b = ex_ee_block + ex_ee_len -1 <EXT_MAX_BLOCK ? - ex_ee_block + ex_ee_len -1 :EXT_MAX_BLOCK ; + b = ex_ee_block + ex_ee_len -1 <EXT_MAX_BLOCKS ? + ex_ee_block + ex_ee_len -1 :EXT_MAX_BLOCKS ;ext_debug (" border %u:%u\n" , a, b);
@@ -3783,15 +3783,14 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, flags |=FIEMAP_EXTENT_UNWRITTEN ;/* -* If this extent reaches EXT_MAX_BLOCK, it must be last. +* If this extent reaches EXT_MAX_BLOCKS, it must be last. * -* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK, +* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCKS, * this also indicates no more allocated blocks. * -* XXX this might miss a single-block extent at EXT_MAX_BLOCK */ -if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCK || - newex->ec_block + newex->ec_len -1 ==EXT_MAX_BLOCK ) { +if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCKS || + newex->ec_block + newex->ec_len ==EXT_MAX_BLOCKS ) {loff_t size =i_size_read (inode);loff_t bs =EXT4_BLOCK_SIZE (inode->i_sb);
@@ -3871,8 +3870,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, start_blk = start >> inode->i_sb->s_blocksize_bits; last_blk = (start + len -1 ) >> inode->i_sb->s_blocksize_bits; -if (last_blk >=EXT_MAX_BLOCK ) - last_blk =EXT_MAX_BLOCK -1 ; +if (last_blk >=EXT_MAX_BLOCKS ) + last_blk =EXT_MAX_BLOCKS -1 ; len_blks = ((ext4_lblk_t ) last_blk) - start_blk +1 ;/*
fs/ext4/move_extent.c +5 -5
@@ -1001,12 +1001,12 @@ mext_check_arguments(struct inode *orig_inode,return -EINVAL ; } -if ((orig_start >EXT_MAX_BLOCK ) || - (donor_start >EXT_MAX_BLOCK ) || - (*len >EXT_MAX_BLOCK ) || - (orig_start + *len >EXT_MAX_BLOCK )) { +if ((orig_start >=EXT_MAX_BLOCKS ) || + (donor_start >=EXT_MAX_BLOCKS ) || + (*len >EXT_MAX_BLOCKS ) || + (orig_start + *len >=EXT_MAX_BLOCKS )) {ext4_debug ("ext4 move extent: Can't handle over [%u] blocks " -"[ino:orig %lu, donor %lu]\n" ,EXT_MAX_BLOCK , +"[ino:orig %lu, donor %lu]\n" ,EXT_MAX_BLOCKS , orig_inode->i_ino, donor_inode->i_ino);return -EINVAL ; }
fs/ext4/super.c +12 -3
@@ -1975,6 +1975,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,* in the vfs. ext4 inode has 48 bits of i_block in fsblock units, * so that won't be a limiting factor. * +* However there is other limiting factor. We do store extents in the form +* of starting block and length, hence the resulting length of the extent +* covering maximum file size must fit into on-disk format containers as +* well. Given that length is always by 1 unit bigger than max unit (because +* we count 0 as well) we have to lower the s_maxbytes by one fs block. +* * Note, this does *not* consider any metadata overhead for vfs i_blocks. */ static loff_t ext4_max_size (int blkbits,int has_huge_files)
@@ -1996,10 +2002,13 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) upper_limit <<= blkbits; } -/* 32-bit extent-start container, ee_block */ - res =1LL <<32 ; +/* +* 32-bit extent-start container, ee_block. We lower the maxbytes +* by one fs block, so ee_len can cover the extent of maximum file +* size +*/ + res = (1LL <<32 ) -1 ; res <<= blkbits; - res -=1 ;/* Sanity check against vm- & vfs- imposed limits */ if (res > upper_limit)
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 122/184] ext4: Fix max file size and logical block counting
Quoted 8 lines · Willy Tarreau
Date: Tue, 04 Jun 2013 19:23:32 +0200
From: Willy Tarreau <[email protected]>
To: [email protected], [email protected]
Cc: Lukas Czerner <[email protected]>, Theodore Tso <[email protected]>,
Willy Tarreau <[email protected]>
Subject: [ 122/184] ext4: Fix max file size and logical block counting2.6.32-longterm review patch. If anyone has any objections, please let me know.
Now it looks like we could get rid of this thing in e2fsprogs as well. As well as remove the remaining bits from kernel. What do you think Ted ?
-Lukas
Quoted 264 lines
------------------
of extent format fileFrom: Lukas Czerner <[email protected]>
commit
f17722f917b2f21497deb6edc62fb1683daa08e6upstreamKazuya Mio reported that he was able to hit
BUG_ON(next == lblock)inext4_ext_put_gap_in_cache()while creating a sparse file in extent format and fill the tail of file up to its end. We will hit theBUG_ONwhen we write the last block (2^32-1) into the sparse file.The root cause of the problem lies in the fact that we specifically set
s_maxbytesso that block ats_maxbytesfit into on-disk extent format, which is 32 bit long. However, we are not storing start and end block number, but rather start block number and length in blocks. It means that in order to cover extent from 0 toEXT_MAX_BLOCKwe need EXT_MAX_BLOCK+1 to fit into len (because we counting block 0 as well) - and it does not.The only way to fix it without changing the meaning of the struct
ext4_extentmembers is, as Kazuya Mio suggested, to lowers_maxbytesby one fs block so we can cover the whole extent we can get by the on-disk extent format.Also in many places
EXT_MAX_BLOCKis used as length instead of maximum logical block number as the name suggests, it is all a bit messy. So this commit renames it toEXT_MAX_BLOCKSand change its usage in some places to actually be maximum number of blocks in the extent.The bug which this commit fixes can be reproduced as follows:
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-2)) sync
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-1))Reported-by Kazuya Mio <[email protected]>Signed-off-by Lukas Czerner <[email protected]>Signed-off-by "Theodore Ts'o" <[email protected]>[dannf: Applied the backport from RHEL6 to Debian's 2.6.32]Signed-off-by Willy Tarreau <[email protected]>--- fs/ext4/ext4_extents.h | 7 +++++-- fs/ext4/extents.c | 39 +++++++++++++++++++-------------------- fs/ext4/move_extent.c | 10 +++++----- fs/ext4/super.c | 15 ++++++++++++--- 4 files changed, 41 insertions(+), 30 deletions(-)fs/ext4/ext4_extents.h +5
-2@@ -137,8 +137,11 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,#define EXT_BREAK 1#define EXT_REPEAT 2 -/* Maximum logical block in a file; ext4_extent's ee_block is __le32 */ -#define EXT_MAX_BLOCK 0xffffffff +/* +* Maximum number of logical blocks in a file; ext4_extent's ee_block is +* __le32. +*/ +#define EXT_MAX_BLOCKS 0xffffffff/* * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an fs/ext4/extents.c +19
-20@@ -1331,7 +1331,7 @@ got_index:/* * ext4_ext_next_allocated_block: -* returns allocated block in subsequent extent or EXT_MAX_BLOCK. +* returns allocated block in subsequent extent or EXT_MAX_BLOCKS. * NOTE: it considers block number from index entry as * allocated block. Thus, index entries have to be consistent * with leaves. @@ -1345,7 +1345,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) depth = path->p_depth;if (depth ==0 && path->p_ext ==NULL ) -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ;while (depth >=0 ) {if (depth == path->p_depth) {@@ -1362,12 +1362,12 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) depth--; } -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ; }/* * ext4_ext_next_leaf_block: -* returns first allocated block from next leaf or EXT_MAX_BLOCK +* returns first allocated block from next leaf or EXT_MAX_BLOCKS */ static ext4_lblk_t ext4_ext_next_leaf_block (struct inode *inode,struct ext4_ext_path *path)@@ -1379,7 +1379,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,/* zero-tree has no leaf blocks at all */ if (depth ==0 ) -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ;/* go to index block */ depth--;@@ -1392,7 +1392,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode, depth--; } -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ; }/* @@ -1572,13 +1572,13 @@ unsigned int ext4_ext_check_overlap(struct inode *inode,*/ if (b2 < b1) { b2 =ext4_ext_next_allocated_block (path); -if (b2 ==EXT_MAX_BLOCK ) +if (b2 ==EXT_MAX_BLOCKS ) goto out; }/* check for wrap through zero on extent logical start block*/ if (b1 + len1 < b1) { - len1 =EXT_MAX_BLOCK - b1; + len1 =EXT_MAX_BLOCKS - b1; newext->ee_len =cpu_to_le16 (len1); ret =1 ; }@@ -1654,7 +1654,7 @@ repeat: fex =EXT_LAST_EXTENT (eh); next =ext4_ext_next_leaf_block (inode, path);if (le32_to_cpu (newext->ee_block) >le32_to_cpu (fex->ee_block) - && next !=EXT_MAX_BLOCK ) { + && next !=EXT_MAX_BLOCKS ) {ext_debug ("next leaf block - %d\n" , next);BUG_ON (npath !=NULL ); npath =ext4_ext_find_extent (inode, next,NULL );@@ -1772,7 +1772,7 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,BUG_ON (func ==NULL );BUG_ON (inode ==NULL ); -while (block < last && block !=EXT_MAX_BLOCK ) { +while (block < last && block !=EXT_MAX_BLOCKS ) { num = last - block;/* find extent for this block */ down_read (&EXT4_I (inode)->i_data_sem);@@ -1900,7 +1900,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,if (ex ==NULL ) {/* there is no extent yet, so gap is [0;-] */ lblock =0 ; - len =EXT_MAX_BLOCK ; + len =EXT_MAX_BLOCKS ;ext_debug ("cache gap(whole file):" ); }else if (block <le32_to_cpu (ex->ee_block)) { lblock = block;@@ -2145,8 +2145,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, path[depth].p_ext = ex; a = ex_ee_block > start ? ex_ee_block : start; - b = ex_ee_block + ex_ee_len -1 <EXT_MAX_BLOCK ? - ex_ee_block + ex_ee_len -1 :EXT_MAX_BLOCK ; + b = ex_ee_block + ex_ee_len -1 <EXT_MAX_BLOCKS ? + ex_ee_block + ex_ee_len -1 :EXT_MAX_BLOCKS ;ext_debug (" border %u:%u\n" , a, b);@@ -3783,15 +3783,14 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, flags |=FIEMAP_EXTENT_UNWRITTEN ;/* -* If this extent reaches EXT_MAX_BLOCK, it must be last. +* If this extent reaches EXT_MAX_BLOCKS, it must be last. * -* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK, +* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCKS, * this also indicates no more allocated blocks. * -* XXX this might miss a single-block extent at EXT_MAX_BLOCK */ -if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCK || - newex->ec_block + newex->ec_len -1 ==EXT_MAX_BLOCK ) { +if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCKS || + newex->ec_block + newex->ec_len ==EXT_MAX_BLOCKS ) {loff_t size =i_size_read (inode);loff_t bs =EXT4_BLOCK_SIZE (inode->i_sb);@@ -3871,8 +3870,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, start_blk = start >> inode->i_sb->s_blocksize_bits; last_blk = (start + len -1 ) >> inode->i_sb->s_blocksize_bits; -if (last_blk >=EXT_MAX_BLOCK ) - last_blk =EXT_MAX_BLOCK -1 ; +if (last_blk >=EXT_MAX_BLOCKS ) + last_blk =EXT_MAX_BLOCKS -1 ; len_blks = ((ext4_lblk_t ) last_blk) - start_blk +1 ;/* fs/ext4/move_extent.c +5
-5@@ -1001,12 +1001,12 @@ mext_check_arguments(struct inode *orig_inode,return -EINVAL ; } -if ((orig_start >EXT_MAX_BLOCK ) || - (donor_start >EXT_MAX_BLOCK ) || - (*len >EXT_MAX_BLOCK ) || - (orig_start + *len >EXT_MAX_BLOCK )) { +if ((orig_start >=EXT_MAX_BLOCKS ) || + (donor_start >=EXT_MAX_BLOCKS ) || + (*len >EXT_MAX_BLOCKS ) || + (orig_start + *len >=EXT_MAX_BLOCKS )) {ext4_debug ("ext4 move extent: Can't handle over [%u] blocks " -"[ino:orig %lu, donor %lu]\n" ,EXT_MAX_BLOCK , +"[ino:orig %lu, donor %lu]\n" ,EXT_MAX_BLOCKS , orig_inode->i_ino, donor_inode->i_ino);return -EINVAL ; }fs/ext4/super.c +12
-3@@ -1975,6 +1975,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,* in the vfs. ext4 inode has 48 bits of i_block in fsblock units, * so that won't be a limiting factor. * +* However there is other limiting factor. We do store extents in the form +* of starting block and length, hence the resulting length of the extent +* covering maximum file size must fit into on-disk format containers as +* well. Given that length is always by 1 unit bigger than max unit (because +* we count 0 as well) we have to lower the s_maxbytes by one fs block. +* * Note, this does *not* consider any metadata overhead for vfs i_blocks. */ static loff_t ext4_max_size (int blkbits,int has_huge_files)@@ -1996,10 +2002,13 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) upper_limit <<= blkbits; } -/* 32-bit extent-start container, ee_block */ - res =1LL <<32 ; +/* +* 32-bit extent-start container, ee_block. We lower the maxbytes +* by one fs block, so ee_len can cover the extent of maximum file +* size +*/ + res = (1LL <<32 ) -1 ; res <<= blkbits; - res -=1 ;/* Sanity check against vm- & vfs- imposed limits */ if (res > upper_limit)
Re: [ 122/184] ext4: Fix max file size and logical block counting
Quoted 16 lines · Lukᅵ Czerner
Date: Wed, 5 Jun 2013 11:26:55 +0200 (CEST)
From: Lukᅵ Czerner <[email protected]>
To: Willy Tarreau <[email protected]>
Cc: [email protected], [email protected],
Theodore Tso <[email protected]>
Subject: Re: [ 122/184] ext4: Fix max file size and logical block countingQuoted 7 lines · Willy Tarreau
Date: Tue, 04 Jun 2013 19:23:32 +0200
From: Willy Tarreau <[email protected]>
To: [email protected], [email protected]
Cc: Lukas Czerner <[email protected]>, Theodore Tso <[email protected]>,
Willy Tarreau <[email protected]>
Subject: [ 122/184] ext4: Fix max file size and logical block counting
Quoted 5 lines
Quoted 1 line
2.6.32-longterm review patch. If anyone has any objections, please let me know.
Now it looks like we could get rid of this thing in e2fsprogs as well. As well as remove the remaining bits from kernel. What do you think Ted ?
Oops, this is not the commit I was looking for. Sorry for the noise!
-Lukas
Quoted 268 lines
-Lukas
Quoted 264 lines
------------------
of extent format fileFrom: Lukas Czerner <[email protected]>
commit
f17722f917b2f21497deb6edc62fb1683daa08e6upstreamKazuya Mio reported that he was able to hit
BUG_ON(next == lblock)inext4_ext_put_gap_in_cache()while creating a sparse file in extent format and fill the tail of file up to its end. We will hit theBUG_ONwhen we write the last block (2^32-1) into the sparse file.The root cause of the problem lies in the fact that we specifically set
s_maxbytesso that block ats_maxbytesfit into on-disk extent format, which is 32 bit long. However, we are not storing start and end block number, but rather start block number and length in blocks. It means that in order to cover extent from 0 toEXT_MAX_BLOCKwe need EXT_MAX_BLOCK+1 to fit into len (because we counting block 0 as well) - and it does not.The only way to fix it without changing the meaning of the struct
ext4_extentmembers is, as Kazuya Mio suggested, to lowers_maxbytesby one fs block so we can cover the whole extent we can get by the on-disk extent format.Also in many places
EXT_MAX_BLOCKis used as length instead of maximum logical block number as the name suggests, it is all a bit messy. So this commit renames it toEXT_MAX_BLOCKSand change its usage in some places to actually be maximum number of blocks in the extent.The bug which this commit fixes can be reproduced as follows:
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-2)) sync
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-1))Reported-by Kazuya Mio <[email protected]>Signed-off-by Lukas Czerner <[email protected]>Signed-off-by "Theodore Ts'o" <[email protected]>[dannf: Applied the backport from RHEL6 to Debian's 2.6.32]Signed-off-by Willy Tarreau <[email protected]>--- fs/ext4/ext4_extents.h | 7 +++++-- fs/ext4/extents.c | 39 +++++++++++++++++++-------------------- fs/ext4/move_extent.c | 10 +++++----- fs/ext4/super.c | 15 ++++++++++++--- 4 files changed, 41 insertions(+), 30 deletions(-)fs/ext4/ext4_extents.h +5
-2@@ -137,8 +137,11 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,#define EXT_BREAK 1#define EXT_REPEAT 2 -/* Maximum logical block in a file; ext4_extent's ee_block is __le32 */ -#define EXT_MAX_BLOCK 0xffffffff +/* +* Maximum number of logical blocks in a file; ext4_extent's ee_block is +* __le32. +*/ +#define EXT_MAX_BLOCKS 0xffffffff/* * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an fs/ext4/extents.c +19
-20@@ -1331,7 +1331,7 @@ got_index:/* * ext4_ext_next_allocated_block: -* returns allocated block in subsequent extent or EXT_MAX_BLOCK. +* returns allocated block in subsequent extent or EXT_MAX_BLOCKS. * NOTE: it considers block number from index entry as * allocated block. Thus, index entries have to be consistent * with leaves. @@ -1345,7 +1345,7 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) depth = path->p_depth;if (depth ==0 && path->p_ext ==NULL ) -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ;while (depth >=0 ) {if (depth == path->p_depth) {@@ -1362,12 +1362,12 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path) depth--; } -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ; }/* * ext4_ext_next_leaf_block: -* returns first allocated block from next leaf or EXT_MAX_BLOCK +* returns first allocated block from next leaf or EXT_MAX_BLOCKS */ static ext4_lblk_t ext4_ext_next_leaf_block (struct inode *inode,struct ext4_ext_path *path)@@ -1379,7 +1379,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode,/* zero-tree has no leaf blocks at all */ if (depth ==0 ) -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ;/* go to index block */ depth--;@@ -1392,7 +1392,7 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct inode *inode, depth--; } -return EXT_MAX_BLOCK ; +return EXT_MAX_BLOCKS ; }/* @@ -1572,13 +1572,13 @@ unsigned int ext4_ext_check_overlap(struct inode *inode,*/ if (b2 < b1) { b2 =ext4_ext_next_allocated_block (path); -if (b2 ==EXT_MAX_BLOCK ) +if (b2 ==EXT_MAX_BLOCKS ) goto out; }/* check for wrap through zero on extent logical start block*/ if (b1 + len1 < b1) { - len1 =EXT_MAX_BLOCK - b1; + len1 =EXT_MAX_BLOCKS - b1; newext->ee_len =cpu_to_le16 (len1); ret =1 ; }@@ -1654,7 +1654,7 @@ repeat: fex =EXT_LAST_EXTENT (eh); next =ext4_ext_next_leaf_block (inode, path);if (le32_to_cpu (newext->ee_block) >le32_to_cpu (fex->ee_block) - && next !=EXT_MAX_BLOCK ) { + && next !=EXT_MAX_BLOCKS ) {ext_debug ("next leaf block - %d\n" , next);BUG_ON (npath !=NULL ); npath =ext4_ext_find_extent (inode, next,NULL );@@ -1772,7 +1772,7 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,BUG_ON (func ==NULL );BUG_ON (inode ==NULL ); -while (block < last && block !=EXT_MAX_BLOCK ) { +while (block < last && block !=EXT_MAX_BLOCKS ) { num = last - block;/* find extent for this block */ down_read (&EXT4_I (inode)->i_data_sem);@@ -1900,7 +1900,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,if (ex ==NULL ) {/* there is no extent yet, so gap is [0;-] */ lblock =0 ; - len =EXT_MAX_BLOCK ; + len =EXT_MAX_BLOCKS ;ext_debug ("cache gap(whole file):" ); }else if (block <le32_to_cpu (ex->ee_block)) { lblock = block;@@ -2145,8 +2145,8 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, path[depth].p_ext = ex; a = ex_ee_block > start ? ex_ee_block : start; - b = ex_ee_block + ex_ee_len -1 <EXT_MAX_BLOCK ? - ex_ee_block + ex_ee_len -1 :EXT_MAX_BLOCK ; + b = ex_ee_block + ex_ee_len -1 <EXT_MAX_BLOCKS ? + ex_ee_block + ex_ee_len -1 :EXT_MAX_BLOCKS ;ext_debug (" border %u:%u\n" , a, b);@@ -3783,15 +3783,14 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, flags |=FIEMAP_EXTENT_UNWRITTEN ;/* -* If this extent reaches EXT_MAX_BLOCK, it must be last. +* If this extent reaches EXT_MAX_BLOCKS, it must be last. * -* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK, +* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCKS, * this also indicates no more allocated blocks. * -* XXX this might miss a single-block extent at EXT_MAX_BLOCK */ -if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCK || - newex->ec_block + newex->ec_len -1 ==EXT_MAX_BLOCK ) { +if (ext4_ext_next_allocated_block (path) ==EXT_MAX_BLOCKS || + newex->ec_block + newex->ec_len ==EXT_MAX_BLOCKS ) {loff_t size =i_size_read (inode);loff_t bs =EXT4_BLOCK_SIZE (inode->i_sb);@@ -3871,8 +3870,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, start_blk = start >> inode->i_sb->s_blocksize_bits; last_blk = (start + len -1 ) >> inode->i_sb->s_blocksize_bits; -if (last_blk >=EXT_MAX_BLOCK ) - last_blk =EXT_MAX_BLOCK -1 ; +if (last_blk >=EXT_MAX_BLOCKS ) + last_blk =EXT_MAX_BLOCKS -1 ; len_blks = ((ext4_lblk_t ) last_blk) - start_blk +1 ;/* fs/ext4/move_extent.c +5
-5@@ -1001,12 +1001,12 @@ mext_check_arguments(struct inode *orig_inode,return -EINVAL ; } -if ((orig_start >EXT_MAX_BLOCK ) || - (donor_start >EXT_MAX_BLOCK ) || - (*len >EXT_MAX_BLOCK ) || - (orig_start + *len >EXT_MAX_BLOCK )) { +if ((orig_start >=EXT_MAX_BLOCKS ) || + (donor_start >=EXT_MAX_BLOCKS ) || + (*len >EXT_MAX_BLOCKS ) || + (orig_start + *len >=EXT_MAX_BLOCKS )) {ext4_debug ("ext4 move extent: Can't handle over [%u] blocks " -"[ino:orig %lu, donor %lu]\n" ,EXT_MAX_BLOCK , +"[ino:orig %lu, donor %lu]\n" ,EXT_MAX_BLOCKS , orig_inode->i_ino, donor_inode->i_ino);return -EINVAL ; }fs/ext4/super.c +12
-3@@ -1975,6 +1975,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,* in the vfs. ext4 inode has 48 bits of i_block in fsblock units, * so that won't be a limiting factor. * +* However there is other limiting factor. We do store extents in the form +* of starting block and length, hence the resulting length of the extent +* covering maximum file size must fit into on-disk format containers as +* well. Given that length is always by 1 unit bigger than max unit (because +* we count 0 as well) we have to lower the s_maxbytes by one fs block. +* * Note, this does *not* consider any metadata overhead for vfs i_blocks. */ static loff_t ext4_max_size (int blkbits,int has_huge_files)@@ -1996,10 +2002,13 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) upper_limit <<= blkbits; } -/* 32-bit extent-start container, ee_block */ - res =1LL <<32 ; +/* +* 32-bit extent-start container, ee_block. We lower the maxbytes +* by one fs block, so ee_len can cover the extent of maximum file +* size +*/ + res = (1LL <<32 ) -1 ; res <<= blkbits; - res -=1 ;/* Sanity check against vm- & vfs- imposed limits */ if (res > upper_limit)
PATCH 123/184 ext4: fix memory leak in ext4_xattr_set_acl()s
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
error path
From: Eugene Shatokhin <[email protected]>
commit 24ec19b0ae83a385ad9c55520716da671274b96c upstream.
In ext4_xattr_set_acl(), if ext4_journal_start() returns an error, posix_acl_release() will not be called for 'acl' which may result in a memory leak.
This patch fixes that.
--- fs/ext4/acl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/ext4/acl.c +4 -2
@@ -454,8 +454,10 @@ ext4_xattr_set_acl(struct inode *inode, int type, const void *value, retry: handle =ext4_journal_start (inode,EXT4_DATA_TRANS_BLOCKS (inode->i_sb)); -if (IS_ERR (handle)) -return PTR_ERR (handle); +if (IS_ERR (handle)) { + error =PTR_ERR (handle); + goto release_and_out; + } error =ext4_set_acl (handle, inode, type, acl);ext4_journal_stop (handle);if (error == -ENOSPC &&ext4_should_retry_alloc (inode->i_sb, &retries))
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 124/184 ext4: online defrag is not supported for journaled
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
files
From: Dmitry Monakhov <[email protected]>
commit f066055a3449f0e5b0ae4f3ceab4445bead47638 upstream.
Proper block swap for inodes with full journaling enabled is truly non obvious task. In order to be on a safe side let's explicitly disable it for now.
--- fs/ext4/move_extent.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/ext4/move_extent.c +6 -1
@@ -1208,7 +1208,12 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, orig_inode->i_ino, donor_inode->i_ino);return -EINVAL ; } - +/* TODO: This is non obvious task to swap blocks for inodes with full +jornaling enabled */ +if (ext4_should_journal_data (orig_inode) || +ext4_should_journal_data (donor_inode)) { +return -EINVAL ; + }/* Protect orig and donor inodes against a truncate */ ret1 =mext_inode_double_lock (orig_inode, donor_inode);if (ret1 <0 )
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 125/184 ext4: always set i_op in ext4_mknod()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Schubert <[email protected]>
commit 6a08f447facb4f9e29fcc30fb68060bb5a0d21c2 upstream.
ext4_special_inode_operations have their own ifdef CONFIG_EXT4_FS_XATTR to mask those methods. And ext4_iget also always sets it, so there is an inconsistency.
--- fs/ext4/namei.c | 2 -- 1 file changed, 2 deletions(-)
fs/ext4/namei.c +0 -2
@@ -1828,9 +1828,7 @@ retry: err =PTR_ERR (inode);if (!IS_ERR (inode)) {init_special_inode (inode, inode->i_mode, rdev); -#ifdef CONFIG_EXT4_FS_XATTR inode->i_op = &ext4_special_inode_operations; -#endif err =ext4_add_nondir (handle, dentry, inode); }ext4_journal_stop (handle);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 126/184 ext4: fix fdatasync() for files with only i_size
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
changes
From: Jan Kara <[email protected]>
commit b71fc079b5d8f42b2a52743c8d2f1d35d655b1c5 upstream.
Code tracking when transaction needs to be committed on fdatasync(2) forgets to handle a situation when only inode's i_size is changed. Thus in such situations fdatasync(2) doesn't force transaction with new i_size to disk and that can result in wrong i_size after a crash.
Fix the issue by updating inode's i_datasync_tid whenever its size is updated.
--- fs/ext4/inode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/ext4/inode.c +6 -2
@@ -5121,6 +5121,7 @@ static int ext4_do_update_inode(handle_t *handle,struct ext4_inode_info *ei =EXT4_I (inode);struct buffer_head *bh = iloc->bh;int err =0 , rc, block; +int need_datasync =0 ;/* For fields not not tracking in the in-memory inode, * initialise them to zero for new inodes. */
@@ -5169,7 +5170,10 @@ static int ext4_do_update_inode(handle_t *handle, raw_inode->i_file_acl_high =cpu_to_le16 (ei->i_file_acl >>32 ); raw_inode->i_file_acl_lo =cpu_to_le32 (ei->i_file_acl); -ext4_isize_set (raw_inode, ei->i_disksize); +if (ei->i_disksize !=ext4_isize (raw_inode)) { +ext4_isize_set (raw_inode, ei->i_disksize); + need_datasync =1 ; + } if (ei->i_disksize > 0x7fffffffULL) { struct super_block *sb = inode->i_sb; if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
@@ -5222,7 +5226,7 @@ static int ext4_do_update_inode(handle_t *handle, err = rc;ext4_clear_inode_state (inode,EXT4_STATE_NEW ); -ext4_update_inode_fsync_trans (handle, inode,0 ); +ext4_update_inode_fsync_trans (handle, inode, need_datasync); out_brelse:brelse (bh);ext4_std_error (inode->i_sb, err);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 127/184 ext4: lock i_mutex when truncating orphan inodes
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
commit 721e3eba21e43532e438652dd8f1fcdfce3187e7 upstream.
Commit c278531d39 added a warning when ext4_flush_unwritten_io() is called without i_mutex being taken. It had previously not been taken during orphan cleanup since races weren't possible at that point in the mount process, but as a result of this c278531d39, we will now see a kernel WARN_ON in this case. Take the i_mutex in ext4_orphan_cleanup() to suppress this warning.
--- fs/ext4/super.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ext4/super.c +2 -0
@@ -1937,7 +1937,9 @@ static void ext4_orphan_cleanup(struct super_block *sb, __func__, inode->i_ino, inode->i_size);jbd_debug (2 ,"truncating inode %lu to %lld bytes\n" , inode->i_ino, inode->i_size); +mutex_lock (&inode->i_mutex);ext4_truncate (inode); +mutex_unlock (&inode->i_mutex); nr_truncates++; }else { ext4_msg(sb, KERN_DEBUG,
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 128/184 ext4: fix race in ext4_mb_add_n_trim()
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Niu Yawei <[email protected]>
commit f1167009711032b0d747ec89a632a626c901a1ad upstream.
In ext4_mb_add_n_trim(), lg_prealloc_lock should be taken when changing the lg_prealloc_list.
--- fs/ext4/mballoc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/ext4/mballoc.c +3 -3
@@ -4163,7 +4163,7 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)/* The max size of hash table is PREALLOC_TB_SIZE */ order =PREALLOC_TB_SIZE -1 ;/* Add the prealloc space to lg */ -rcu_read_lock (); +spin_lock (&lg->lg_prealloc_lock);list_for_each_entry_rcu (tmp_pa, &lg->lg_prealloc_list[order], pa_inode_list) {spin_lock (&tmp_pa->pa_lock);
@@ -4187,12 +4187,12 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)if (!added)list_add_tail_rcu (&pa->pa_inode_list, &lg->lg_prealloc_list[order]); -rcu_read_unlock (); +spin_unlock (&lg->lg_prealloc_lock);/* Now trim the list to be not more than 8 elements */ if (lg_prealloc_count >8 ) {ext4_mb_discard_lg_preallocations (sb, lg, - order, lg_prealloc_count); + order, lg_prealloc_count);return ; }return ;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 129/184 ext4: limit group search loop for non-extent files
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
From: Lachlan McIlroy <[email protected]>
commit e6155736ad76b2070652745f9e54cdea3f0d8567 upstream.
In the case where we are allocating for a non-extent file, we must limit the groups we allocate from to those below 2^32 blocks, and ext4_mb_regular_allocator() attempts to do this initially by putting a cap on ngroups for the subsequent search loop.
However, the initial target group comes in from the allocation context (ac), and it may already be beyond the artificially limited ngroups. In this case, the limit
if (group == ngroups) group = 0;
at the top of the loop is never true, and the loop will run away.
Catch this case inside the loop and reset the search to start at group 0.
[[email protected]: add commit msg & comments]
--- fs/ext4/mballoc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/ext4/mballoc.c +5 -1
@@ -2070,7 +2070,11 @@ repeat: group = ac->ac_g_ex.fe_group;for (i =0 ; i < ngroups; group++, i++) { -if (group == ngroups) +/* +* Artificially restricted ngroups for non-extent +* files makes group > ngroups possible on first loop. +*/ +if (group >= ngroups) group =0 ;/* This now checks without needing the buddy page */
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
PATCH 130/184 CVE-2012-4508 kernel: ext4: AIO vs fallocate stale
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
data exposure
From: Jamie Iles <[email protected]>
CVE-2012-4508 kernel: ext4: AIO vs fallocate stale data exposure [dannf: backported to Debian's 2.6.32]
--- fs/ext4/extents.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-)
fs/ext4/extents.c +66 -1
@@ -62,6 +62,7 @@ ext4_fsblk_t ext_pblock(struct ext4_extent *ex)* idx_pblock: * combine low and high parts of a leaf physical block number into ext4_fsblk_t */ +#define EXT4_EXT_DATA_VALID 0x8/* extent contains valid data */ ext4_fsblk_t idx_pblock (struct ext4_extent_idx *ix) {ext4_fsblk_t block;
@@ -2933,6 +2934,30 @@ static int ext4_split_unwritten_extents(handle_t *handle,ext4_ext_mark_uninitialized (ex3); err =ext4_ext_insert_extent (handle, inode, path, ex3, flags);if (err == -ENOSPC && may_zeroout) { +/* +* This is different from the upstream, because we +* need only a flag to say that the extent contains +* the actual data. +* +* If the extent contains valid data, which can only +* happen if AIO races with fallocate, then we got +* here from ext4_convert_unwritten_extents_dio(). +* So we have to be careful not to zeroout valid data +* in the extent. +* +* To avoid it, we only zeroout the ex3 and extend the +* extent which is going to become initialized to cover +* ex3 as well. and continue as we would if only +* split in two was required. +*/ +if (flags &EXT4_EXT_DATA_VALID ) { + err =ext4_ext_zeroout (inode, ex3); +if (err) + goto fix_extent_len; + max_blocks = allocated; + ex2->ee_len =cpu_to_le16 (max_blocks); + goto skip; + } err =ext4_ext_zeroout (inode, &orig_ex);if (err) goto fix_extent_len;
@@ -2978,6 +3003,7 @@ static int ext4_split_unwritten_extents(handle_t *handle, allocated = max_blocks; } +skip:/* * If there was a change of depth as part of the * insertion of ex3 above, we need to update the length
@@ -3030,11 +3056,16 @@ fix_extent_len:ext4_ext_dirty (handle, inode, path + depth);return err; } +static int ext4_convert_unwritten_extents_dio (handle_t *handle,struct inode *inode, +ext4_lblk_t iblock, +unsigned int max_blocks,struct ext4_ext_path *path) {struct ext4_extent *ex; +ext4_lblk_t ee_block; +unsigned int ee_len;struct ext4_extent_header *eh;int depth;int err =0 ;
@@ -3043,6 +3074,30 @@ static int ext4_convert_unwritten_extents_dio(handle_t *handle, depth =ext_depth (inode); eh = path[depth].p_hdr; ex = path[depth].p_ext; + ee_block =le32_to_cpu (ex->ee_block); + ee_len =ext4_ext_get_actual_len (ex); + +ext_debug ("ext4_convert_unwritten_extents_endio: inode %lu, logical" +"block %llu, max_blocks %u\n" , inode->i_ino, + (unsigned long long )ee_block, ee_len); + +/* If extent is larger than requested then split is required */ + +if (ee_block != iblock || ee_len > max_blocks) { + err =ext4_split_unwritten_extents (handle, inode, path, + iblock, max_blocks, +EXT4_EXT_DATA_VALID ); +if (err <0 ) + goto out; +ext4_ext_drop_refs (path); + path =ext4_ext_find_extent (inode, iblock, path); +if (IS_ERR (path)) { + err =PTR_ERR (path); + goto out; + } + depth =ext_depth (inode); + ex = path[depth].p_ext; + } err =ext4_ext_get_access (handle, inode, path + depth);if (err)
@@ -3129,7 +3184,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,/* async DIO end_io complete, convert the filled extent to written */ if (flags ==EXT4_GET_BLOCKS_DIO_CONVERT_EXT ) { ret =ext4_convert_unwritten_extents_dio (handle, inode, - path); + iblock, max_blocks, + path);if (ret >=0 )ext4_update_inode_fsync_trans (handle, inode,1 ); goto out2;
@@ -3498,6 +3554,12 @@ void ext4_ext_truncate(struct inode *inode)int err =0 ;/* +* finish any pending end_io work so we won't run the risk of +* converting any truncated blocks to initialized later +*/ +flush_aio_dio_completed_IO (inode); + +/* * probably first extent we're gonna free will be last in block */ err =ext4_writepage_trans_blocks (inode);
@@ -3630,6 +3692,9 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)mutex_unlock (&inode->i_mutex);return ret; } + +/* Prevent race condition between unwritten */ +flush_aio_dio_completed_IO (inode); retry:while (ret >=0 && ret < max_blocks) { block = block + ret;
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 130/184] CVE-2012-4508 kernel: ext4: AIO vs fallocate stale
Quoted 9 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
data exposureFrom: Jamie Iles <[email protected]>
CVE-2012-4508 kernel: ext4: AIO vs fallocate stale data exposure [dannf: backported to Debian's 2.6.32]
Well, this has an interesting ancestry. The original upstream commits were c278531d39f3158bfee93dc67da0b77e09776de2, 60d4616f3dc63371b3dc367e5e88fd4b4f037f65 and (most importantly) dee1f973ca341c266229faa5a1a5bb268bed3531 by Dmitry Monakhov <[email protected]>. They were backported into the RHEL 6 kernel by Lukas Czerner, according to its changelog. Dann got this version from Oracle's redpatch repository, where, if I understand rightly, Jamie Iles attempted to regenerate Lukas's patch(es).
Would any of the above named be prepared to put their Signed-off-by to this?
Ben.
Quoted 137 lines
Signed-off-by Willy Tarreau <[email protected]>--- fs/ext4/extents.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-)fs/ext4/extents.c +66
-1@@ -62,6 +62,7 @@ ext4_fsblk_t ext_pblock(struct ext4_extent *ex)* idx_pblock: * combine low and high parts of a leaf physical block number into ext4_fsblk_t */ +#define EXT4_EXT_DATA_VALID 0x8/* extent contains valid data */ ext4_fsblk_t idx_pblock (struct ext4_extent_idx *ix) {ext4_fsblk_t block;@@ -2933,6 +2934,30 @@ static int ext4_split_unwritten_extents(handle_t *handle,ext4_ext_mark_uninitialized (ex3); err =ext4_ext_insert_extent (handle, inode, path, ex3, flags);if (err == -ENOSPC && may_zeroout) { +/* +* This is different from the upstream, because we +* need only a flag to say that the extent contains +* the actual data. +* +* If the extent contains valid data, which can only +* happen if AIO races with fallocate, then we got +* here from ext4_convert_unwritten_extents_dio(). +* So we have to be careful not to zeroout valid data +* in the extent. +* +* To avoid it, we only zeroout the ex3 and extend the +* extent which is going to become initialized to cover +* ex3 as well. and continue as we would if only +* split in two was required. +*/ +if (flags &EXT4_EXT_DATA_VALID ) { + err =ext4_ext_zeroout (inode, ex3); +if (err) + goto fix_extent_len; + max_blocks = allocated; + ex2->ee_len =cpu_to_le16 (max_blocks); + goto skip; + } err =ext4_ext_zeroout (inode, &orig_ex);if (err) goto fix_extent_len;@@ -2978,6 +3003,7 @@ static int ext4_split_unwritten_extents(handle_t *handle, allocated = max_blocks; } +skip:/* * If there was a change of depth as part of the * insertion of ex3 above, we need to update the length @@ -3030,11 +3056,16 @@ fix_extent_len:ext4_ext_dirty (handle, inode, path + depth);return err; } +static int ext4_convert_unwritten_extents_dio (handle_t *handle,struct inode *inode, +ext4_lblk_t iblock, +unsigned int max_blocks,struct ext4_ext_path *path) {struct ext4_extent *ex; +ext4_lblk_t ee_block; +unsigned int ee_len;struct ext4_extent_header *eh;int depth;int err =0 ;@@ -3043,6 +3074,30 @@ static int ext4_convert_unwritten_extents_dio(handle_t *handle, depth =ext_depth (inode); eh = path[depth].p_hdr; ex = path[depth].p_ext; + ee_block =le32_to_cpu (ex->ee_block); + ee_len =ext4_ext_get_actual_len (ex); + +ext_debug ("ext4_convert_unwritten_extents_endio: inode %lu, logical" +"block %llu, max_blocks %u\n" , inode->i_ino, + (unsigned long long )ee_block, ee_len); + +/* If extent is larger than requested then split is required */ + +if (ee_block != iblock || ee_len > max_blocks) { + err =ext4_split_unwritten_extents (handle, inode, path, + iblock, max_blocks, +EXT4_EXT_DATA_VALID ); +if (err <0 ) + goto out; +ext4_ext_drop_refs (path); + path =ext4_ext_find_extent (inode, iblock, path); +if (IS_ERR (path)) { + err =PTR_ERR (path); + goto out; + } + depth =ext_depth (inode); + ex = path[depth].p_ext; + } err =ext4_ext_get_access (handle, inode, path + depth);if (err)@@ -3129,7 +3184,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,/* async DIO end_io complete, convert the filled extent to written */ if (flags ==EXT4_GET_BLOCKS_DIO_CONVERT_EXT ) { ret =ext4_convert_unwritten_extents_dio (handle, inode, - path); + iblock, max_blocks, + path);if (ret >=0 )ext4_update_inode_fsync_trans (handle, inode,1 ); goto out2;@@ -3498,6 +3554,12 @@ void ext4_ext_truncate(struct inode *inode)int err =0 ;/* +* finish any pending end_io work so we won't run the risk of +* converting any truncated blocks to initialized later +*/ +flush_aio_dio_completed_IO (inode); + +/* * probably first extent we're gonna free will be last in block */ err =ext4_writepage_trans_blocks (inode);@@ -3630,6 +3692,9 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)mutex_unlock (&inode->i_mutex);return ret; } + +/* Prevent race condition between unwritten */ +flush_aio_dio_completed_IO (inode); retry:while (ret >=0 && ret < max_blocks) { block = block + ret;
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 130/184] CVE-2012-4508 kernel: ext4: AIO vs fallocate stale
Quoted 20 lines · Ben Hutchings
Quoted 9 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
data exposureFrom: Jamie Iles <[email protected]>
CVE-2012-4508 kernel: ext4: AIO vs fallocate stale data exposure [dannf: backported to Debian's 2.6.32]
Well, this has an interesting ancestry. The original upstream commits were
c278531d39f3158bfee93dc67da0b77e09776de2,60d4616f3dc63371b3dc367e5e88fd4b4f037f65and (most importantly)dee1f973ca341c266229faa5a1a5bb268bed3531by Dmitry Monakhov <[email protected]>. They were backported into the RHEL 6 kernel by Lukas Czerner, according to its changelog. Dann got this version from Oracle's redpatch repository, where, if I understand rightly, Jamie Iles attempted to regenerate Lukas's patch(es).
Quoted 2 lines
Would any of the above named be prepared to put their Signed-off-by to this?
Interesting archaeological digging. In the mean time I'm adding this useful information to the message commit, it never hurts and can be useful in the future.
Guys, I'm planning on releasing this late this evening on European time, so it's not too late yet to add your s-o-b.
Thanks,
Willy
Re: [ 130/184] CVE-2012-4508 kernel: ext4: AIO vs fallocate stale
In reply to Ben HutchingsHi Ben, Willy,
Quoted 11 lines · Ben Hutchings
Quoted 9 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
data exposureFrom: Jamie Iles <[email protected]>
CVE-2012-4508 kernel: ext4: AIO vs fallocate stale data exposure [dannf: backported to Debian's 2.6.32]
Quoted 8 lines
Well, this has an interesting ancestry. The original upstream commits were
c278531d39f3158bfee93dc67da0b77e09776de2,60d4616f3dc63371b3dc367e5e88fd4b4f037f65and (most importantly)dee1f973ca341c266229faa5a1a5bb268bed3531by Dmitry Monakhov <[email protected]>. They were backported into the RHEL 6 kernel by Lukas Czerner, according to its changelog. Dann got this version from Oracle's redpatch repository, where, if I understand rightly, Jamie Iles attempted to regenerate Lukas's patch(es).
That sounds correct to me - the patch is the result of splitting the large ext4 patch that RHEL did from 6.3 -> 6.4. The Virtuozzo/OpenVZ folks came up with the same patch (independently I think) too.
Quoted 2 lines
Would any of the above named be prepared to put their Signed-off-by to this?
Sure, I'd be happy to add my s-o-b.
Thanks,
Jamie
Re: [ 130/184] CVE-2012-4508 kernel: ext4: AIO vs fallocate stale
Hi James,
Quoted 3 lines · Jamie Iles
Sure, I'd be happy to add my s-o-b.
Signed-off-by Jamie Iles <[email protected]>
Added, thanks.
willy
PATCH 131/184 ext4: make orphan functions be no-op in no-journal
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
mode
From: Anatol Pomozov <[email protected]>
Instead of checking whether the handle is valid, we check if journal is enabled. This avoids taking the s_orphan_lock mutex in all cases when there is no journal in use, including the error paths where ext4_orphan_del() is called with a handle set to NULL.
--- fs/ext4/namei.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
fs/ext4/namei.c +3 -4
@@ -2001,7 +2001,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)struct ext4_iloc iloc;int err =0 , rc; -if (!ext4_handle_valid (handle)) +if (!EXT4_SB (sb)->s_journal)return 0 ;mutex_lock (&EXT4_SB (sb)->s_orphan_lock);
@@ -2082,8 +2082,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)struct ext4_iloc iloc;int err =0 ; -/* ext4_handle_valid() assumes a valid handle_t pointer */ -if (handle && !ext4_handle_valid (handle)) +if (!EXT4_SB (inode->i_sb)->s_journal)return 0 ;mutex_lock (&EXT4_SB (inode->i_sb)->s_orphan_lock);
@@ -2102,7 +2101,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)* transaction handle with which to update the orphan list on * disk, but we still need to remove the inode from the linked * list in memory. */ -if (sbi->s_journal && !handle) +if (!handle) goto out; err =ext4_reserve_inode_write (handle, inode, &iloc);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 131/184] ext4: make orphan functions be no-op in no-journal
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
modeFrom: Anatol Pomozov <[email protected]>
commit c9b92530a723ac5ef8e352885a1862b18f31b2f5 upstream.
Quoted 44 lines
Instead of checking whether the handle is valid, we check if journal is enabled. This avoids taking the
s_orphan_lockmutex in all cases when there is no journal in use, including the error paths whereext4_orphan_del()is called with a handle set to NULL.Signed-off-by Anatol Pomozov <[email protected]>Signed-off-by "Theodore Ts'o" <[email protected]>Signed-off-by Willy Tarreau <[email protected]>--- fs/ext4/namei.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)fs/ext4/namei.c +3
-4@@ -2001,7 +2001,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)struct ext4_iloc iloc;int err =0 , rc; -if (!ext4_handle_valid (handle)) +if (!EXT4_SB (sb)->s_journal)return 0 ;mutex_lock (&EXT4_SB (sb)->s_orphan_lock);@@ -2082,8 +2082,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)struct ext4_iloc iloc;int err =0 ; -/* ext4_handle_valid() assumes a valid handle_t pointer */ -if (handle && !ext4_handle_valid (handle)) +if (!EXT4_SB (inode->i_sb)->s_journal)return 0 ;mutex_lock (&EXT4_SB (inode->i_sb)->s_orphan_lock);@@ -2102,7 +2101,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)* transaction handle with which to update the orphan list on * disk, but we still need to remove the inode from the linked * list in memory. */ -if (sbi->s_journal && !handle) +if (!handle) goto out; err =ext4_reserve_inode_write (handle, inode, &iloc);
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 131/184] ext4: make orphan functions be no-op in no-journal
Quoted 9 lines · Ben Hutchings
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
modeFrom: Anatol Pomozov <[email protected]>
commit
c9b92530a723ac5ef8e352885a1862b18f31b2f5upstream.
added, thanks.
Willy
PATCH 132/184 ext4: avoid hang when mounting non-journal
In reply to a message not in the archive2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
filesystems with orphan list
From: Theodore Ts'o <[email protected]>
When trying to mount a file system which does not contain a journal, but which does have a orphan list containing an inode which needs to be truncated, the mount call with hang forever in ext4_orphan_cleanup() because ext4_orphan_del() will return immediately without removing the inode from the orphan list, leading to an uninterruptible loop in kernel code which will busy out one of the CPU's on the system.
This can be trivially reproduced by trying to mount the file system found in tests/f_orphan_extents_inode/image.gz from the e2fsprogs source tree. If a malicious user were to put this on a USB stick, and mount it on a Linux desktop which has automatic mounts enabled, this could be considered a potential denial of service attack. (Not a big deal in practice, but professional paranoids worry about such things, and have even been known to allocate CVE numbers for such problems.)
--- fs/ext4/namei.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/ext4/namei.c +2 -1
@@ -2082,7 +2082,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)struct ext4_iloc iloc;int err =0 ; -if (!EXT4_SB (inode->i_sb)->s_journal) +if ((!EXT4_SB (inode->i_sb)->s_journal) && + !(EXT4_SB (inode->i_sb)->s_mount_state &EXT4_ORPHAN_FS ))return 0 ;mutex_lock (&EXT4_SB (inode->i_sb)->s_orphan_lock);
Signature · 1 line
1.7.12.2.21.g234cd45.dirty
Re: [ 132/184] ext4: avoid hang when mounting non-journal
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
filesystems with orphan listFrom: Theodore Ts'o <[email protected]>
commit 0e9a9a1ad619e7e987815d20262d36a2f95717ca upstream.
Quoted 38 lines
When trying to mount a file system which does not contain a journal, but which does have a orphan list containing an inode which needs to be truncated, the mount call with hang forever in
ext4_orphan_cleanup()becauseext4_orphan_del()will return immediately without removing the inode from the orphan list, leading to an uninterruptible loop in kernel code which will busy out one of the CPU's on the system.This can be trivially reproduced by trying to mount the file system found in tests/f_orphan_extents_inode/image.gz from the e2fsprogs source tree. If a malicious user were to put this on a USB stick, and mount it on a Linux desktop which has automatic mounts enabled, this could be considered a potential denial of service attack. (Not a big deal in practice, but professional paranoids worry about such things, and have even been known to allocate CVE numbers for such problems.)
Signed-off-by "Theodore Ts'o" <[email protected]>Reviewed-by Zheng Liu <[email protected]>Signed-off-by Willy Tarreau <[email protected]>--- fs/ext4/namei.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)fs/ext4/namei.c +2
-1@@ -2082,7 +2082,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)struct ext4_iloc iloc;int err =0 ; -if (!EXT4_SB (inode->i_sb)->s_journal) +if ((!EXT4_SB (inode->i_sb)->s_journal) && + !(EXT4_SB (inode->i_sb)->s_mount_state &EXT4_ORPHAN_FS ))return 0 ;mutex_lock (&EXT4_SB (inode->i_sb)->s_orphan_lock);
Signature · 3 lines
Ben Hutchings
Theory and practice are closer in theory than in practice.
- John Levine, moderator of comp.compilersRe: [ 132/184] ext4: avoid hang when mounting non-journal
Quoted 9 lines · Ben Hutchings
Quoted 6 lines · Willy Tarreau
2.6.32-longterm review patch. If anyone has any objections, please let me know.
------------------
filesystems with orphan listFrom: Theodore Ts'o <[email protected]>
commit
0e9a9a1ad619e7e987815d20262d36a2f95717caupstream.
added, thanks Ben.
Willy