From: Greg Kroah-Hartman Date: Fri, 22 Feb 2008 22:59:35 +0000 (-0800) Subject: .24 patches added X-Git-Tag: v2.6.22.19~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=250ce622e4e06da98f2635bf64eeff857254d691;p=thirdparty%2Fkernel%2Fstable-queue.git .24 patches added --- diff --git a/queue-2.6.24/be-more-robust-about-bad-arguments-in-get_user_pages.patch b/queue-2.6.24/be-more-robust-about-bad-arguments-in-get_user_pages.patch new file mode 100644 index 00000000000..d4b89d8268d --- /dev/null +++ b/queue-2.6.24/be-more-robust-about-bad-arguments-in-get_user_pages.patch @@ -0,0 +1,47 @@ +From 900cf086fd2fbad07f72f4575449e0d0958f860f Mon Sep 17 00:00:00 2001 +From: Jonathan Corbet +Date: Mon, 11 Feb 2008 16:17:33 -0700 +Subject: [PATCH] Be more robust about bad arguments in get_user_pages() + +From: Jonathan Corbet + +patch 900cf086fd2fbad07f72f4575449e0d0958f860f in mainline. + +So I spent a while pounding my head against my monitor trying to figure +out the vmsplice() vulnerability - how could a failure to check for +*read* access turn into a root exploit? It turns out that it's a buffer +overflow problem which is made easy by the way get_user_pages() is +coded. + +In particular, "len" is a signed int, and it is only checked at the +*end* of a do {} while() loop. So, if it is passed in as zero, the loop +will execute once and decrement len to -1. At that point, the loop will +proceed until the next invalid address is found; in the process, it will +likely overflow the pages array passed in to get_user_pages(). + +I think that, if get_user_pages() has been asked to grab zero pages, +that's what it should do. Thus this patch; it is, among other things, +enough to block the (already fixed) root exploit and any others which +might be lurking in similar code. I also think that the number of pages +should be unsigned, but changing the prototype of this function probably +requires some more careful review. + +Signed-off-by: Jonathan Corbet +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memory.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -980,6 +980,8 @@ int get_user_pages(struct task_struct *t + int i; + unsigned int vm_flags; + ++ if (len <= 0) ++ return 0; + /* + * Require read or write permissions. + * If 'force' is set, we only require the "MAY" flags. diff --git a/queue-2.6.24/disable-g5-nap-mode-during-smu-commands-on-u3.patch b/queue-2.6.24/disable-g5-nap-mode-during-smu-commands-on-u3.patch new file mode 100644 index 00000000000..b5f9f9df45d --- /dev/null +++ b/queue-2.6.24/disable-g5-nap-mode-during-smu-commands-on-u3.patch @@ -0,0 +1,144 @@ +From 592a607bbc053bc6f614a0e619326009f4b3829e Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Thu, 7 Feb 2008 14:29:43 +1100 +Subject: [PATCH] [POWERPC] Disable G5 NAP mode during SMU commands on U3 + +From: Benjamin Herrenschmidt + +patch 592a607bbc053bc6f614a0e619326009f4b3829e in mainline. + +It appears that with the U3 northbridge, if the processor is in NAP +mode the whole time while waiting for an SMU command to complete, +then the SMU will fail. It could be related to the weird backward +mechanism the SMU uses to get to system memory via i2c to the +northbridge that doesn't operate properly when the said bridge is +in napping along with the CPU. That is on U3 at least, U4 doesn't +seem to be affected. + +This didn't show before NO_HZ as the timer wakeup was enough to make +it work it seems, but that is no longer the case. + +This fixes it by disabling NAP mode on those machines while +an SMU command is in flight. + +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Paul Mackerras +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/platforms/powermac/feature.c | 11 ++++++++++- + drivers/macintosh/smu.c | 25 ++++++++++++++++++++++++- + include/asm-powerpc/pmac_feature.h | 8 ++++++++ + 3 files changed, 42 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/platforms/powermac/feature.c ++++ b/arch/powerpc/platforms/powermac/feature.c +@@ -2565,6 +2565,8 @@ static void __init probe_uninorth(void) + + /* Locate core99 Uni-N */ + uninorth_node = of_find_node_by_name(NULL, "uni-n"); ++ uninorth_maj = 1; ++ + /* Locate G5 u3 */ + if (uninorth_node == NULL) { + uninorth_node = of_find_node_by_name(NULL, "u3"); +@@ -2575,8 +2577,10 @@ static void __init probe_uninorth(void) + uninorth_node = of_find_node_by_name(NULL, "u4"); + uninorth_maj = 4; + } +- if (uninorth_node == NULL) ++ if (uninorth_node == NULL) { ++ uninorth_maj = 0; + return; ++ } + + addrp = of_get_property(uninorth_node, "reg", NULL); + if (addrp == NULL) +@@ -3029,3 +3033,8 @@ void pmac_resume_agp_for_card(struct pci + pmac_agp_resume(pmac_agp_bridge); + } + EXPORT_SYMBOL(pmac_resume_agp_for_card); ++ ++int pmac_get_uninorth_variant(void) ++{ ++ return uninorth_maj; ++} +--- a/drivers/macintosh/smu.c ++++ b/drivers/macintosh/smu.c +@@ -85,6 +85,7 @@ struct smu_device { + u32 cmd_buf_abs; /* command buffer absolute */ + struct list_head cmd_list; + struct smu_cmd *cmd_cur; /* pending command */ ++ int broken_nap; + struct list_head cmd_i2c_list; + struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */ + struct timer_list i2c_timer; +@@ -135,6 +136,19 @@ static void smu_start_cmd(void) + fend = faddr + smu->cmd_buf->length + 2; + flush_inval_dcache_range(faddr, fend); + ++ ++ /* We also disable NAP mode for the duration of the command ++ * on U3 based machines. ++ * This is slightly racy as it can be written back to 1 by a sysctl ++ * but that never happens in practice. There seem to be an issue with ++ * U3 based machines such as the iMac G5 where napping for the ++ * whole duration of the command prevents the SMU from fetching it ++ * from memory. This might be related to the strange i2c based ++ * mechanism the SMU uses to access memory. ++ */ ++ if (smu->broken_nap) ++ powersave_nap = 0; ++ + /* This isn't exactly a DMA mapping here, I suspect + * the SMU is actually communicating with us via i2c to the + * northbridge or the CPU to access RAM. +@@ -211,6 +225,10 @@ static irqreturn_t smu_db_intr(int irq, + misc = cmd->misc; + mb(); + cmd->status = rc; ++ ++ /* Re-enable NAP mode */ ++ if (smu->broken_nap) ++ powersave_nap = 1; + bail: + /* Start next command if any */ + smu_start_cmd(); +@@ -461,7 +479,7 @@ int __init smu_init (void) + if (np == NULL) + return -ENODEV; + +- printk(KERN_INFO "SMU driver %s %s\n", VERSION, AUTHOR); ++ printk(KERN_INFO "SMU: Driver %s %s\n", VERSION, AUTHOR); + + if (smu_cmdbuf_abs == 0) { + printk(KERN_ERR "SMU: Command buffer not allocated !\n"); +@@ -533,6 +551,11 @@ int __init smu_init (void) + goto fail; + } + ++ /* U3 has an issue with NAP mode when issuing SMU commands */ ++ smu->broken_nap = pmac_get_uninorth_variant() < 4; ++ if (smu->broken_nap) ++ printk(KERN_INFO "SMU: using NAP mode workaround\n"); ++ + sys_ctrler = SYS_CTRLER_SMU; + return 0; + +--- a/include/asm-powerpc/pmac_feature.h ++++ b/include/asm-powerpc/pmac_feature.h +@@ -392,6 +392,14 @@ extern u32 __iomem *uninorth_base; + #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) + #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + ++/* Uninorth variant: ++ * ++ * 0 = not uninorth ++ * 1 = U1.x or U2.x ++ * 3 = U3 ++ * 4 = U4 ++ */ ++extern int pmac_get_uninorth_variant(void); + + #endif /* __ASM_POWERPC_PMAC_FEATURE_H */ + #endif /* __KERNEL__ */ diff --git a/queue-2.6.24/genirq-do-not-leave-interupts-enabled-on-free_irq.patch b/queue-2.6.24/genirq-do-not-leave-interupts-enabled-on-free_irq.patch new file mode 100644 index 00000000000..958e6f0ef2c --- /dev/null +++ b/queue-2.6.24/genirq-do-not-leave-interupts-enabled-on-free_irq.patch @@ -0,0 +1,76 @@ +From stable-bounces@linux.kernel.org Tue Feb 19 15:29:28 2008 +From: Thomas Gleixner +Date: Wed, 20 Feb 2008 00:29:02 +0100 (CET) +Subject: genirq: do not leave interupts enabled on free_irq +To: Stable Team +Message-ID: + +From: Thomas Gleixner + +commit 89d694b9dbe769ca1004e01db0ca43964806a611 + +The default_disable() function was changed in commit: + + 76d2160147f43f982dfe881404cfde9fd0a9da21 + genirq: do not mask interrupts by default + +It removed the mask function in favour of the default delayed +interrupt disabling. Unfortunately this also broke the shutdown in +free_irq() when the last handler is removed from the interrupt for +those architectures which rely on the default implementations. Now we +can end up with a enabled interrupt line after the last handler was +removed, which can result in spurious interrupts. + +Fix this by adding a default_shutdown function, which is only +installed, when the irqchip implementation does provide neither a +shutdown nor a disable function. + + +Pointed-out-by: Michael Hennerich +Signed-off-by: Thomas Gleixner +Acked-by: Ingo Molnar +Tested-by: Michael Hennerich +Signed-off-by: Greg Kroah-Hartman + + +--- + kernel/irq/chip.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +--- a/kernel/irq/chip.c ++++ b/kernel/irq/chip.c +@@ -246,6 +246,17 @@ static unsigned int default_startup(unsi + } + + /* ++ * default shutdown function ++ */ ++static void default_shutdown(unsigned int irq) ++{ ++ struct irq_desc *desc = irq_desc + irq; ++ ++ desc->chip->mask(irq); ++ desc->status |= IRQ_MASKED; ++} ++ ++/* + * Fixup enable/disable function pointers + */ + void irq_chip_set_defaults(struct irq_chip *chip) +@@ -256,8 +267,15 @@ void irq_chip_set_defaults(struct irq_ch + chip->disable = default_disable; + if (!chip->startup) + chip->startup = default_startup; ++ /* ++ * We use chip->disable, when the user provided its own. When ++ * we have default_disable set for chip->disable, then we need ++ * to use default_shutdown, otherwise the irq line is not ++ * disabled on free_irq(): ++ */ + if (!chip->shutdown) +- chip->shutdown = chip->disable; ++ chip->shutdown = chip->disable != default_disable ? ++ chip->disable : default_shutdown; + if (!chip->name) + chip->name = chip->typename; + if (!chip->end) diff --git a/queue-2.6.24/hrtimer-catch-expired-clock_realtime-timers-early.patch b/queue-2.6.24/hrtimer-catch-expired-clock_realtime-timers-early.patch new file mode 100644 index 00000000000..e287a596ef1 --- /dev/null +++ b/queue-2.6.24/hrtimer-catch-expired-clock_realtime-timers-early.patch @@ -0,0 +1,58 @@ +From stable-bounces@linux.kernel.org Tue Feb 19 16:05:31 2008 +From: Thomas Gleixner +Date: Wed, 20 Feb 2008 01:04:56 +0100 (CET) +Subject: hrtimer: catch expired CLOCK_REALTIME timers early +To: Stable Team +Message-ID: + + + +From: Thomas Gleixner + +commit 63070a79ba482c274bad10ac8c4b587a3e011f2c + +A CLOCK_REALTIME timer, which has an absolute expiry time less than +the clock realtime offset calls with a negative delta into the clock +events code and triggers the WARN_ON() there. + +This is a false positive and needs to be prevented. Check the result +of timer->expires - timer->base->offset right away and return -ETIME +right away. + +Thanks to Frans Pop, who reported the problem and tested the fixes. + +Signed-off-by: Thomas Gleixner +Tested-by: Frans Pop +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/hrtimer.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -427,6 +427,8 @@ static int hrtimer_reprogram(struct hrti + ktime_t expires = ktime_sub(timer->expires, base->offset); + int res; + ++ WARN_ON_ONCE(timer->expires.tv64 < 0); ++ + /* + * When the callback is running, we do not reprogram the clock event + * device. The timer callback is either running on a different CPU or +@@ -437,6 +439,15 @@ static int hrtimer_reprogram(struct hrti + if (hrtimer_callback_running(timer)) + return 0; + ++ /* ++ * CLOCK_REALTIME timer might be requested with an absolute ++ * expiry time which is less than base->offset. Nothing wrong ++ * about that, just avoid to call into the tick code, which ++ * has now objections against negative expiry values. ++ */ ++ if (expires.tv64 < 0) ++ return -ETIME; ++ + if (expires.tv64 >= expires_next->tv64) + return 0; + diff --git a/queue-2.6.24/hrtimer-check-relative-timeouts-for-overflow.patch b/queue-2.6.24/hrtimer-check-relative-timeouts-for-overflow.patch new file mode 100644 index 00000000000..622e785dee3 --- /dev/null +++ b/queue-2.6.24/hrtimer-check-relative-timeouts-for-overflow.patch @@ -0,0 +1,154 @@ +From stable-bounces@linux.kernel.org Tue Feb 19 16:03:26 2008 +From: Thomas Gleixner +Date: Wed, 20 Feb 2008 01:03:00 +0100 (CET) +Subject: hrtimer: check relative timeouts for overflow +To: Stable Team +Message-ID: + +From: Thomas Gleixner + +commit: 5a7780e725d1bb4c3094fcc12f1c5c5faea1e988 + +Various user space callers ask for relative timeouts. While we fixed +that overflow issue in hrtimer_start(), the sites which convert +relative user space values to absolute timeouts themself were uncovered. + +Instead of putting overflow checks into each place add a function +which does the sanity checking and convert all affected callers to use +it. + +Thanks to Frans Pop, who reported the problem and tested the fixes. + +Signed-off-by: Thomas Gleixner +Acked-by: Ingo Molnar +Tested-by: Frans Pop +Signed-off-by: Greg Kroah-Hartman + + +--- + include/linux/ktime.h | 2 ++ + kernel/futex.c | 2 +- + kernel/futex_compat.c | 2 +- + kernel/hrtimer.c | 38 +++++++++++++++++++++----------------- + kernel/posix-timers.c | 8 +++++--- + 5 files changed, 30 insertions(+), 22 deletions(-) + +--- a/include/linux/ktime.h ++++ b/include/linux/ktime.h +@@ -310,6 +310,8 @@ static inline ktime_t ktime_sub_us(const + return ktime_sub_ns(kt, usec * 1000); + } + ++extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs); ++ + /* + * The resolution of the clocks. The resolution value is returned in + * the clock_getres() system call to give application programmers an +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -2094,7 +2094,7 @@ asmlinkage long sys_futex(u32 __user *ua + + t = timespec_to_ktime(ts); + if (cmd == FUTEX_WAIT) +- t = ktime_add(ktime_get(), t); ++ t = ktime_add_safe(ktime_get(), t); + tp = &t; + } + /* +--- a/kernel/futex_compat.c ++++ b/kernel/futex_compat.c +@@ -175,7 +175,7 @@ asmlinkage long compat_sys_futex(u32 __u + + t = timespec_to_ktime(ts); + if (cmd == FUTEX_WAIT) +- t = ktime_add(ktime_get(), t); ++ t = ktime_add_safe(ktime_get(), t); + tp = &t; + } + if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE) +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -325,6 +325,24 @@ unsigned long ktime_divns(const ktime_t + } + #endif /* BITS_PER_LONG >= 64 */ + ++/* ++ * Add two ktime values and do a safety check for overflow: ++ */ ++ ++ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs) ++{ ++ ktime_t res = ktime_add(lhs, rhs); ++ ++ /* ++ * We use KTIME_SEC_MAX here, the maximum timeout which we can ++ * return to user space in a timespec: ++ */ ++ if (res.tv64 < 0 || res.tv64 < lhs.tv64 || res.tv64 < rhs.tv64) ++ res = ktime_set(KTIME_SEC_MAX, 0); ++ ++ return res; ++} ++ + /* High resolution timer related functions */ + #ifdef CONFIG_HIGH_RES_TIMERS + +@@ -682,13 +700,7 @@ hrtimer_forward(struct hrtimer *timer, k + */ + orun++; + } +- timer->expires = ktime_add(timer->expires, interval); +- /* +- * Make sure, that the result did not wrap with a very large +- * interval. +- */ +- if (timer->expires.tv64 < 0) +- timer->expires = ktime_set(KTIME_SEC_MAX, 0); ++ timer->expires = ktime_add_safe(timer->expires, interval); + + return orun; + } +@@ -839,7 +851,7 @@ hrtimer_start(struct hrtimer *timer, kti + new_base = switch_hrtimer_base(timer, base); + + if (mode == HRTIMER_MODE_REL) { +- tim = ktime_add(tim, new_base->get_time()); ++ tim = ktime_add_safe(tim, new_base->get_time()); + /* + * CONFIG_TIME_LOW_RES is a temporary way for architectures + * to signal that they simply return xtime in +@@ -848,16 +860,8 @@ hrtimer_start(struct hrtimer *timer, kti + * timeouts. This will go away with the GTOD framework. + */ + #ifdef CONFIG_TIME_LOW_RES +- tim = ktime_add(tim, base->resolution); ++ tim = ktime_add_safe(tim, base->resolution); + #endif +- /* +- * Careful here: User space might have asked for a +- * very long sleep, so the add above might result in a +- * negative number, which enqueues the timer in front +- * of the queue. +- */ +- if (tim.tv64 < 0) +- tim.tv64 = KTIME_MAX; + } + timer->expires = tim; + +--- a/kernel/posix-timers.c ++++ b/kernel/posix-timers.c +@@ -766,9 +766,11 @@ common_timer_set(struct k_itimer *timr, + /* SIGEV_NONE timers are not queued ! See common_timer_get */ + if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { + /* Setup correct expiry time for relative timers */ +- if (mode == HRTIMER_MODE_REL) +- timer->expires = ktime_add(timer->expires, +- timer->base->get_time()); ++ if (mode == HRTIMER_MODE_REL) { ++ timer->expires = ++ ktime_add_safe(timer->expires, ++ timer->base->get_time()); ++ } + return 0; + } + diff --git a/queue-2.6.24/hrtimer-fix-rmtp-handling-in-hrtimer_nanosleep.patch b/queue-2.6.24/hrtimer-fix-rmtp-handling-in-hrtimer_nanosleep.patch new file mode 100644 index 00000000000..4e37bd75649 --- /dev/null +++ b/queue-2.6.24/hrtimer-fix-rmtp-handling-in-hrtimer_nanosleep.patch @@ -0,0 +1,189 @@ +From stable-bounces@linux.kernel.org Tue Feb 19 15:48:29 2008 +From: Oleg Nesterov +Date: Wed, 20 Feb 2008 00:48:06 +0100 (CET) +Subject: hrtimer: fix *rmtp handling in hrtimer_nanosleep() +To: Stable Team +Message-ID: + +From: Oleg Nesterov + +commit 080344b98805553f9b01de0f59a41b1533036d8d + +Spotted by Pavel Emelyanov and Alexey Dobriyan. + +hrtimer_nanosleep() sets restart_block->arg1 = rmtp, but this rmtp points to +the local variable which lives in the caller's stack frame. This means that +if sys_restart_syscall() actually happens and it is interrupted as well, we +don't update the user-space variable, but write into the already dead stack +frame. + +Introduced by commit 04c227140fed77587432667a574b14736a06dd7f +hrtimer: Rework hrtimer_nanosleep to make sys_compat_nanosleep easier + +Change the callers to pass "__user *rmtp" to hrtimer_nanosleep(), and change +hrtimer_nanosleep() to use copy_to_user() to actually update *rmtp. + +Small problem remains. man 2 nanosleep states that *rtmp should be written if +nanosleep() was interrupted (it says nothing whether it is OK to update *rmtp +if nanosleep returns 0), but (with or without this patch) we can dirty *rem +even if nanosleep() returns 0. + +NOTE: this patch doesn't change compat_sys_nanosleep(), because it has other +bugs. Fixed by the next patch. + +Signed-off-by: Oleg Nesterov +Cc: Alexey Dobriyan +Cc: Michael Kerrisk +Cc: Pavel Emelyanov +Cc: Peter Zijlstra +Cc: Toyo Abe +Cc: Andrew Morton +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/hrtimer.h | 2 - + kernel/hrtimer.c | 51 +++++++++++++++++++++++++----------------------- + kernel/posix-timers.c | 17 ++-------------- + 3 files changed, 31 insertions(+), 39 deletions(-) + +--- a/include/linux/hrtimer.h ++++ b/include/linux/hrtimer.h +@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, k + + /* Precise sleep: */ + extern long hrtimer_nanosleep(struct timespec *rqtp, +- struct timespec *rmtp, ++ struct timespec __user *rmtp, + const enum hrtimer_mode mode, + const clockid_t clockid); + extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -1291,11 +1291,26 @@ static int __sched do_nanosleep(struct h + return t->task == NULL; + } + ++static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) ++{ ++ struct timespec rmt; ++ ktime_t rem; ++ ++ rem = ktime_sub(timer->expires, timer->base->get_time()); ++ if (rem.tv64 <= 0) ++ return 0; ++ rmt = ktime_to_timespec(rem); ++ ++ if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) ++ return -EFAULT; ++ ++ return 1; ++} ++ + long __sched hrtimer_nanosleep_restart(struct restart_block *restart) + { + struct hrtimer_sleeper t; +- struct timespec *rmtp; +- ktime_t time; ++ struct timespec __user *rmtp; + + restart->fn = do_no_restart_syscall; + +@@ -1305,12 +1320,11 @@ long __sched hrtimer_nanosleep_restart(s + if (do_nanosleep(&t, HRTIMER_MODE_ABS)) + return 0; + +- rmtp = (struct timespec *)restart->arg1; ++ rmtp = (struct timespec __user *)restart->arg1; + if (rmtp) { +- time = ktime_sub(t.timer.expires, t.timer.base->get_time()); +- if (time.tv64 <= 0) +- return 0; +- *rmtp = ktime_to_timespec(time); ++ int ret = update_rmtp(&t.timer, rmtp); ++ if (ret <= 0) ++ return ret; + } + + restart->fn = hrtimer_nanosleep_restart; +@@ -1319,12 +1333,11 @@ long __sched hrtimer_nanosleep_restart(s + return -ERESTART_RESTARTBLOCK; + } + +-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp, ++long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, + const enum hrtimer_mode mode, const clockid_t clockid) + { + struct restart_block *restart; + struct hrtimer_sleeper t; +- ktime_t rem; + + hrtimer_init(&t.timer, clockid, mode); + t.timer.expires = timespec_to_ktime(*rqtp); +@@ -1336,10 +1349,9 @@ long hrtimer_nanosleep(struct timespec * + return -ERESTARTNOHAND; + + if (rmtp) { +- rem = ktime_sub(t.timer.expires, t.timer.base->get_time()); +- if (rem.tv64 <= 0) +- return 0; +- *rmtp = ktime_to_timespec(rem); ++ int ret = update_rmtp(&t.timer, rmtp); ++ if (ret <= 0) ++ return ret; + } + + restart = ¤t_thread_info()->restart_block; +@@ -1355,8 +1367,7 @@ long hrtimer_nanosleep(struct timespec * + asmlinkage long + sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp) + { +- struct timespec tu, rmt; +- int ret; ++ struct timespec tu; + + if (copy_from_user(&tu, rqtp, sizeof(tu))) + return -EFAULT; +@@ -1364,15 +1375,7 @@ sys_nanosleep(struct timespec __user *rq + if (!timespec_valid(&tu)) + return -EINVAL; + +- ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, +- CLOCK_MONOTONIC); +- +- if (ret && rmtp) { +- if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) +- return -EFAULT; +- } +- +- return ret; ++ return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); + } + + /* +--- a/kernel/posix-timers.c ++++ b/kernel/posix-timers.c +@@ -981,20 +981,9 @@ sys_clock_getres(const clockid_t which_c + static int common_nsleep(const clockid_t which_clock, int flags, + struct timespec *tsave, struct timespec __user *rmtp) + { +- struct timespec rmt; +- int ret; +- +- ret = hrtimer_nanosleep(tsave, rmtp ? &rmt : NULL, +- flags & TIMER_ABSTIME ? +- HRTIMER_MODE_ABS : HRTIMER_MODE_REL, +- which_clock); +- +- if (ret && rmtp) { +- if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) +- return -EFAULT; +- } +- +- return ret; ++ return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? ++ HRTIMER_MODE_ABS : HRTIMER_MODE_REL, ++ which_clock); + } + + asmlinkage long diff --git a/queue-2.6.24/hrtimer-fix-rmtp-restarts-handling-in-compat_sys_nanosleep.patch b/queue-2.6.24/hrtimer-fix-rmtp-restarts-handling-in-compat_sys_nanosleep.patch new file mode 100644 index 00000000000..bf70d6593be --- /dev/null +++ b/queue-2.6.24/hrtimer-fix-rmtp-restarts-handling-in-compat_sys_nanosleep.patch @@ -0,0 +1,103 @@ +From stable-bounces@linux.kernel.org Tue Feb 19 15:49:15 2008 +From: Oleg Nesterov +Date: Wed, 20 Feb 2008 00:48:53 +0100 (CET) +Subject: hrtimer: fix *rmtp/restarts handling in compat_sys_nanosleep() +To: Stable Team +Message-ID: + +From: Oleg Nesterov + +commit 416529374b4793ba2d2e97e736d108a2e0f3ef07 + +Spotted by Pavel Emelyanov and Alexey Dobriyan. + +compat_sys_nanosleep() implicitly uses hrtimer_nanosleep_restart(), this can't +work. Make a suitable compat_nanosleep_restart() helper. + +Introduced by commit c70878b4e0b6cf8d2f1e46319e48e821ef4a8aba +hrtimer: hook compat_sys_nanosleep up to high res timer code + +Also, set ->addr_limit = KERNEL_DS before doing hrtimer_nanosleep(), this func +was changed by the previous patch and now takes the "__user *" parameter. + +Thanks to Ingo Molnar for fixing the bug in this patch. + +Signed-off-by: Oleg Nesterov +Cc: Andrew Morton +Cc: Alexey Dobriyan +Cc: Pavel Emelyanov +Cc: Peter Zijlstra +Cc: Toyo Abe +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + + +--- + kernel/compat.c | 44 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 4 deletions(-) + +--- a/kernel/compat.c ++++ b/kernel/compat.c +@@ -40,10 +40,36 @@ int put_compat_timespec(const struct tim + __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; + } + ++static long compat_nanosleep_restart(struct restart_block *restart) ++{ ++ struct compat_timespec __user *rmtp; ++ struct timespec rmt; ++ mm_segment_t oldfs; ++ long ret; ++ ++ rmtp = (struct compat_timespec __user *)(restart->arg1); ++ restart->arg1 = (unsigned long)&rmt; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ret = hrtimer_nanosleep_restart(restart); ++ set_fs(oldfs); ++ ++ if (ret) { ++ restart->fn = compat_nanosleep_restart; ++ restart->arg1 = (unsigned long)rmtp; ++ ++ if (rmtp && put_compat_timespec(&rmt, rmtp)) ++ return -EFAULT; ++ } ++ ++ return ret; ++} ++ + asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, + struct compat_timespec __user *rmtp) + { + struct timespec tu, rmt; ++ mm_segment_t oldfs; + long ret; + + if (get_compat_timespec(&tu, rqtp)) +@@ -52,11 +78,21 @@ asmlinkage long compat_sys_nanosleep(str + if (!timespec_valid(&tu)) + return -EINVAL; + +- ret = hrtimer_nanosleep(&tu, rmtp ? &rmt : NULL, HRTIMER_MODE_REL, +- CLOCK_MONOTONIC); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ret = hrtimer_nanosleep(&tu, ++ rmtp ? (struct timespec __user *)&rmt : NULL, ++ HRTIMER_MODE_REL, CLOCK_MONOTONIC); ++ set_fs(oldfs); ++ ++ if (ret) { ++ struct restart_block *restart ++ = ¤t_thread_info()->restart_block; ++ ++ restart->fn = compat_nanosleep_restart; ++ restart->arg1 = (unsigned long)rmtp; + +- if (ret && rmtp) { +- if (put_compat_timespec(&rmt, rmtp)) ++ if (rmtp && put_compat_timespec(&rmt, rmtp)) + return -EFAULT; + } + diff --git a/queue-2.6.24/kbuild-allow-fstack-protector-to-take-effect.patch b/queue-2.6.24/kbuild-allow-fstack-protector-to-take-effect.patch new file mode 100644 index 00000000000..8561f4b767e --- /dev/null +++ b/queue-2.6.24/kbuild-allow-fstack-protector-to-take-effect.patch @@ -0,0 +1,68 @@ +From stable-bounces@linux.kernel.org Mon Feb 18 16:05:47 2008 +From: Sam Ravnborg +Date: Tue, 19 Feb 2008 00:05:28 GMT +Subject: kbuild: allow -fstack-protector to take effect +To: jejb@kernel.org, stable@kernel.org +Message-ID: <200802190005.m1J05SKP017015@hera.kernel.org> + +From: Sam Ravnborg + +commit: e06b8b98da071f7dd78fb7822991694288047df0 + +Arjan van de Ven wrote: +=== +I just read the excellent LWN writeup of the vmsplice +security thing, and that got me wondering why this attack +wasn't stopped by the CONFIG_CC_STACKPROTECTOR option... +because it plain should have been... + +Some analysis later.. it turns out that the following line +in the top level Makefile, added by you in October 2007, +entirely disables CONFIG_CC_STACKPROTECTOR ;( +With this line removed the exploit will be nicely stopped. + +CFLAGS += $(call cc-option, -fno-stack-protector) + +Now I realize that certain distros have patched gcc to +compensate for their lack of distro wide CFLAGS, and it's +great to work around that... but would there be a way to NOT +disable this for CONFIG_CC_STACKPROTECTOR please? +It would have made this exploit not possible for those kernels +that enable this feature (and that includes distros like Fedora) +=== + +Move the assignment to KBUILD_CFLAGS up before including +the arch specific Makefile so arch makefiles may override +the setting. + +Signed-off-by: Sam Ravnborg +Cc: Arjan van de Ven +Signed-off-by: Greg Kroah-Hartman + +--- + Makefile | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -507,6 +507,10 @@ else + KBUILD_CFLAGS += -O2 + endif + ++# Force gcc to behave correct even for buggy distributions ++# Arch Makefiles may override this setting ++KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) ++ + include $(srctree)/arch/$(SRCARCH)/Makefile + + ifdef CONFIG_FRAME_POINTER +@@ -520,9 +524,6 @@ KBUILD_CFLAGS += -g + KBUILD_AFLAGS += -gdwarf-2 + endif + +-# Force gcc to behave correct even for buggy distributions +-KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) +- + # arch Makefile may override CC so keep this after arch Makefile is included + NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) + CHECKFLAGS += $(NOSTDINC_FLAGS) diff --git a/queue-2.6.24/pcmcia-fix-station-address-detection-in-smc.patch b/queue-2.6.24/pcmcia-fix-station-address-detection-in-smc.patch new file mode 100644 index 00000000000..c4c68cc9dbd --- /dev/null +++ b/queue-2.6.24/pcmcia-fix-station-address-detection-in-smc.patch @@ -0,0 +1,53 @@ +From stable-bounces@linux.kernel.org Thu Feb 21 16:33:44 2008 +From: Chuck Ebbert +Date: Thu, 21 Feb 2008 19:33:00 -0500 +Subject: PCMCIA: Fix station address detection in smc +To: linux-stable +Cc: Jeff Garzik +Message-ID: <47BE183C.8080105@redhat.com> + +From: Chuck Ebbert + +Commit: a1a98b72dbd17e53cd92b8e78f404525ebcfd981 + +Fix station address detection in smc + +Megahertz EM1144 PCMCIA ethernet adapter needs special handling +because it has two VERS_1 tuples and the station address is in +the second one. Conversion to generic handling of these fields +broke it. Reverting that fixes the device. + + https://bugzilla.redhat.com/show_bug.cgi?id=233255 + +Thanks go to Jon Stanley for not giving up on this one until the +problem was found. + +Signed-off-by: Chuck Ebbert +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/pcmcia/smc91c92_cs.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/pcmcia/smc91c92_cs.c ++++ b/drivers/net/pcmcia/smc91c92_cs.c +@@ -559,8 +559,16 @@ static int mhz_setup(struct pcmcia_devic + + /* Read the station address from the CIS. It is stored as the last + (fourth) string in the Version 1 Version/ID tuple. */ +- if (link->prod_id[3]) { +- station_addr = link->prod_id[3]; ++ tuple->DesiredTuple = CISTPL_VERS_1; ++ if (first_tuple(link, tuple, parse) != CS_SUCCESS) { ++ rc = -1; ++ goto free_cfg_mem; ++ } ++ /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ ++ if (next_tuple(link, tuple, parse) != CS_SUCCESS) ++ first_tuple(link, tuple, parse); ++ if (parse->version_1.ns > 3) { ++ station_addr = parse->version_1.str + parse->version_1.ofs[3]; + if (cvt_ascii_address(dev, station_addr) == 0) { + rc = 0; + goto free_cfg_mem; diff --git a/queue-2.6.24/powerpc-revert-chrp_pci_fixup_vt8231_ata-devinit-to-fix-libata-on-pegasos.patch b/queue-2.6.24/powerpc-revert-chrp_pci_fixup_vt8231_ata-devinit-to-fix-libata-on-pegasos.patch new file mode 100644 index 00000000000..e6b93282d49 --- /dev/null +++ b/queue-2.6.24/powerpc-revert-chrp_pci_fixup_vt8231_ata-devinit-to-fix-libata-on-pegasos.patch @@ -0,0 +1,48 @@ +From stable-bounces@linux.kernel.org Thu Feb 21 16:42:09 2008 +From: Olaf Hering +Date: Thu, 21 Feb 2008 19:41:44 -0500 +Subject: POWERPC: Revert chrp_pci_fixup_vt8231_ata devinit to fix libata on pegasos +To: linux-stable +Cc: Paul Mackerras +Message-ID: <47BE1A48.3000604@redhat.com> + +From: Olaf Hering + +Commit: 092ca5bd61da6344f3b249754b337f2d48dfe08d + +[POWERPC] Revert chrp_pci_fixup_vt8231_ata devinit to fix libata on pegasos + +Commit 6d98bda79bea0e1be26c0767d0e9923ad3b72f2e changed the init order +for chrp_pci_fixup_vt8231_ata(). + +It can not work anymore because either the irq is not yet set to 14 or +pci_get_device() returns nothing. At least the printk() in +chrp_pci_fixup_vt8231_ata() does not trigger anymore. +pata_via works again on Pegasos with the change below. + +Signed-off-by: Olaf Hering +Signed-off-by: Paul Mackerras +Cc: Chuck Ebbert +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/platforms/chrp/pci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/platforms/chrp/pci.c ++++ b/arch/powerpc/platforms/chrp/pci.c +@@ -354,7 +354,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_WI + * mode as well. The same fixup must be done to the class-code property in + * the IDE node /pci@80000000/ide@C,1 + */ +-static void __devinit chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) ++static void chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) + { + u8 progif; + struct pci_dev *viaisa; +@@ -375,4 +375,4 @@ static void __devinit chrp_pci_fixup_vt8 + + pci_dev_put(viaisa); + } +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); diff --git a/queue-2.6.24/s390-fix-futex_atomic_cmpxchg_std-inline-assembly.patch b/queue-2.6.24/s390-fix-futex_atomic_cmpxchg_std-inline-assembly.patch new file mode 100644 index 00000000000..231051ee209 --- /dev/null +++ b/queue-2.6.24/s390-fix-futex_atomic_cmpxchg_std-inline-assembly.patch @@ -0,0 +1,41 @@ +From stable-bounces@linux.kernel.org Tue Feb 19 09:20:19 2008 +From: Heiko Carstens +Date: Tue, 19 Feb 2008 17:20:11 GMT +Subject: S390: Fix futex_atomic_cmpxchg_std inline assembly. +To: jejb@kernel.org, stable@kernel.org +Message-ID: <200802191720.m1JHKBd6029869@hera.kernel.org> + +From: Heiko Carstens + +commit: d5b02b3ff1d9a2e1074f559c84ed378cfa6fc3c0 upstream + +Add missing exception table entry so that the kernel can handle +proctection exceptions as well on the cs instruction. Currently only +specification exceptions are handled correctly. +The missing entry allows user space to crash the kernel. + +Signed-off-by: Heiko Carstens +Signed-off-by: Martin Schwidefsky +Signed-off-by: Greg Kroah-Hartman + +--- + arch/s390/lib/uaccess_std.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/s390/lib/uaccess_std.c ++++ b/arch/s390/lib/uaccess_std.c +@@ -293,10 +293,10 @@ int futex_atomic_cmpxchg_std(int __user + + asm volatile( + " sacf 256\n" +- " cs %1,%4,0(%5)\n" +- "0: lr %0,%1\n" +- "1: sacf 0\n" +- EX_TABLE(0b,1b) ++ "0: cs %1,%4,0(%5)\n" ++ "1: lr %0,%1\n" ++ "2: sacf 0\n" ++ EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "=d" (ret), "+d" (oldval), "=m" (*uaddr) + : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) + : "cc", "memory" ); diff --git a/queue-2.6.24/scsi-gdth-scan-for-scsi-devices.patch b/queue-2.6.24/scsi-gdth-scan-for-scsi-devices.patch new file mode 100644 index 00000000000..c237272ab94 --- /dev/null +++ b/queue-2.6.24/scsi-gdth-scan-for-scsi-devices.patch @@ -0,0 +1,62 @@ +From stable-bounces@linux.kernel.org Thu Feb 14 13:15:25 2008 +From: Boaz Harrosh +Date: Thu, 14 Feb 2008 21:15:08 GMT +Subject: SCSI: gdth: scan for scsi devices +To: jejb@kernel.org, stable@kernel.org +Message-ID: <200802142115.m1ELF82G011611@hera.kernel.org> + + +From: Boaz Harrosh + +commit: 61c92814dc324b541391757062ff02fbf3b08086 + +The patch: "gdth: switch to modern scsi host registration" + +missed one simple fact when moving a way from scsi_module.c. +That is to call scsi_scan_host() on the probed host. +With this the gdth driver from 2.6.24 is again able to +see drives and boot. + +Signed-off-by: Boaz Harrosh +Tested-by: Joerg Dorchain +Tested-by: Stefan Priebe +Tested-by: Jon Chelton +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/gdth.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/scsi/gdth.c ++++ b/drivers/scsi/gdth.c +@@ -4838,6 +4838,9 @@ static int __init gdth_isa_probe_one(ulo + if (error) + goto out_free_coal_stat; + list_add_tail(&ha->list, &gdth_instances); ++ ++ scsi_scan_host(shp); ++ + return 0; + + out_free_coal_stat: +@@ -4965,6 +4968,9 @@ static int __init gdth_eisa_probe_one(us + if (error) + goto out_free_coal_stat; + list_add_tail(&ha->list, &gdth_instances); ++ ++ scsi_scan_host(shp); ++ + return 0; + + out_free_ccb_phys: +@@ -5102,6 +5108,9 @@ static int __init gdth_pci_probe_one(gdt + if (error) + goto out_free_coal_stat; + list_add_tail(&ha->list, &gdth_instances); ++ ++ scsi_scan_host(shp); ++ + return 0; + + out_free_coal_stat: diff --git a/queue-2.6.24/series b/queue-2.6.24/series index e413dad3fc7..e5f8f965c20 100644 --- a/queue-2.6.24/series +++ b/queue-2.6.24/series @@ -20,3 +20,17 @@ inet_diag-fix-inet_diag_lock_handler-error-path.patch inet-prevent-out-of-sync-truesize-on-ip_fragment-slow-path.patch bluetooth-add-conn-add-del-workqueues-to-avoid-connection-fail.patch audit-increase-skb-truesize-in-audit_expand.patch +be-more-robust-about-bad-arguments-in-get_user_pages.patch +disable-g5-nap-mode-during-smu-commands-on-u3.patch +hrtimer-fix-rmtp-handling-in-hrtimer_nanosleep.patch +hrtimer-fix-rmtp-restarts-handling-in-compat_sys_nanosleep.patch +slub-deal-with-annoying-gcc-warning-on-kfree.patch +hrtimer-check-relative-timeouts-for-overflow.patch +hrtimer-catch-expired-clock_realtime-timers-early.patch +genirq-do-not-leave-interupts-enabled-on-free_irq.patch +s390-fix-futex_atomic_cmpxchg_std-inline-assembly.patch +usb-fix-pm-counter-leak-in-usblp.patch +scsi-gdth-scan-for-scsi-devices.patch +kbuild-allow-fstack-protector-to-take-effect.patch +pcmcia-fix-station-address-detection-in-smc.patch +powerpc-revert-chrp_pci_fixup_vt8231_ata-devinit-to-fix-libata-on-pegasos.patch diff --git a/queue-2.6.24/slub-deal-with-annoying-gcc-warning-on-kfree.patch b/queue-2.6.24/slub-deal-with-annoying-gcc-warning-on-kfree.patch new file mode 100644 index 00000000000..f7108e08461 --- /dev/null +++ b/queue-2.6.24/slub-deal-with-annoying-gcc-warning-on-kfree.patch @@ -0,0 +1,39 @@ +From 5bb983b0cce9b7b281af15730f7019116dd42568 Mon Sep 17 00:00:00 2001 +From: Christoph Lameter +Date: Thu, 7 Feb 2008 17:47:41 -0800 +Subject: SLUB: Deal with annoying gcc warning on kfree() + +From: Christoph Lameter + +patch 5bb983b0cce9b7b281af15730f7019116dd42568 in mainline. + +gcc 4.2 spits out an annoying warning if one casts a const void * +pointer to a void * pointer. No warning is generated if the +conversion is done through an assignment. + +Signed-off-by: Christoph Lameter +Signed-off-by: Greg Kroah-Hartman + +--- + mm/slub.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2592,6 +2592,7 @@ EXPORT_SYMBOL(ksize); + void kfree(const void *x) + { + struct page *page; ++ void *object = (void *)x; + + if (unlikely(ZERO_OR_NULL_PTR(x))) + return; +@@ -2601,7 +2602,7 @@ void kfree(const void *x) + put_page(page); + return; + } +- slab_free(page->slab, page, (void *)x, __builtin_return_address(0)); ++ slab_free(page->slab, page, object, __builtin_return_address(0)); + } + EXPORT_SYMBOL(kfree); + diff --git a/queue-2.6.24/usb-fix-pm-counter-leak-in-usblp.patch b/queue-2.6.24/usb-fix-pm-counter-leak-in-usblp.patch new file mode 100644 index 00000000000..211765a2c3c --- /dev/null +++ b/queue-2.6.24/usb-fix-pm-counter-leak-in-usblp.patch @@ -0,0 +1,30 @@ +From stable-bounces@linux.kernel.org Thu Feb 21 16:35:12 2008 +From: Oliver Neukum +Date: Fri, 22 Feb 2008 00:35:05 GMT +Subject: USB: fix pm counter leak in usblp +Message-ID: <200802220035.m1M0Z5Xh015119@hera.kernel.org> + +From: Oliver Neukum + +commit 1902869019918411c148c18cc3a22aade569ac9a upstream + +if you fail in open() you must decrement the pm counter again. + +Signed-off-by: Oliver Neukum +Signed-off-by: Pete Zaitcev +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/class/usblp.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/class/usblp.c ++++ b/drivers/usb/class/usblp.c +@@ -428,6 +428,7 @@ static int usblp_open(struct inode *inod + usblp->rcomplete = 0; + + if (handle_bidir(usblp) < 0) { ++ usb_autopm_put_interface(intf); + usblp->used = 0; + file->private_data = NULL; + retval = -EIO;