Skip to contentSkip to conversation

Revert "pcdp: use early_ioremap/early_iounmap to

PATCH In review Willy Tarreau 10 participants 240 messages Jun 4, 2013 – Nov 16, 2013 1 message not in the archive Page 1 of 2

Subsystems (89)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): 58df134a4b98edf5b0073e2e1e988fe6@local

#1 lore raw

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
index a330492..51e0e2d 100644
@@ -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
#2 lore raw

PATCH 2/184 Revert "block: improve queue_should_plug() by

In reply to a message not in the archive

2.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

(cherry picked from commit 79da0644a8e0838522828f106e4049639eea6baf)
Cc Thomas Bork <[email protected]>
---
 block/blk-core.c       | 11 ++---------
 include/linux/blkdev.h |  4 +---
 2 files changed, 3 insertions(+), 12 deletions(-)
block/blk-core.c +2 -9
index cffd737..00ac586 100644
@@ -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
index 5eb6cb0..ec9c10b 100644
@@ -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
#3 lore raw

PATCH 3/184 2.6.32.y: timekeeping: Fix nohz issue with commit

In reply to a message not in the archive

2.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
index 3d35af3..f65a0fb 100644
@@ -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
#4 lore raw

PATCH 4/184 clockevents: Dont allow dummy broadcast timers

In reply to a message not in the archive

2.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.

Cc linux-arm-kernel at lists.infradead.org
Cc Jon Medhurst (Tixy) <[email protected]>
---
 kernel/time/tick-broadcast.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/time/tick-broadcast.c +2 -1
index 57b953f..67fe3d9 100644
@@ -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
#5 lore raw

PATCH 5/184 posix-cpu-timers: Fix nanosleep task_struct leak

In reply to a message not in the archive

2.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
index 5c9dc22..ea83f5d 100644
@@ -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
#6 lore raw

PATCH 6/184 timer: Dont reinitialize the cpu base lock during

In reply to a message not in the archive

2.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
index cb3c1f1..8123679 100644
@@ -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
#7 lore raw

PATCH 7/184 tick: Cleanup NOHZ per cpu data on cpu down

In reply to a message not in the archive

2.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
index b63cfeb..9f0fd18 100644
@@ -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
#8 lore raw

PATCH 8/184 kbuild: Fix gcc -x syntax

In reply to a message not in the archive

2.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
index 77f5021..57ff855 100644
@@ -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
index eecd2a9..700dc14 100644
@@ -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
index 92b62a8..5405ff17 100644
@@ -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
index debecb5..7f2126d 100644
@@ -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
index 29493dc..12dbd0b 100644
@@ -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
index afaec61..973e8c1 100644
@@ -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
index fa59cbf..854d9c7 100755
@@ -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
index fcef0f5..4bab9e2 100644
@@ -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
#9 lore raw

PATCH 9/184 gen_init_cpio: avoid stack overflow when expanding

In reply to a message not in the archive

2.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 terminated

This 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
index 83b3dde..13cd679 100644
@@ -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
#10 lore raw

PATCH 10/184 usermodehelper: introduce umh_complete(sub_info)

In reply to a message not in the archive

2.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).

Cc Tetsuo Handa <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[email protected]>
[dannf: Adjusted to apply to Debian's 2.6.32]
---
 kernel/kmod.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/kmod.c +7 -2
index a061472..2a27d17 100644
@@ -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
#11 lore raw

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 b3449922502f5a161ee2b5022a33aec8472fbf18 upstream

Preparation. Add the new trivial helper, umh_complete(). Currently it simply does complete(sub_info->complete).

Quoted 8 lines
Cc Tetsuo Handa <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[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
---
 kernel/kmod.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/kmod.c +7 -2
index a061472..2a27d17 100644
@@ -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.compilers
#12 lore raw

Re: [ 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 b3449922502f5a161ee2b5022a33aec8472fbf18 upstream

Preparation. Add the new trivial helper, umh_complete(). Currently it simply does complete(sub_info->complete).

Quoted 8 lines
Cc Tetsuo Handa <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[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

#13 lore raw

PATCH 11/184 usermodehelper: implement UMH_KILLABLE

In reply to a message not in the archive

2.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.

Cc Tetsuo Handa <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[email protected]>
[dannf: backported to Debian's 2.6.32]
---
 include/linux/kmod.h |  2 ++
 kernel/kmod.c        | 27 +++++++++++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)
include/linux/kmod.h +2 -0
index 0546fe7..93e732e 100644
@@ -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
index 2a27d17..2c2a020 100644
@@ -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
#14 lore raw

PATCH 12/184 usermodehelper: ____call_usermodehelper() doesnt

In reply to a message not in the archive

2.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.

Cc Tetsuo Handa <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[email protected]>
[dannf: adjusted to apply to Debian's 2.6.32]
---
 kernel/kmod.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/kmod.c +1 -1
index 2c2a020..f12d883 100644
@@ -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
#15 lore raw

PATCH 13/184 kmod: introduce call_modprobe() helper

In reply to a message not in the archive

2.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().

Cc Tetsuo Handa <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[email protected]>
[dannf: backported to Debian's 2.6.32]
---
 kernel/kmod.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)
kernel/kmod.c +14 -7
index f12d883..1088a8f 100644
@@ -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
#16 lore raw

PATCH 14/184 kmod: make __request_module() killable

In reply to a message not in the archive

2.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.

Cc Rusty Russell <[email protected]>
Cc Tejun Heo <[email protected]>
Cc David Rientjes <[email protected]>
[dannf, bwh: backported to Debian's 2.6.32]
---
 kernel/kmod.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)
kernel/kmod.c +34 -2
index 1088a8f..8ecc509 100644
@@ -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
#17 lore raw

PATCH 15/184 exec: do not leave bprm->interp on stack

In reply to a message not in the archive

2.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/

Cc halfdog <[email protected]>
Cc Alexander Viro <[email protected]>
[dannf: backported to Debian's 2.6.32]
---
 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
index 42b60b0..fb93997 100644
@@ -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
index 0834350..356568c 100644
@@ -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
index 86fafc6..f9f1b11 100644
@@ -1108,9 +1108,24 @@ void free_bprm(struct linux_binprm *bprm)
 		mutex_unlock(&current->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
index a3d802e..d06c3a4 100644
@@ -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
#18 lore raw

PATCH 16/184 exec: use -ELOOP for max recursion depth

In reply to a message not in the archive

2.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.

Cc halfdog <[email protected]>
Cc Alexander Viro <[email protected]>
[dannf: backported to Debian's 2.6.32]
---
 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
index 32fb00b..416dcae 100644
@@ -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
index fb93997..258c5ca 100644
@@ -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
index 356568c..4fe6b8a 100644
@@ -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
index f9f1b11..feb2435 100644
@@ -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
index d06c3a4..9ffffec 100644
@@ -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
#19 lore raw

PATCH 17/184 signal: always clear sa_restorer on execve

In reply to a message not in the archive

2.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
  ...
[[email protected]: use SA_RESTORER for backportability]
Cc Emese Revfy <[email protected]>
Cc PaX Team <[email protected]>
Cc Al Viro <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc "Eric W. Biederman" <[email protected]>
Cc Serge Hallyn <[email protected]>
Cc Julien Tinnes <[email protected]>
---
 kernel/signal.c | 3 +++
 1 file changed, 3 insertions(+)
kernel/signal.c +3 -0
index 2494827..df993fd 100644
@@ -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
#20 lore raw

PATCH 18/184 ptrace: ptrace_resume() shouldnt wake up

In reply to a message not in the archive

2.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.

(cherry picked from commit 0666fb51b1483f27506e212cc7f7b2645b5c7acc)
---
 kernel/ptrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/ptrace.c +1 -1
index 05625f6..d8184b5 100644
@@ -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
#21 lore raw

PATCH 19/184 ptrace: introduce signal_wake_up_state() and

In reply to a message not in the archive

2.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.

(backported from commit 910ffdb18a6408e14febbb6e4b6840fd2c928c82)

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
index 71849bf..73c3b9b 100644
@@ -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
index d8184b5..37850f9 100644
@@ -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
index df993fd..b40f4f0 100644
@@ -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
#22 lore raw

PATCH 20/184 ptrace: ensure arch_ptrace/ptrace_request can never

In reply to a message not in the archive

2.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().

(backported from commit 9899d11f654474d2d54ea52ceaa2a1f4db3abd68)

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
index 37850f9..d0036f0 100644
@@ -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
index b40f4f0..1929014 100644
@@ -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
Acked-by Colin King Acked-by Stefan Bader Acked-by on v1 20/184
#23 lore raw

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 SIGKILL

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.

http://kernel.ubuntu.com/git?p=ubuntu/ubuntu-lucid.git;a=commit;h=d06bbd59e5c7a0e0525af764a897028d6d352c36

Cheers,

Signature · 1 line
Luis
Quoted 1 line

From d06bbd59e5c7a0e0525af764a897028d6d352c36 Mon 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 d6a1da349c76ac2ebe4774d1da9fb7e660df01d3 Mon 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
index d0036f0..d9c8c47 100644
@@ -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
#24 lore raw

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 SIGKILL

From: 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.

http://kernel.ubuntu.com/git?p=ubuntu/ubuntu-lucid.git;a=commit;h=d06bbd59e5c7a0e0525af764a897028d6d352c36

Thanks for letting me know, Luis. Queuing it now.

Willy

maintainer
#25 lore raw

Re: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never

In reply to Luis Henriques
Quoted 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.

maintainer
#26 lore raw

Re: [ 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 prevent wakeup(), 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_s
 		sigismember(&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, i
 		read_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;
 
#27 lore raw

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 prevent wakeup(), 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_s
 		sigismember(&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, i
 		read_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

maintainer
#28 lore raw

Re: [ 020/184] ptrace: ensure arch_ptrace/ptrace_request can never

In reply to 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 ?

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.

#29 lore raw

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
#30 lore raw

PATCH 21/184 kernel/signal.c: stop info leak via the tkill and

In reply to a message not in the archive

2.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
index 1929014..845de15 100644
@@ -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
#31 lore raw

PATCH 22/184 signal: Define __ARCH_HAS_SA_RESTORER so we know

In reply to a message not in the archive

2.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
index 43ba0fb..559ee24 100644
@@ -127,6 +127,7 @@ struct sigaction {
 	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/avr32/include/asm/signal.h +1 -0
index 8790dfc..e6952a0 100644
@@ -128,6 +128,7 @@ struct sigaction {
 	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/cris/include/asm/signal.h +1 -0
index ea6af9a..057fea2 100644
@@ -122,6 +122,7 @@ struct sigaction {
 	void (*sa_restorer)(void);
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/h8300/include/asm/signal.h +1 -0
index fd8b66e..8695707 100644
@@ -121,6 +121,7 @@ struct sigaction {
 	void (*sa_restorer)(void);
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/m32r/include/asm/signal.h +1 -0
index 9c1acb2..a96a9f4 100644
@@ -123,6 +123,7 @@ struct sigaction {
 	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/m68k/include/asm/signal.h +1 -0
index 5bc09c7..01a492a 100644
@@ -119,6 +119,7 @@ struct sigaction {
 	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/mn10300/include/asm/signal.h +1 -0
index 7e891fc..045d6a2 100644
@@ -131,6 +131,7 @@ struct sigaction {
 	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/powerpc/include/asm/signal.h +1 -0
index 3eb13be..ec63a0a 100644
@@ -109,6 +109,7 @@ struct sigaction {
 	__sigrestore_t sa_restorer;
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
arch/s390/include/asm/signal.h +1 -0
index cdf5cb2..c872626 100644
@@ -131,6 +131,7 @@ struct sigaction {
         void (*sa_restorer)(void);
         sigset_t sa_mask;               /* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
         struct sigaction sa;
arch/sparc/include/asm/signal.h +1 -0
index e49b828..4929431 100644
@@ -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
index 598457c..6cbc795 100644
@@ -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
index 633ba73..75edf8a 100644
@@ -133,6 +133,7 @@ struct sigaction {
 	void (*sa_restorer)(void);
 	sigset_t sa_mask;		/* mask last for extensibility */
 };
+#define __ARCH_HAS_SA_RESTORER
 
 struct k_sigaction {
 	struct sigaction sa;
include/asm-generic/signal.h +4 -0
index 555c0ae..743f7a5 100644
@@ -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
#32 lore raw

PATCH 23/184 kernel/signal.c: use __ARCH_HAS_SA_RESTORER instead

In reply to a message not in the archive

2.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.

Cc Emese Revfy <[email protected]>
Cc Emese Revfy <[email protected]>
Cc PaX Team <[email protected]>
Cc Al Viro <[email protected]>
Cc Oleg Nesterov <[email protected]>
Cc "Eric W. Biederman" <[email protected]>
Cc Serge Hallyn <[email protected]>
Cc Julien Tinnes <[email protected]>
Cc Ben Hutchings <[email protected]>
---
 kernel/signal.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/signal.c +1 -1
index 845de15..fb7e242 100644
@@ -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
#33 lore raw

PATCH 24/184 wake_up_process() should be never used to wakeup a

In reply to a message not in the archive

2.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.

(backported from commit 9067ac85d533651b98c2ff903182a20cbb361fcb)

Conflicts:
kernel/sched/core.c

---
 kernel/sched.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/sched.c +2 -1
index 0591df8..42bf6a6 100644
@@ -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
#34 lore raw

PATCH 25/184 coredump: prevent double-free on an error path in

In reply to a message not in the archive

2.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
index a64fde6..c564293 100644
@@ -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
#35 lore raw

PATCH 26/184 kernel/sys.c: call disable_nonboot_cpus() in

In reply to a message not in the archive

2.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
index e9512b1..5a381e6 100644
@@ -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
#36 lore raw

PATCH 27/184 ring-buffer: Fix race between integrity check and

In reply to a message not in the archive

2.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
index e749a05..6024960 100644
@@ -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
maintainer
#37 lore raw

Re: [ 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.

------------------
readers

From: Steven Rostedt <[email protected]>

commit 9366c1ba13fbc41bdb57702e75ca4382f209c82f upstream.

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.

---
 kernel/trace/ring_buffer.c | 2 ++
 1 file changed, 2 insertions(+)
kernel/trace/ring_buffer.c +2 -0
index e749a05..6024960 100644
@@ -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;
 
#38 lore raw

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.

------------------
readers

From: Steven Rostedt <[email protected]>

commit 9366c1ba13fbc41bdb57702e75ca4382f209c82f upstream.

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 if rb_set_head_page() fails

Ah yes indeed, thank you for bringing this up, Steve.

Willy

#39 lore raw

PATCH 28/184 genalloc: stop crashing the system when destroying a

In reply to a message not in the archive

2.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
index eed2bdb..c1fb257 100644
@@ -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
#40 lore raw

PATCH 29/184 kernel/resource.c: fix stack overflow in

In reply to a message not in the archive

2.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
index fb11a58..207915a 100644
@@ -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
#41 lore raw

PATCH 30/184 Driver core: treat unregistered bus_types as having

In reply to a message not in the archive

2.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 NULL

Joonsoo 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
index 63c143e..6f1ba10 100644
@@ -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
#42 lore raw

PATCH 31/184 cgroup: remove incorrect dget/dput() pair in

In reply to a message not in the archive

2.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
index 1fbcc74..04a9704 100644
@@ -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
#43 lore raw

PATCH 32/184 Fix a dead loop in async_synchronize_full()

In reply to a message not in the archive

2.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
index 27235f5..397a7c7 100644
@@ -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
#44 lore raw

PATCH 33/184 tracing: Dont call page_to_pfn() if page is NULL

In reply to a message not in the archive

2.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
index eaf46bd..a8dc32a 100644
@@ -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
#45 lore raw

PATCH 34/184 tracing: Fix double free when function profile init

In reply to a message not in the archive

2.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
index 4872937..c5f8ab9 100644
@@ -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
#46 lore raw

PATCH 35/184 hugetlb: fix resv_map leak in error path

In reply to a message not in the archive

2.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
index 20f9240..3d61035 100644
@@ -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
#47 lore raw

PATCH 36/184 mm: fix vma_resv_map() NULL pointer

In reply to a message not in the archive

2.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/0x1b

This 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 ]

Cc Mel Gorman <[email protected]>
Cc KOSAKI Motohiro <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Andrea Arcangeli <[email protected]>
Cc Andrew Morton <[email protected]>
[dannf: backported to Debian's 2.6.32]
---
 mm/hugetlb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
mm/hugetlb.c +2 -1
index 3d61035..b435d1f 100644
@@ -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
#48 lore raw

PATCH 37/184 mm: Fix PageHead when !CONFIG_PAGEFLAGS_EXTENDED

In reply to a message not in the archive

2.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
index 6b202b1..f451772 100644
@@ -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
#49 lore raw

PATCH 38/184 mm: bugfix: set current->reclaim_state to NULL while

In reply to a message not in the archive

2.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
index 4649929..738db2b 100644
@@ -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
#50 lore raw

PATCH 39/184 mm: fix invalidate_complete_page2() lock ordering

In reply to a message not in the archive

2.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
index 258bda7..b41d26d 100644
@@ -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
#51 lore raw

PATCH 40/184 mempolicy: fix a race in shared_policy_replace()

In reply to a message not in the archive

2.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
index 085c903..e68b592 100644
@@ -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
index a6563fb..df6602f 100644
@@ -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
#52 lore raw

PATCH 41/184 ALSA: hda - More ALC663 fixes and support of

In reply to a message not in the archive

2.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
index 6419095..06e7cc2 100644
@@ -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_setup
 
 static 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_setup
 
 static 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_setup
 
 static 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_setup
 
 static 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_setup
 
 static 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
#53 lore raw

PATCH 42/184 ALSA: hda - Add a pin-fix for FSC Amilo Pi1505

In reply to a message not in the archive

2.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

cfc9b06f0bef ALSA: hda - Add a pin-fix for FSC Amilo Pi1505

for 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.

(cherry picked from commit cfc9b06f0befe50ef02253f72b76946363549031)
Cc Jonathan Nieder <[email protected]>
---
 sound/pci/hda/patch_realtek.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
sound/pci/hda/patch_realtek.c +23 -0
index 06e7cc2..d9b4453 100644
@@ -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
#54 lore raw

PATCH 43/184 ALSA: seq: Fix missing error handling in

In reply to a message not in the archive

2.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
index f745c31..c2ec4ef 100644
@@ -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
#55 lore raw

PATCH 44/184 ALSA: ice1712: Initialize card->private_data

In reply to a message not in the archive

2.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
index d74033a..95496ae 100644
@@ -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
#56 lore raw

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.

------------------
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().

This bug appears to have been introduced in Linux 3.8 and doesn't need fixing in 2.6.32.

Ben.

Quoted 21 lines
---
 sound/pci/ice1712/ice1712.c | 2 ++
 1 file changed, 2 insertions(+)
sound/pci/ice1712/ice1712.c +2 -0
index d74033a..95496ae 100644
@@ -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.compilers
#57 lore raw

Re: [ 044/184] ALSA: ice1712: Initialize card->private_data

Hi Ben,

Quoted 9 lines · Ben Hutchings
Quoted 6 lines

From: Sean Connor <[email protected]>

commit 69a4cfdd444d1fe5c24d29b3a063964ac165d2cd upstream.

Set card->private_data in snd_ice1712_create for fixing NULL dereference in snd_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

#58 lore raw

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 69a4cfdd444d1fe5c24d29b3a063964ac165d2cd upstream.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Set card->private_data in snd_ice1712_create for fixing NULL dereference in snd_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

#59 lore raw

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_data was 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

#60 lore raw

PATCH 45/184 ALSA: ac97 - Fix missing NULL check in

In reply to a message not in the archive

2.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
index 78288db..5f295f7 100644
@@ -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
#61 lore raw

PATCH 46/184 x86, ioapic: initialize nr_ioapic_registers early in

In reply to a message not in the archive

2.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
index 8928d97..d256bc3 100644
@@ -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
#62 lore raw

PATCH 47/184 x86: Dont use the EFI reboot method by default

In reply to a message not in the archive

2.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

f70e957cda22 x86: Don't use the EFI reboot method by default,

               2011-07-06

for 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 f70e957cda22d309c769805cbb932407a5232219

Quoted 8 lines
Author: Matthew Garrett <[email protected]>
Date:   Wed Jul 6 16:52:37 2011 -0400

x86: 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/721576

There 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.

Cc Linus Torvalds <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Alan Cox <[email protected]>
(cherry picked from commit f70e957cda22d309c769805cbb932407a5232219)
Cc Jonathan Nieder <[email protected]>
Cc Ben Hutchings <[email protected]>
---
 arch/x86/kernel/efi.c | 3 ---
 1 file changed, 3 deletions(-)
arch/x86/kernel/efi.c +0 -3
index cdcfb12..a3e77af 100644
@@ -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
#63 lore raw

PATCH 48/184 x86, random: make ARCH_RANDOM prompt if EMBEDDED,

In reply to a message not in the archive

2.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
index aa889d6..ee0168d 100644
@@ -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
#64 lore raw

PATCH 49/184 x86/xen: dont assume %ds is usable in xen_iret for

In reply to a message not in the archive

2.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
index 9a95a9c..d05bd11 100644
@@ -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
#65 lore raw

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_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
index 9a95a9c..d05bd11 100644
@@ -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.compilers
#66 lore raw

Re: [ 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 13d2b4d11d69a92574a55bfd985cfb0ca77aebdc upstream.

Added, thanks Ben.
Willy

#67 lore raw

PATCH 50/184 x86/msr: Add capabilities check

In reply to a message not in the archive

2.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.

Cc Linus Torvalds <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Horses <[email protected]>
[dannf: backported to Debian's 2.6.32]
---
 arch/x86/kernel/msr.c | 3 +++
 1 file changed, 3 insertions(+)
arch/x86/kernel/msr.c +3 -0
index 5eaeb5e..63a053b 100644
@@ -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
#68 lore raw

PATCH 51/184 x86/mm: Check if PUD is large when validating a

In reply to a message not in the archive

2.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
index af6fd36..1cce9d2 100644
@@ -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
index 7d095ad..ccbc61b 100644
@@ -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
#69 lore raw

PATCH 52/184 x86, mm, paravirt: Fix vmalloc_fault oops during

In reply to a message not in the archive

2.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
index 249ad57..df87450 100644
@@ -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
#70 lore raw

PATCH 53/184 xen/bootup: allow read_tscp call for Xen PV guests.

In reply to a message not in the archive

2.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
index d52f895..f1539ff 100644
@@ -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
#71 lore raw

PATCH 54/184 xen/bootup: allow {read|write}_cr8 pvops call.

In reply to a message not in the archive

2.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
index f1539ff..126a093 100644
@@ -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
#72 lore raw

PATCH 55/184 KVM: x86: fix for buffer overflow in handling of

In reply to a message not in the archive

2.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
index 271fddf..e24e9ce 100644
@@ -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
#73 lore raw

PATCH 56/184 KVM: x86: relax MSR_KVM_SYSTEM_TIME alignment check

In reply to a message not in the archive

2.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.

[dannf: backported to Debian's 2.6.32]
---
 arch/x86/kvm/x86.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/kvm/x86.c +4 -3
index e24e9ce..79905f2 100644
@@ -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
#74 lore raw

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 clock

Check for an address+len that would cross page boundary instead.

[dannf: backported to Debian's 2.6.32]
---
 arch/x86/kvm/x86.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
arch/x86/kvm/x86.c +4 -3
index e24e9ce..79905f2 100644
@@ -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.compilers
#75 lore raw

Re: [ 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 8f964525a121f2ff2df948dac908dcc65be21b5b upstream. This alternate fix avoids the need for extensive backporting.

Added, thank you Ben.

Willy

#76 lore raw

PATCH 57/184 KVM: Fix bounds checking in ioapic indirect register

In reply to a message not in the archive

2.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
index 9fe140b..69969ae 100644
@@ -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
#77 lore raw

PATCH 58/184 KVM: x86: invalid opcode oops on SET_SREGS with

In reply to a message not in the archive

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 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
index 79905f2..ec9728f 100644
@@ -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
#78 lore raw

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 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.

Quoted 6 lines

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]

Quoted 19 lines
---
 arch/x86/kvm/x86.c | 3 +++
 1 file changed, 3 insertions(+)
arch/x86/kvm/x86.c +3 -0
index 79905f2..ec9728f 100644
@@ -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.compilers
#80 lore raw

PATCH 59/184 MCE: Fix vm86 handling for 32bit mce handler

In reply to a message not in the archive

2.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
index 0f16a2b..28a7e4c8 100644
@@ -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
#81 lore raw

PATCH 60/184 ACPI / cpuidle: Fix NULL pointer issues when cpuidle

In reply to a message not in the archive

2.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
index a6ad608..70e9ed1 100644
@@ -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
#82 lore raw

PATCH 61/184 PCI/PM: Clean up PME state when removing a device

In reply to a message not in the archive

2.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
index 176615e..27ae1f9 100644
@@ -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
#83 lore raw

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 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.

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.com

---
 drivers/pci/remove.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/pci/remove.c +2 -0
index 176615e..27ae1f9 100644
@@ -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.compilers
#84 lore raw

Re: [ 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 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.

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

#85 lore raw

PATCH 62/184 alpha: Add irongate_io to PCI bus resources

In reply to a message not in the archive

2.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
index 99c0f46..dc616b3 100644
@@ -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
#86 lore raw

PATCH 63/184 PARISC: fix user-triggerable panic on parisc

In reply to a message not in the archive

2.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 int
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()");

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
index fb59852..32d43e7 100644
@@ -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
#87 lore raw

PATCH 64/184 serial: 8250, increase PASS_LIMIT

In reply to a message not in the archive

2.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_LIMIT merged 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 is e7328ae1 serial: 8250, increase PASS_LIMIT

Cc Alan Cox <[email protected]>
(cherry picked from commit e7328ae1848966181a7ac47e8ae6cddbd2cf55f3)
Cc Ram Gupta <[email protected]>
---
 drivers/serial/8250.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/serial/8250.c +1 -1
index 6a451e8..12e1e9e 100644
@@ -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
#88 lore raw

PATCH 65/184 drivers/char/ipmi: memcpy, need additional 2 bytes

In reply to a message not in the archive

2.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
index 7b98c06..a65a574 100644
@@ -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
#89 lore raw

PATCH 66/184 w1: fix oops when w1_search is called from netlink

In reply to a message not in the archive

2.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:
04f482faf50535229a5a5c8d629cf963899f857c is the first bad commit commit 04f482faf50535229a5a5c8d629cf963899f857c

Author: 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
index acc7e3b..74284bd 100644
@@ -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
#90 lore raw

PATCH 67/184 staging: comedi: ni_labpc: correct differential

In reply to a message not in the archive

2.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
index 4ac745a..eada2ce 100644
@@ -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
#91 lore raw

PATCH 68/184 staging: comedi: ni_labpc: set up command4 register

In reply to a message not in the archive

2.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
index eada2ce..76ca73a 100644
@@ -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
#92 lore raw

PATCH 69/184 staging: comedi: comedi_test: fix race when

In reply to a message not in the archive

2.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
index ef83a1a..7a1e2e8 100644
@@ -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
#93 lore raw

PATCH 70/184 staging: comedi: fix memory leak for saved channel

In reply to a message not in the archive

2.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
index 908f25a..b83c76f 100644
@@ -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
#94 lore raw

PATCH 71/184 staging: comedi: s626: dont dereference insn->data

In reply to a message not in the archive

2.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
index 80d2787..7a7c29f 100644
@@ -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
#95 lore raw

PATCH 72/184 staging: comedi: jr3_pci: fix iomem dereference

In reply to a message not in the archive

2.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
index 1d6385a..ae6f40c 100644
@@ -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
#96 lore raw

PATCH 73/184 staging: comedi: dont dereference user memory for

In reply to a message not in the archive

2.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
index b83c76f..193b836 100644
@@ -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
#97 lore raw

PATCH 74/184 staging: comedi: check s->async for poll(), read()

In reply to a message not in the archive

2.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
index 193b836..90810e8 100644
@@ -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
#98 lore raw

PATCH 75/184 staging: comedi: das08: Correct AO output for

In reply to a message not in the archive

2.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
index f425833..c05cb4b 100644
@@ -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
#99 lore raw

PATCH 76/184 staging: vt6656: [BUG] out of bound array reference

In reply to a message not in the archive

2.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
index 405c4f7..9d059de 100644
@@ -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
#100 lore raw

PATCH 77/184 libata: fix Null pointer dereference on disk error

In reply to a message not in the archive

2.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
index 553edcc..57e895a1 100644
@@ -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
#101 lore raw

PATCH 78/184 scsi: Silence unnecessary warnings about ioctl to

In reply to a message not in the archive

2.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.

CC Paolo Bonzini <[email protected]>
CC James Bottomley <[email protected]>
[bwh: Backported to 3.2: use ENOTTY, not ENOIOCTLCMD]
(cherry picked from commit f45c9a6eec20cd712421c442785e7a4e9215a230)
Cc Thomas Bork <[email protected]>
---
 block/scsi_ioctl.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
block/scsi_ioctl.c +4 -1
index 2be0a97..123eb17 100644
@@ -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
#102 lore raw

PATCH 79/184 scsi: use __uX types for headers exported to user

In reply to a message not in the archive

2.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'

Cc Boaz Harrosh <[email protected]>
Cc James Smart <[email protected]>
Cc James Bottomley <[email protected]>
(cherry picked from commit 083c8c1e60e5c27a277e87dbeb6b89b47937559f)
Cc Thomas Bork <[email protected]>
---
 include/scsi/scsi.h         | 8 ++++----
 include/scsi/scsi_netlink.h | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)
include/scsi/scsi.h +4 -4
index 34c46ab..b3cffec 100644
@@ -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
index 536752c..58ce8fe 100644
@@ -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
#103 lore raw

PATCH 80/184 fix crash in scsi_dispatch_cmd()

In reply to a message not in the archive

2.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.

(cherry picked from commit bfe159a51203c15d23cb3158fffdc25ec4b4dda1)
Cc Thomas Bork <[email protected]>
---
 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
index 00ac586..4058f46 100644
@@ -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
index 49557e9..85bd7b4 100644
@@ -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
index e28f9b0..933f1c5 100644
@@ -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
#104 lore raw

PATCH 81/184 SCSI: bnx2i: Fixed NULL ptr deference for 1G bnx2

In reply to a message not in the archive

2.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
index 5c8d763..1ab55d6 100644
@@ -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
#105 lore raw

PATCH 82/184 keys: fix race with concurrent

In reply to a message not in the archive

2.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
index 931cfda..75fb18c 100644
@@ -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
#106 lore raw

PATCH 83/184 crypto: cryptd - disable softirqs in

In reply to a message not in the archive

2.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
index 3533582..9e1bf69 100644
@@ -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
#107 lore raw

PATCH 84/184 xfrm_user: fix info leak in copy_to_user_state()

In reply to a message not in the archive

2.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
index b95a2d6..4823a15 100644
@@ -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
#108 lore raw

PATCH 85/184 xfrm_user: fix info leak in copy_to_user_policy()

In reply to a message not in the archive

2.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
index 4823a15..3de81fe 100644
@@ -1076,6 +1076,7 @@ static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy
 
 static 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
#109 lore raw

PATCH 86/184 xfrm_user: fix info leak in copy_to_user_tmpl()

In reply to a message not in the archive

2.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
index 3de81fe..a8d83c4 100644
@@ -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
#110 lore raw

PATCH 87/184 xfrm_user: return error pointer instead of NULL

In reply to a message not in the archive

2.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
index a8d83c4..dff20ac 100644
@@ -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
#111 lore raw

PATCH 88/184 xfrm_user: return error pointer instead of NULL #2

In reply to a message not in the archive

2.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
index dff20ac..06f42f6 100644
@@ -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
#112 lore raw

PATCH 89/184 r8169: correct settings of rtl8102e.

In reply to a message not in the archive

2.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.

(cherry picked from commit d24e9aafe5d5dfdf6d114b29e67f8afd5fae5ef0)
Cc Thomas Bork <[email protected]>
---
 drivers/net/r8169.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)
drivers/net/r8169.c +6 -14
index 3ebe50c..6197140 100644
@@ -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
#113 lore raw

PATCH 90/184 r8169: remove the obsolete and incorrect AMD

In reply to a message not in the archive

2.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.

(cherry picked from commit 3a42cce923b0242d0293cae0a162601afa89d552)
Cc Thomas Bork <[email protected]>
---
 drivers/net/r8169.c | 7 -------
 1 file changed, 7 deletions(-)
drivers/net/r8169.c +0 -7
index 6197140..b22623d 100644
@@ -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
#114 lore raw

PATCH 91/184 r8169: Add support for D-Link 530T rev C1 (Kernel

In reply to a message not in the archive

2.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

(cherry picked from commit 7106159f8bd33bd5e5b0ea2c87e499117fc22c69)
Cc Thomas Bork <[email protected]>
---
 drivers/net/r8169.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/r8169.c +1 -0
index b22623d..2d89062 100644
@@ -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
#115 lore raw

PATCH 92/184 r8169: incorrect identifier for a 8168dp

In reply to a message not in the archive

2.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.

(cherry picked from commit 17c99297212a2d1b1779a08caf4b0d83a85545df)
Cc Thomas Bork <[email protected]>
---
 drivers/net/r8169.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/r8169.c +1 -1
index 2d89062..7ddbb8e 100644
@@ -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
#116 lore raw

PATCH 93/184 b43legacy: Fix crash on unload when firmware not

In reply to a message not in the archive

2.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
index c3968fad..fc0fc85 100644
@@ -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
#117 lore raw

PATCH 94/184 tg3: Avoid null pointer dereference in tg3_interrupt

In reply to a message not in the archive

2.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
index fd6622c..89aa69c 100644
@@ -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
#118 lore raw

PATCH 95/184 IPoIB: Fix use-after-free of multicast object

In reply to a message not in the archive

2.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
index b4b2257..f6a23ec 100644
@@ -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
index 8763c1e..bd656a7 100644
@@ -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
#119 lore raw

PATCH 96/184 telephony: ijx: buffer overflow in ixj_write_cid()

In reply to a message not in the archive

2.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
index 40de151..56eb6cc 100644
@@ -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
#120 lore raw

PATCH 97/184 Bluetooth: Fix incorrect strncpy() in

In reply to a message not in the archive

2.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.)

[backported to 2.6.32 jmm]
---
 net/bluetooth/hidp/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/hidp/core.c +1 -1
index 49d8495..0c2c59d 100644
@@ -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
#121 lore raw

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->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.)

[backported to 2.6.32 jmm]
---
 net/bluetooth/hidp/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/hidp/core.c +1 -1
index 49d8495..0c2c59d 100644
@@ -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.compilers
#122 lore raw

Re: [ 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

#123 lore raw

PATCH 98/184 Bluetooth: HCI - Fix info leak in getsockopt(HCI_FILTER)

In reply to a message not in the archive

2.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
index 75302a9..45caaaa 100644
@@ -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
#124 lore raw

PATCH 99/184 Bluetooth: RFCOMM - Fix info leak via getsockname()

In reply to a message not in the archive

2.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
index 1ae3f80..c47b7c4 100644
@@ -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
#125 lore raw

PATCH 100/184 Bluetooth: RFCOMM - Fix missing msg_namelen update

In reply to a message not in the archive

2.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
index c47b7c4..1db0132 100644
@@ -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
#126 lore raw

PATCH 101/184 Bluetooth: L2CAP - Fix info leak via getsockname()

In reply to a message not in the archive

2.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.

Cc Marcel Holtmann <[email protected]>
Cc Gustavo Padovan <[email protected]>
Cc Johan Hedberg <[email protected]>
[bwh: Backported to 2.6.32: adjust filename]
---
 net/bluetooth/l2cap.c | 1 +
 1 file changed, 1 insertion(+)
net/bluetooth/l2cap.c +1 -0
index 71120ee..1c20bd9 100644
@@ -1184,6 +1184,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 
 	BT_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
#127 lore raw

PATCH 102/184 Bluetooth: fix possible info leak in

In reply to a message not in the archive

2.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.

Cc Marcel Holtmann <[email protected]>
Cc Gustavo Padovan <[email protected]>
Cc Johan Hedberg <[email protected]>
[dannf: adjusted to apply to Debian's 2.6.32]
---
 net/bluetooth/af_bluetooth.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/af_bluetooth.c +2 -2
index 8cfb5a8..d7239dd 100644
@@ -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
#128 lore raw

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 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.

Cc Marcel Holtmann <[email protected]>
Cc Gustavo Padovan <[email protected]>
Cc Johan Hedberg <[email protected]>
[dannf: adjusted to apply to Debian's 2.6.32]
---
 net/bluetooth/af_bluetooth.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/af_bluetooth.c +2 -2
index 8cfb5a8..d7239dd 100644
@@ -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.compilers
#129 lore raw

Re: [ 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 4683f42fde3977bdb4e8a09622788cc8b5313778 upstream.

Added, thank you.

Willy

#130 lore raw

PATCH 103/184 xhci: Make handover code more robust

In reply to a message not in the archive

2.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
index 981b604..01e7fae 100644
@@ -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
#131 lore raw

PATCH 104/184 USB: EHCI: go back to using the system clock for QH

In reply to a message not in the archive

2.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
index 7b2e99c..8d17f780 100644
@@ -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
index 5b3ca74..b2b3416 100644
@@ -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
#132 lore raw

PATCH 105/184 USB: whiteheat: fix memory leak in error path

In reply to a message not in the archive

2.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
index 1093d2e..1247be1 100644
@@ -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
#133 lore raw

PATCH 106/184 USB: serial: Fix memory leak in sierra_release()

In reply to a message not in the archive

2.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
index 1b5c9f8..0cbf847 100644
@@ -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
#134 lore raw

PATCH 107/184 USB: mos7840: fix urb leak at release

In reply to a message not in the archive

2.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
index 61829b8..9c338ca 100644
@@ -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
#135 lore raw

PATCH 108/184 USB: mos7840: fix port-device leak in error path

In reply to a message not in the archive

2.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
index 9c338ca..c802c77 100644
@@ -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
#136 lore raw

PATCH 109/184 USB: garmin_gps: fix memory leak on disconnect

In reply to a message not in the archive

2.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
index 867d97b..7c3ac7b 100644
@@ -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
#137 lore raw

PATCH 110/184 USB: io_ti: Fix NULL dereference in chase_port()

In reply to a message not in the archive

2.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
index 14d51e6..cf515f0 100644
@@ -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
#138 lore raw

PATCH 111/184 USB: cdc-wdm: fix buffer overflow

In reply to a message not in the archive

2.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.

[bwh: Backported to 2.6.32: adjust context]
---
 drivers/usb/class/cdc-wdm.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)
drivers/usb/class/cdc-wdm.c +20 -3
index 37f2899..01ae519 100644
@@ -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
#139 lore raw

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 c0f5ecee4e741667b2493c742b60b6218d40b3aa upstream.

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.

[bwh: Backported to 2.6.32: adjust context]
Quoted 74 lines
---
 drivers/usb/class/cdc-wdm.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)
drivers/usb/class/cdc-wdm.c +20 -3
index 37f2899..01ae519 100644
@@ -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.compilers
#140 lore raw

Re: [ 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 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.

Quoted 5 lines
Quoted 3 lines
[bwh: Backported to 2.6.32: adjust context]

Added, thanks.
willy

#141 lore raw

PATCH 112/184 epoll: prevent missed events on EPOLL_CTL_MOD

In reply to a message not in the archive

2.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/

Cc Hans Verkuil <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Al Viro <[email protected]>
Cc Davide Libenzi <[email protected]>
Cc Hans de Goede <[email protected]>
Cc Mauro Carvalho Chehab <[email protected]>
Cc David Miller <[email protected]>
Cc Eric Dumazet <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Andreas Voellmy <[email protected]>
[bwh: Backported to 3.2: adjust context]
---
 fs/eventpoll.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
fs/eventpoll.c +21 -1
index ff57421..83fbd64 100644
@@ -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
#142 lore raw

PATCH 113/184 fs/compat_ioctl.c: VIDEO_SET_SPU_PALETTE missing

In reply to a message not in the archive

2.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
index d84e705..0dd21a4 100644
@@ -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
#143 lore raw

PATCH 114/184 fs/fscache/stats.c: fix memory leak

In reply to a message not in the archive

2.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
index 46435f3a..4fd7e1c 100644
@@ -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
#144 lore raw

PATCH 115/184 sysfs: sysfs_pathname/sysfs_add_one: Use strlcat()

In reply to a message not in the archive

2.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
index e020183..5e7279a 100644
@@ -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
#145 lore raw

PATCH 116/184 tmpfs: fix use-after-free of mempolicy object

In reply to a message not in the archive

2.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 here

Panic:

    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/0x1f

Non-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
index 3e0005b..e6a0c72 100644
@@ -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
#146 lore raw

PATCH 117/184 jbd: Delay discarding buffers in

In reply to a message not in the archive

2.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]>.

(cherry picked from commit 86963918965eb8fe0c8ae009e7c1b4c630f533d5)
---
 fs/jbd/commit.c      | 10 +++++-----
 fs/jbd/transaction.c | 43 +++++++++++++++++++++++++++++++------------
 2 files changed, 36 insertions(+), 17 deletions(-)
fs/jbd/commit.c +5 -5
index 17d29a8..2a5cdd0 100644
@@ -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
#147 lore raw

PATCH 118/184 jbd: Fix assertion failure in commit code due to

In reply to a message not in the archive

2.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.

(cherry picked from commit 09e05d4805e6c524c1af74e524e5d0528bb3fef3)
---
 fs/jbd/commit.c      | 45 +++++++++++++++++++++++++++---------
 fs/jbd/transaction.c | 64 ++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 78 insertions(+), 31 deletions(-)
fs/jbd/commit.c +34 -11
index 2a5cdd0..1060d48 100644
@@ -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
#148 lore raw

PATCH 119/184 jbd: Fix lock ordering bug in journal_unmap_buffer()

In reply to a message not in the archive

2.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
index 4eff79c..1352e60 100644
@@ -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
#149 lore raw

PATCH 120/184 ext4: Fix fs corruption when make_indexed_dir()

In reply to a message not in the archive

2.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.

(cherry picked from commit 7ad8e4e6ae2a7c95445ee1715b1714106fb95037)
---
 fs/ext4/namei.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
fs/ext4/namei.c +12 -2
index c3b6ad0..afe3148 100644
@@ -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
#150 lore raw

PATCH 121/184 ext4: dont dereference null pointer when

In reply to a message not in the archive

2.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

(cherry picked from commit 6976a6f2acde2b0443cd64f1d08af90630e4ce81)
---
 fs/ext4/namei.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
fs/ext4/namei.c +4 -2
index afe3148..902f69b 100644
@@ -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
#151 lore raw

PATCH 122/184 ext4: Fix max file size and logical block counting

In reply to a message not in the archive

2.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))

[dannf: Applied the backport from RHEL6 to Debian's 2.6.32]
---
 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
index bdb6ce7..24fa647 100644
@@ -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
index b4402c8..f4b471d 100644
@@ -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
index a73ed78..fe81390 100644
@@ -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
index f1e7077..3ce77c5 100644
@@ -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
#152 lore raw

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 counting

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 ?

-Lukas

Quoted 264 lines

------------------
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))

[dannf: Applied the backport from RHEL6 to Debian's 2.6.32]
---
 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
index bdb6ce7..24fa647 100644
@@ -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
index b4402c8..f4b471d 100644
@@ -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
index a73ed78..fe81390 100644
@@ -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
index f1e7077..3ce77c5 100644
@@ -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)
#153 lore raw

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 counting

Quoted 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 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))

[dannf: Applied the backport from RHEL6 to Debian's 2.6.32]
---
 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
index bdb6ce7..24fa647 100644
@@ -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
index b4402c8..f4b471d 100644
@@ -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
index a73ed78..fe81390 100644
@@ -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
index f1e7077..3ce77c5 100644
@@ -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)
#154 lore raw

PATCH 123/184 ext4: fix memory leak in ext4_xattr_set_acl()s

In reply to a message not in the archive

2.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
index 0df88b2..d29a06b 100644
@@ -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
#155 lore raw

PATCH 124/184 ext4: online defrag is not supported for journaled

In reply to a message not in the archive

2.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
index fe81390..da25617 100644
@@ -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
#156 lore raw

PATCH 125/184 ext4: always set i_op in ext4_mknod()

In reply to a message not in the archive

2.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
index 902f69b..828c9c9 100644
@@ -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
#157 lore raw

PATCH 126/184 ext4: fix fdatasync() for files with only i_size

In reply to a message not in the archive

2.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
index efe6363..babf448 100644
@@ -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
#158 lore raw

PATCH 127/184 ext4: lock i_mutex when truncating orphan inodes

In reply to a message not in the archive

2.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
index 3ce77c5..108515f 100644
@@ -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
#159 lore raw

PATCH 128/184 ext4: fix race in ext4_mb_add_n_trim()

In reply to a message not in the archive

2.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
index 42bac1b..c7e8bdb 100644
@@ -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
#160 lore raw

PATCH 129/184 ext4: limit group search loop for non-extent files

In reply to a message not in the archive

2.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
index c7e8bdb..cecf2a5 100644
@@ -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
#161 lore raw

PATCH 130/184 CVE-2012-4508 kernel: ext4: AIO vs fallocate stale

In reply to a message not in the archive

2.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
index f4b471d..3f022ea 100644
@@ -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
#162 lore raw

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 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]

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
---
 fs/ext4/extents.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 66 insertions(+), 1 deletion(-)
fs/ext4/extents.c +66 -1
index f4b471d..3f022ea 100644
@@ -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.compilers
#163 lore raw

Re: [ 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 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]

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).

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

#164 lore raw

Re: [ 130/184] CVE-2012-4508 kernel: ext4: AIO vs fallocate stale

In reply to Ben Hutchings

Hi 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 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]

Quoted 8 lines

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).

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

#166 lore raw

PATCH 131/184 ext4: make orphan functions be no-op in no-journal

In reply to a message not in the archive

2.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
index 828c9c9..230bef5 100644
@@ -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
#167 lore raw

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.

------------------
mode

From: 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_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
index 828c9c9..230bef5 100644
@@ -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.compilers
#168 lore raw

Re: [ 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.

------------------
mode

From: Anatol Pomozov <[email protected]>

commit c9b92530a723ac5ef8e352885a1862b18f31b2f5 upstream.

added, thanks.
Willy

#169 lore raw

PATCH 132/184 ext4: avoid hang when mounting non-journal

In reply to a message not in the archive

2.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
index 230bef5..3a1af19 100644
@@ -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
#170 lore raw

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 list

From: 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() 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
index 230bef5..3a1af19 100644
@@ -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.compilers
#171 lore raw

Re: [ 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 list

From: Theodore Ts'o <[email protected]>

commit 0e9a9a1ad619e7e987815d20262d36a2f95717ca upstream.

added, thanks Ben.

Willy