Linux v3.8.3
This commit is contained in:
parent
f330a83bcb
commit
f7c0765d63
|
@ -1,127 +0,0 @@
|
|||
arch/arm/kernel/traps.c | 34 +++++++---------------------------
|
||||
arch/arm/mm/alignment.c | 11 ++++-------
|
||||
2 files changed, 11 insertions(+), 34 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
|
||||
index b0179b8..62f429e 100644
|
||||
--- a/arch/arm/kernel/traps.c
|
||||
+++ b/arch/arm/kernel/traps.c
|
||||
@@ -89,17 +89,8 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
|
||||
unsigned long top)
|
||||
{
|
||||
unsigned long first;
|
||||
- mm_segment_t fs;
|
||||
int i;
|
||||
|
||||
- /*
|
||||
- * We need to switch to kernel mode so that we can use __get_user
|
||||
- * to safely read from kernel space. Note that we now dump the
|
||||
- * code first, just in case the backtrace kills us.
|
||||
- */
|
||||
- fs = get_fs();
|
||||
- set_fs(KERNEL_DS);
|
||||
-
|
||||
printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top);
|
||||
|
||||
for (first = bottom & ~31; first < top; first += 32) {
|
||||
@@ -112,7 +103,7 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
|
||||
for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
|
||||
if (p >= bottom && p < top) {
|
||||
unsigned long val;
|
||||
- if (__get_user(val, (unsigned long *)p) == 0)
|
||||
+ if (probe_kernel_address(p, val) == 0)
|
||||
sprintf(str + i * 9, " %08lx", val);
|
||||
else
|
||||
sprintf(str + i * 9, " ????????");
|
||||
@@ -120,8 +111,6 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
|
||||
}
|
||||
printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
|
||||
}
|
||||
-
|
||||
- set_fs(fs);
|
||||
}
|
||||
|
||||
static void dump_instr(const char *lvl, struct pt_regs *regs)
|
||||
@@ -129,25 +118,18 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
|
||||
unsigned long addr = instruction_pointer(regs);
|
||||
const int thumb = thumb_mode(regs);
|
||||
const int width = thumb ? 4 : 8;
|
||||
- mm_segment_t fs;
|
||||
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
|
||||
int i;
|
||||
|
||||
- /*
|
||||
- * We need to switch to kernel mode so that we can use __get_user
|
||||
- * to safely read from kernel space. Note that we now dump the
|
||||
- * code first, just in case the backtrace kills us.
|
||||
- */
|
||||
- fs = get_fs();
|
||||
- set_fs(KERNEL_DS);
|
||||
-
|
||||
for (i = -4; i < 1 + !!thumb; i++) {
|
||||
unsigned int val, bad;
|
||||
|
||||
- if (thumb)
|
||||
- bad = __get_user(val, &((u16 *)addr)[i]);
|
||||
- else
|
||||
- bad = __get_user(val, &((u32 *)addr)[i]);
|
||||
+ if (thumb) {
|
||||
+ u16 instr;
|
||||
+ bad = probe_kernel_address(addr, instr);
|
||||
+ val = instr;
|
||||
+ } else
|
||||
+ bad = probe_kernel_address(addr, val);
|
||||
|
||||
if (!bad)
|
||||
p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
|
||||
@@ -158,8 +140,6 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
printk("%sCode: %s\n", lvl, str);
|
||||
-
|
||||
- set_fs(fs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM_UNWIND
|
||||
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
|
||||
index b9f60eb..f8f14fc 100644
|
||||
--- a/arch/arm/mm/alignment.c
|
||||
+++ b/arch/arm/mm/alignment.c
|
||||
@@ -749,7 +749,6 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
unsigned long instr = 0, instrptr;
|
||||
int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
|
||||
unsigned int type;
|
||||
- mm_segment_t fs;
|
||||
unsigned int fault;
|
||||
u16 tinstr = 0;
|
||||
int isize = 4;
|
||||
@@ -760,16 +759,15 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
|
||||
instrptr = instruction_pointer(regs);
|
||||
|
||||
- fs = get_fs();
|
||||
- set_fs(KERNEL_DS);
|
||||
if (thumb_mode(regs)) {
|
||||
- fault = __get_user(tinstr, (u16 *)(instrptr & ~1));
|
||||
+ unsigned long ptr = instrptr;
|
||||
+ fault = probe_kernel_address(ptr, tinstr);
|
||||
if (!fault) {
|
||||
if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
|
||||
IS_T32(tinstr)) {
|
||||
/* Thumb-2 32-bit */
|
||||
u16 tinst2 = 0;
|
||||
- fault = __get_user(tinst2, (u16 *)(instrptr+2));
|
||||
+ fault = probe_kernel_address(ptr + 2, tinst2);
|
||||
instr = (tinstr << 16) | tinst2;
|
||||
thumb2_32b = 1;
|
||||
} else {
|
||||
@@ -778,8 +776,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
}
|
||||
}
|
||||
} else
|
||||
- fault = __get_user(instr, (u32 *)instrptr);
|
||||
- set_fs(fs);
|
||||
+ fault = probe_kernel_address(instrptr, instr);
|
||||
|
||||
if (fault) {
|
||||
type = TYPE_FAULT;
|
|
@ -1,223 +0,0 @@
|
|||
From 9a5467bf7b6e9e02ec9c3da4e23747c05faeaac6 Mon Sep 17 00:00:00 2001
|
||||
From: Mathias Krause <minipli@googlemail.com>
|
||||
Date: Tue, 5 Feb 2013 18:19:13 +0100
|
||||
Subject: [PATCH] crypto: user - fix info leaks in report API
|
||||
|
||||
Three errors resulting in kernel memory disclosure:
|
||||
|
||||
1/ The structures used for the netlink based crypto algorithm report API
|
||||
are located on the stack. As snprintf() does not fill the remainder of
|
||||
the buffer with null bytes, those stack bytes will be disclosed to users
|
||||
of the API. Switch to strncpy() to fix this.
|
||||
|
||||
2/ crypto_report_one() does not initialize all field of struct
|
||||
crypto_user_alg. Fix this to fix the heap info leak.
|
||||
|
||||
3/ For the module name we should copy only as many bytes as
|
||||
module_name() returns -- not as much as the destination buffer could
|
||||
hold. But the current code does not and therefore copies random data
|
||||
from behind the end of the module name, as the module name is always
|
||||
shorter than CRYPTO_MAX_ALG_NAME.
|
||||
|
||||
Also switch to use strncpy() to copy the algorithm's name and
|
||||
driver_name. They are strings, after all.
|
||||
|
||||
Signed-off-by: Mathias Krause <minipli@googlemail.com>
|
||||
Cc: Steffen Klassert <steffen.klassert@secunet.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
---
|
||||
crypto/ablkcipher.c | 12 ++++++------
|
||||
crypto/aead.c | 9 ++++-----
|
||||
crypto/ahash.c | 2 +-
|
||||
crypto/blkcipher.c | 6 +++---
|
||||
crypto/crypto_user.c | 22 +++++++++++-----------
|
||||
crypto/pcompress.c | 3 +--
|
||||
crypto/rng.c | 2 +-
|
||||
crypto/shash.c | 3 ++-
|
||||
8 files changed, 29 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
|
||||
index 533de95..7d4a8d2 100644
|
||||
--- a/crypto/ablkcipher.c
|
||||
+++ b/crypto/ablkcipher.c
|
||||
@@ -388,9 +388,9 @@ static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_blkcipher rblkcipher;
|
||||
|
||||
- snprintf(rblkcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "ablkcipher");
|
||||
- snprintf(rblkcipher.geniv, CRYPTO_MAX_ALG_NAME, "%s",
|
||||
- alg->cra_ablkcipher.geniv ?: "<default>");
|
||||
+ strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type));
|
||||
+ strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<default>",
|
||||
+ sizeof(rblkcipher.geniv));
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
|
||||
@@ -469,9 +469,9 @@ static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_blkcipher rblkcipher;
|
||||
|
||||
- snprintf(rblkcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "givcipher");
|
||||
- snprintf(rblkcipher.geniv, CRYPTO_MAX_ALG_NAME, "%s",
|
||||
- alg->cra_ablkcipher.geniv ?: "<built-in>");
|
||||
+ strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type));
|
||||
+ strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "<built-in>",
|
||||
+ sizeof(rblkcipher.geniv));
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize;
|
||||
diff --git a/crypto/aead.c b/crypto/aead.c
|
||||
index 4d04e12..547491e 100644
|
||||
--- a/crypto/aead.c
|
||||
+++ b/crypto/aead.c
|
||||
@@ -117,9 +117,8 @@ static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
struct crypto_report_aead raead;
|
||||
struct aead_alg *aead = &alg->cra_aead;
|
||||
|
||||
- snprintf(raead.type, CRYPTO_MAX_ALG_NAME, "%s", "aead");
|
||||
- snprintf(raead.geniv, CRYPTO_MAX_ALG_NAME, "%s",
|
||||
- aead->geniv ?: "<built-in>");
|
||||
+ strncpy(raead.type, "aead", sizeof(raead.type));
|
||||
+ strncpy(raead.geniv, aead->geniv ?: "<built-in>", sizeof(raead.geniv));
|
||||
|
||||
raead.blocksize = alg->cra_blocksize;
|
||||
raead.maxauthsize = aead->maxauthsize;
|
||||
@@ -203,8 +202,8 @@ static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
struct crypto_report_aead raead;
|
||||
struct aead_alg *aead = &alg->cra_aead;
|
||||
|
||||
- snprintf(raead.type, CRYPTO_MAX_ALG_NAME, "%s", "nivaead");
|
||||
- snprintf(raead.geniv, CRYPTO_MAX_ALG_NAME, "%s", aead->geniv);
|
||||
+ strncpy(raead.type, "nivaead", sizeof(raead.type));
|
||||
+ strncpy(raead.geniv, aead->geniv, sizeof(raead.geniv));
|
||||
|
||||
raead.blocksize = alg->cra_blocksize;
|
||||
raead.maxauthsize = aead->maxauthsize;
|
||||
diff --git a/crypto/ahash.c b/crypto/ahash.c
|
||||
index 3887856..793a27f 100644
|
||||
--- a/crypto/ahash.c
|
||||
+++ b/crypto/ahash.c
|
||||
@@ -404,7 +404,7 @@ static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_hash rhash;
|
||||
|
||||
- snprintf(rhash.type, CRYPTO_MAX_ALG_NAME, "%s", "ahash");
|
||||
+ strncpy(rhash.type, "ahash", sizeof(rhash.type));
|
||||
|
||||
rhash.blocksize = alg->cra_blocksize;
|
||||
rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
|
||||
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
|
||||
index e9e7244..a79e7e9 100644
|
||||
--- a/crypto/blkcipher.c
|
||||
+++ b/crypto/blkcipher.c
|
||||
@@ -499,9 +499,9 @@ static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_blkcipher rblkcipher;
|
||||
|
||||
- snprintf(rblkcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "blkcipher");
|
||||
- snprintf(rblkcipher.geniv, CRYPTO_MAX_ALG_NAME, "%s",
|
||||
- alg->cra_blkcipher.geniv ?: "<default>");
|
||||
+ strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type));
|
||||
+ strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "<default>",
|
||||
+ sizeof(rblkcipher.geniv));
|
||||
|
||||
rblkcipher.blocksize = alg->cra_blocksize;
|
||||
rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
|
||||
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
|
||||
index 35d700a..f6d9baf 100644
|
||||
--- a/crypto/crypto_user.c
|
||||
+++ b/crypto/crypto_user.c
|
||||
@@ -75,7 +75,7 @@ static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_cipher rcipher;
|
||||
|
||||
- snprintf(rcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "cipher");
|
||||
+ strncpy(rcipher.type, "cipher", sizeof(rcipher.type));
|
||||
|
||||
rcipher.blocksize = alg->cra_blocksize;
|
||||
rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
|
||||
@@ -94,8 +94,7 @@ static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_comp rcomp;
|
||||
|
||||
- snprintf(rcomp.type, CRYPTO_MAX_ALG_NAME, "%s", "compression");
|
||||
-
|
||||
+ strncpy(rcomp.type, "compression", sizeof(rcomp.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
|
||||
sizeof(struct crypto_report_comp), &rcomp))
|
||||
goto nla_put_failure;
|
||||
@@ -108,12 +107,14 @@ nla_put_failure:
|
||||
static int crypto_report_one(struct crypto_alg *alg,
|
||||
struct crypto_user_alg *ualg, struct sk_buff *skb)
|
||||
{
|
||||
- memcpy(&ualg->cru_name, &alg->cra_name, sizeof(ualg->cru_name));
|
||||
- memcpy(&ualg->cru_driver_name, &alg->cra_driver_name,
|
||||
- sizeof(ualg->cru_driver_name));
|
||||
- memcpy(&ualg->cru_module_name, module_name(alg->cra_module),
|
||||
- CRYPTO_MAX_ALG_NAME);
|
||||
-
|
||||
+ strncpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
|
||||
+ strncpy(ualg->cru_driver_name, alg->cra_driver_name,
|
||||
+ sizeof(ualg->cru_driver_name));
|
||||
+ strncpy(ualg->cru_module_name, module_name(alg->cra_module),
|
||||
+ sizeof(ualg->cru_module_name));
|
||||
+
|
||||
+ ualg->cru_type = 0;
|
||||
+ ualg->cru_mask = 0;
|
||||
ualg->cru_flags = alg->cra_flags;
|
||||
ualg->cru_refcnt = atomic_read(&alg->cra_refcnt);
|
||||
|
||||
@@ -122,8 +123,7 @@ static int crypto_report_one(struct crypto_alg *alg,
|
||||
if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
|
||||
struct crypto_report_larval rl;
|
||||
|
||||
- snprintf(rl.type, CRYPTO_MAX_ALG_NAME, "%s", "larval");
|
||||
-
|
||||
+ strncpy(rl.type, "larval", sizeof(rl.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL,
|
||||
sizeof(struct crypto_report_larval), &rl))
|
||||
goto nla_put_failure;
|
||||
diff --git a/crypto/pcompress.c b/crypto/pcompress.c
|
||||
index 04e083f..7140fe7 100644
|
||||
--- a/crypto/pcompress.c
|
||||
+++ b/crypto/pcompress.c
|
||||
@@ -53,8 +53,7 @@ static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_comp rpcomp;
|
||||
|
||||
- snprintf(rpcomp.type, CRYPTO_MAX_ALG_NAME, "%s", "pcomp");
|
||||
-
|
||||
+ strncpy(rpcomp.type, "pcomp", sizeof(rpcomp.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
|
||||
sizeof(struct crypto_report_comp), &rpcomp))
|
||||
goto nla_put_failure;
|
||||
diff --git a/crypto/rng.c b/crypto/rng.c
|
||||
index f3b7894..e0a25c2 100644
|
||||
--- a/crypto/rng.c
|
||||
+++ b/crypto/rng.c
|
||||
@@ -65,7 +65,7 @@ static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_rng rrng;
|
||||
|
||||
- snprintf(rrng.type, CRYPTO_MAX_ALG_NAME, "%s", "rng");
|
||||
+ strncpy(rrng.type, "rng", sizeof(rrng.type));
|
||||
|
||||
rrng.seedsize = alg->cra_rng.seedsize;
|
||||
|
||||
diff --git a/crypto/shash.c b/crypto/shash.c
|
||||
index f426330f..929058a 100644
|
||||
--- a/crypto/shash.c
|
||||
+++ b/crypto/shash.c
|
||||
@@ -530,7 +530,8 @@ static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
struct crypto_report_hash rhash;
|
||||
struct shash_alg *salg = __crypto_shash_alg(alg);
|
||||
|
||||
- snprintf(rhash.type, CRYPTO_MAX_ALG_NAME, "%s", "shash");
|
||||
+ strncpy(rhash.type, "shash", sizeof(rhash.type));
|
||||
+
|
||||
rhash.blocksize = alg->cra_blocksize;
|
||||
rhash.digestsize = salg->digestsize;
|
||||
|
||||
--
|
||||
1.8.1.2
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
From: Ben Hutchings <ben@decadent.org.uk>
|
||||
Subject: dmi_scan: fix missing check for _DMI_ signature in smbios_present()
|
||||
|
||||
Commit 9f9c9cbb6057 ('drivers/firmware/dmi_scan.c: fetch dmi version from
|
||||
SMBIOS if it exists') hoisted the check for "_DMI_" into
|
||||
dmi_scan_machine(), which means that we don't bother to check for "_DMI_"
|
||||
at offset 16 in an SMBIOS entry. smbios_present() may also call
|
||||
dmi_present() for an address where we found "_SM_", if it failed further
|
||||
validation.
|
||||
|
||||
Check for "_DMI_" in smbios_present() before calling dmi_present().
|
||||
|
||||
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
|
||||
Reported-by: Tim McGrath <tmhikaru@gmail.com>
|
||||
Tested-by: Tim Mcgrath <tmhikaru@gmail.com>
|
||||
Cc: Zhenzhong Duan <zhenzhong.duan@oracle.com>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
---
|
||||
|
||||
drivers/firmware/dmi_scan.c | 5 ++---
|
||||
1 file changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
diff -puN drivers/firmware/dmi_scan.c~dmi_scan-fix-missing-check-for-_dmi_-signature-in-smbios_present drivers/firmware/dmi_scan.c
|
||||
--- a/drivers/firmware/dmi_scan.c~dmi_scan-fix-missing-check-for-_dmi_-signature-in-smbios_present
|
||||
+++ a/drivers/firmware/dmi_scan.c
|
||||
@@ -442,7 +442,6 @@ static int __init dmi_present(const char
|
||||
static int __init smbios_present(const char __iomem *p)
|
||||
{
|
||||
u8 buf[32];
|
||||
- int offset = 0;
|
||||
|
||||
memcpy_fromio(buf, p, 32);
|
||||
if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) {
|
||||
@@ -461,9 +460,9 @@ static int __init smbios_present(const c
|
||||
dmi_ver = 0x0206;
|
||||
break;
|
||||
}
|
||||
- offset = 16;
|
||||
+ return memcmp(p + 16, "_DMI_", 5) || dmi_present(p + 16);
|
||||
}
|
||||
- return dmi_present(buf + offset);
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
void __init dmi_scan_machine(void)
|
||||
_
|
|
@ -1,736 +0,0 @@
|
|||
From 27857f8a3240e35c61dedb88cbdbfbaabbd8ad2b Mon Sep 17 00:00:00 2001
|
||||
From: Seiji Aguchi <seiji.aguchi@hds.com>
|
||||
Date: Tue, 12 Feb 2013 12:59:07 -0800
|
||||
Subject: [PATCH 1/4] efivars: Disable external interrupt while holding
|
||||
efivars->lock
|
||||
|
||||
[Problem]
|
||||
There is a scenario which efi_pstore fails to log messages in a panic case.
|
||||
|
||||
- CPUA holds an efi_var->lock in either efivarfs parts
|
||||
or efi_pstore with interrupt enabled.
|
||||
- CPUB panics and sends IPI to CPUA in smp_send_stop().
|
||||
- CPUA stops with holding the lock.
|
||||
- CPUB kicks efi_pstore_write() via kmsg_dump(KSMG_DUMP_PANIC)
|
||||
but it returns without logging messages.
|
||||
|
||||
[Patch Description]
|
||||
This patch disables an external interruption while holding efivars->lock
|
||||
as follows.
|
||||
|
||||
In efi_pstore_write() and get_var_data(), spin_lock/spin_unlock is
|
||||
replaced by spin_lock_irqsave/spin_unlock_irqrestore because they may
|
||||
be called in an interrupt context.
|
||||
|
||||
In other functions, they are replaced by spin_lock_irq/spin_unlock_irq.
|
||||
because they are all called from a process context.
|
||||
|
||||
By applying this patch, we can avoid the problem above with
|
||||
a following senario.
|
||||
|
||||
- CPUA holds an efi_var->lock with interrupt disabled.
|
||||
- CPUB panics and sends IPI to CPUA in smp_send_stop().
|
||||
- CPUA receives the IPI after releasing the lock because it is
|
||||
disabling interrupt while holding the lock.
|
||||
- CPUB waits for one sec until CPUA releases the lock.
|
||||
- CPUB kicks efi_pstore_write() via kmsg_dump(KSMG_DUMP_PANIC)
|
||||
And it can hold the lock successfully.
|
||||
|
||||
Signed-off-by: Seiji Aguchi <seiji.aguchi@hds.com>
|
||||
Acked-by: Mike Waychison <mikew@google.com>
|
||||
Acked-by: Matt Fleming <matt.fleming@intel.com>
|
||||
Signed-off-by: Tony Luck <tony.luck@intel.com>
|
||||
---
|
||||
drivers/firmware/efivars.c | 84 ++++++++++++++++++++++++----------------------
|
||||
1 file changed, 43 insertions(+), 41 deletions(-)
|
||||
|
||||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
|
||||
index bcb201c..a9277cc 100644
|
||||
--- a/drivers/firmware/efivars.c
|
||||
+++ b/drivers/firmware/efivars.c
|
||||
@@ -406,10 +406,11 @@ static efi_status_t
|
||||
get_var_data(struct efivars *efivars, struct efi_variable *var)
|
||||
{
|
||||
efi_status_t status;
|
||||
+ unsigned long flags;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irqsave(&efivars->lock, flags);
|
||||
status = get_var_data_locked(efivars, var);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
|
||||
@@ -538,14 +539,14 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
status = efivars->ops->set_variable(new_var->VariableName,
|
||||
&new_var->VendorGuid,
|
||||
new_var->Attributes,
|
||||
new_var->DataSize,
|
||||
new_var->Data);
|
||||
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||||
@@ -714,7 +715,7 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
* amounts of memory. Pick a default size of 64K if
|
||||
* QueryVariableInfo() isn't supported by the firmware.
|
||||
*/
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
|
||||
if (!efivars->ops->query_variable_info)
|
||||
status = EFI_UNSUPPORTED;
|
||||
@@ -724,7 +725,7 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
&remaining_size, &max_size);
|
||||
}
|
||||
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
if (status != EFI_UNSUPPORTED)
|
||||
@@ -755,7 +756,7 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
* set_variable call, and removal of the variable from the efivars
|
||||
* list (in the case of an authenticated delete).
|
||||
*/
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
|
||||
status = efivars->ops->set_variable(var->var.VariableName,
|
||||
&var->var.VendorGuid,
|
||||
@@ -763,7 +764,7 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
data);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
kfree(data);
|
||||
|
||||
return efi_status_to_err(status);
|
||||
@@ -784,21 +785,21 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
NULL);
|
||||
|
||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
mutex_lock(&inode->i_mutex);
|
||||
i_size_write(inode, newdatasize + sizeof(attributes));
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
} else if (status == EFI_NOT_FOUND) {
|
||||
list_del(&var->list);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
efivar_unregister(var);
|
||||
drop_nlink(inode);
|
||||
d_delete(file->f_dentry);
|
||||
dput(file->f_dentry);
|
||||
|
||||
} else {
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
pr_warn("efivarfs: inconsistent EFI variable implementation? "
|
||||
"status = %lx\n", status);
|
||||
}
|
||||
@@ -820,11 +821,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
|
||||
void *data;
|
||||
ssize_t size = 0;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
status = efivars->ops->get_variable(var->var.VariableName,
|
||||
&var->var.VendorGuid,
|
||||
&attributes, &datasize, NULL);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
if (status != EFI_BUFFER_TOO_SMALL)
|
||||
return efi_status_to_err(status);
|
||||
@@ -834,12 +835,12 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
status = efivars->ops->get_variable(var->var.VariableName,
|
||||
&var->var.VendorGuid,
|
||||
&attributes, &datasize,
|
||||
(data + sizeof(attributes)));
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
size = efi_status_to_err(status);
|
||||
@@ -1005,9 +1006,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
|
||||
goto out;
|
||||
|
||||
kobject_uevent(&var->kobj, KOBJ_ADD);
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
list_add(&var->list, &efivars->list);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
d_instantiate(dentry, inode);
|
||||
dget(dentry);
|
||||
out:
|
||||
@@ -1024,7 +1025,7 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
struct efivars *efivars = var->efivars;
|
||||
efi_status_t status;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
|
||||
status = efivars->ops->set_variable(var->var.VariableName,
|
||||
&var->var.VendorGuid,
|
||||
@@ -1032,14 +1033,14 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
|
||||
if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) {
|
||||
list_del(&var->list);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
efivar_unregister(var);
|
||||
drop_nlink(dentry->d_inode);
|
||||
dput(dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
@@ -1184,13 +1185,13 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
/* copied by the above to local storage in the dentry. */
|
||||
kfree(name);
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
efivars->ops->get_variable(entry->var.VariableName,
|
||||
&entry->var.VendorGuid,
|
||||
&entry->var.Attributes,
|
||||
&size,
|
||||
NULL);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
inode->i_private = entry;
|
||||
@@ -1253,7 +1254,7 @@ static int efi_pstore_open(struct pstore_info *psi)
|
||||
{
|
||||
struct efivars *efivars = psi->data;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
efivars->walk_entry = list_first_entry(&efivars->list,
|
||||
struct efivar_entry, list);
|
||||
return 0;
|
||||
@@ -1263,7 +1264,7 @@ static int efi_pstore_close(struct pstore_info *psi)
|
||||
{
|
||||
struct efivars *efivars = psi->data;
|
||||
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1339,8 +1340,9 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||||
int i, ret = 0;
|
||||
u64 storage_space, remaining_space, max_variable_size;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
+ unsigned long flags;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irqsave(&efivars->lock, flags);
|
||||
|
||||
/*
|
||||
* Check if there is a space enough to log.
|
||||
@@ -1352,7 +1354,7 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||||
&remaining_space,
|
||||
&max_variable_size);
|
||||
if (status || remaining_space < size + DUMP_NAME_LEN * 2) {
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||||
*id = part;
|
||||
return -ENOSPC;
|
||||
}
|
||||
@@ -1366,7 +1368,7 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||||
efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
|
||||
size, psi->buf);
|
||||
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||||
|
||||
if (size)
|
||||
ret = efivar_create_sysfs_entry(efivars,
|
||||
@@ -1393,7 +1395,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
|
||||
sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count,
|
||||
time.tv_sec);
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
|
||||
for (i = 0; i < DUMP_NAME_LEN; i++)
|
||||
efi_name[i] = name[i];
|
||||
@@ -1437,7 +1439,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
|
||||
if (found)
|
||||
list_del(&found->list);
|
||||
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
if (found)
|
||||
efivar_unregister(found);
|
||||
@@ -1507,7 +1509,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
|
||||
/*
|
||||
* Does this variable already exist?
|
||||
@@ -1525,7 +1527,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1539,10 +1541,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||||
status);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
return -EIO;
|
||||
}
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
/* Create the entry in sysfs. Locking is not required here */
|
||||
status = efivar_create_sysfs_entry(efivars,
|
||||
@@ -1570,7 +1572,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
|
||||
/*
|
||||
* Does this variable already exist?
|
||||
@@ -1588,7 +1590,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* force the Attributes/DataSize to 0 to ensure deletion */
|
||||
@@ -1604,12 +1606,12 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
|
||||
if (status != EFI_SUCCESS) {
|
||||
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
|
||||
status);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
return -EIO;
|
||||
}
|
||||
list_del(&search_efivar->list);
|
||||
/* We need to release this lock before unregistering. */
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
efivar_unregister(search_efivar);
|
||||
|
||||
/* It's dead Jim.... */
|
||||
@@ -1724,9 +1726,9 @@ efivar_create_sysfs_entry(struct efivars *efivars,
|
||||
kfree(short_name);
|
||||
short_name = NULL;
|
||||
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
list_add(&new_efivar->list, &efivars->list);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1795,9 +1797,9 @@ void unregister_efivars(struct efivars *efivars)
|
||||
struct efivar_entry *entry, *n;
|
||||
|
||||
list_for_each_entry_safe(entry, n, &efivars->list, list) {
|
||||
- spin_lock(&efivars->lock);
|
||||
+ spin_lock_irq(&efivars->lock);
|
||||
list_del(&entry->list);
|
||||
- spin_unlock(&efivars->lock);
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
efivar_unregister(entry);
|
||||
}
|
||||
if (efivars->new_var)
|
||||
--
|
||||
1.8.1.2
|
||||
|
||||
|
||||
From 19adc04301476eaa15e035b66e92cb333223c352 Mon Sep 17 00:00:00 2001
|
||||
From: Matthew Garrett <matthew.garrett@nebula.com>
|
||||
Date: Sat, 2 Mar 2013 19:40:17 -0500
|
||||
Subject: [PATCH 2/4] efi: be more paranoid about available space when creating
|
||||
variables
|
||||
|
||||
UEFI variables are typically stored in flash. For various reasons, avaiable
|
||||
space is typically not reclaimed immediately upon the deletion of a
|
||||
variable - instead, the system will garbage collect during initialisation
|
||||
after a reboot.
|
||||
|
||||
Some systems appear to handle this garbage collection extremely poorly,
|
||||
failing if more than 50% of the system flash is in use. This can result in
|
||||
the machine refusing to boot. The safest thing to do for the moment is to
|
||||
forbid writes if they'd end up using more than half of the storage space.
|
||||
We can make this more finegrained later if we come up with a method for
|
||||
identifying the broken machines.
|
||||
|
||||
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
|
||||
---
|
||||
drivers/firmware/efivars.c | 106 +++++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 79 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
|
||||
index a9277cc..919862b 100644
|
||||
--- a/drivers/firmware/efivars.c
|
||||
+++ b/drivers/firmware/efivars.c
|
||||
@@ -419,6 +419,44 @@ get_var_data(struct efivars *efivars, struct efi_variable *var)
|
||||
return status;
|
||||
}
|
||||
|
||||
+static efi_status_t
|
||||
+check_var_size_locked(struct efivars *efivars, u32 attributes,
|
||||
+ unsigned long size)
|
||||
+{
|
||||
+ u64 storage_size, remaining_size, max_size;
|
||||
+ efi_status_t status;
|
||||
+ const struct efivar_operations *fops = efivars->ops;
|
||||
+
|
||||
+ if (!efivars->ops->query_variable_info)
|
||||
+ return EFI_UNSUPPORTED;
|
||||
+
|
||||
+ status = fops->query_variable_info(attributes, &storage_size,
|
||||
+ &remaining_size, &max_size);
|
||||
+
|
||||
+ if (status != EFI_SUCCESS)
|
||||
+ return status;
|
||||
+
|
||||
+ if (!storage_size || size > remaining_size || size > max_size ||
|
||||
+ (remaining_size - size) < (storage_size / 2))
|
||||
+ return EFI_OUT_OF_RESOURCES;
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static efi_status_t
|
||||
+check_var_size(struct efivars *efivars, u32 attributes, unsigned long size)
|
||||
+{
|
||||
+ efi_status_t status;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&efivars->lock, flags);
|
||||
+ status = check_var_size_locked(efivars, attributes, size);
|
||||
+ spin_unlock_irqrestore(&efivars->lock, flags);
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
static ssize_t
|
||||
efivar_guid_read(struct efivar_entry *entry, char *buf)
|
||||
{
|
||||
@@ -540,11 +578,16 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
|
||||
}
|
||||
|
||||
spin_lock_irq(&efivars->lock);
|
||||
- status = efivars->ops->set_variable(new_var->VariableName,
|
||||
- &new_var->VendorGuid,
|
||||
- new_var->Attributes,
|
||||
- new_var->DataSize,
|
||||
- new_var->Data);
|
||||
+
|
||||
+ status = check_var_size_locked(efivars, new_var->Attributes,
|
||||
+ new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
|
||||
+
|
||||
+ if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
|
||||
+ status = efivars->ops->set_variable(new_var->VariableName,
|
||||
+ &new_var->VendorGuid,
|
||||
+ new_var->Attributes,
|
||||
+ new_var->DataSize,
|
||||
+ new_var->Data);
|
||||
|
||||
spin_unlock_irq(&efivars->lock);
|
||||
|
||||
@@ -695,8 +738,7 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
u32 attributes;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
unsigned long datasize = count - sizeof(attributes);
|
||||
- unsigned long newdatasize;
|
||||
- u64 storage_size, remaining_size, max_size;
|
||||
+ unsigned long newdatasize, varsize;
|
||||
ssize_t bytes = 0;
|
||||
|
||||
if (count < sizeof(attributes))
|
||||
@@ -715,28 +757,18 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
* amounts of memory. Pick a default size of 64K if
|
||||
* QueryVariableInfo() isn't supported by the firmware.
|
||||
*/
|
||||
- spin_lock_irq(&efivars->lock);
|
||||
|
||||
- if (!efivars->ops->query_variable_info)
|
||||
- status = EFI_UNSUPPORTED;
|
||||
- else {
|
||||
- const struct efivar_operations *fops = efivars->ops;
|
||||
- status = fops->query_variable_info(attributes, &storage_size,
|
||||
- &remaining_size, &max_size);
|
||||
- }
|
||||
-
|
||||
- spin_unlock_irq(&efivars->lock);
|
||||
+ varsize = datasize + utf16_strsize(var->var.VariableName, 1024);
|
||||
+ status = check_var_size(efivars, attributes, varsize);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
if (status != EFI_UNSUPPORTED)
|
||||
return efi_status_to_err(status);
|
||||
|
||||
- remaining_size = 65536;
|
||||
+ if (datasize > 65536)
|
||||
+ return -ENOSPC;
|
||||
}
|
||||
|
||||
- if (datasize > remaining_size)
|
||||
- return -ENOSPC;
|
||||
-
|
||||
data = kmalloc(datasize, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
@@ -758,6 +790,19 @@ static ssize_t efivarfs_file_write(struct file *file,
|
||||
*/
|
||||
spin_lock_irq(&efivars->lock);
|
||||
|
||||
+ /*
|
||||
+ * Ensure that the available space hasn't shrunk below the safe level
|
||||
+ */
|
||||
+
|
||||
+ status = check_var_size_locked(efivars, attributes, varsize);
|
||||
+
|
||||
+ if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) {
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
+ kfree(data);
|
||||
+
|
||||
+ return efi_status_to_err(status);
|
||||
+ }
|
||||
+
|
||||
status = efivars->ops->set_variable(var->var.VariableName,
|
||||
&var->var.VendorGuid,
|
||||
attributes, datasize,
|
||||
@@ -1338,7 +1383,6 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||||
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
|
||||
struct efivars *efivars = psi->data;
|
||||
int i, ret = 0;
|
||||
- u64 storage_space, remaining_space, max_variable_size;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -1349,11 +1393,11 @@ static int efi_pstore_write(enum pstore_type_id type,
|
||||
* size: a size of logging data
|
||||
* DUMP_NAME_LEN * 2: a maximum size of variable name
|
||||
*/
|
||||
- status = efivars->ops->query_variable_info(PSTORE_EFI_ATTRIBUTES,
|
||||
- &storage_space,
|
||||
- &remaining_space,
|
||||
- &max_variable_size);
|
||||
- if (status || remaining_space < size + DUMP_NAME_LEN * 2) {
|
||||
+
|
||||
+ status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES,
|
||||
+ size + DUMP_NAME_LEN * 2);
|
||||
+
|
||||
+ if (status) {
|
||||
spin_unlock_irqrestore(&efivars->lock, flags);
|
||||
*id = part;
|
||||
return -ENOSPC;
|
||||
@@ -1531,6 +1575,14 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ status = check_var_size_locked(efivars, new_var->Attributes,
|
||||
+ new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
|
||||
+
|
||||
+ if (status && status != EFI_UNSUPPORTED) {
|
||||
+ spin_unlock_irq(&efivars->lock);
|
||||
+ return efi_status_to_err(status);
|
||||
+ }
|
||||
+
|
||||
/* now *really* create the variable via EFI */
|
||||
status = efivars->ops->set_variable(new_var->VariableName,
|
||||
&new_var->VendorGuid,
|
||||
--
|
||||
1.8.1.2
|
||||
|
||||
|
||||
From 46b6e1db3a81203deaf4615637616a0266a2e6e6 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Fleming <matt.fleming@intel.com>
|
||||
Date: Tue, 5 Mar 2013 07:40:16 +0000
|
||||
Subject: [PATCH 3/4] efivars: efivarfs_valid_name() should handle pstore
|
||||
syntax
|
||||
|
||||
Stricter validation was introduced with commit da27a24383b2b
|
||||
("efivarfs: guid part of filenames are case-insensitive") and commit
|
||||
47f531e8ba3b ("efivarfs: Validate filenames much more aggressively"),
|
||||
which is necessary for the guid portion of efivarfs filenames, but we
|
||||
don't need to be so strict with the first part, the variable name. The
|
||||
UEFI specification doesn't impose any constraints on variable names
|
||||
other than they be a NULL-terminated string.
|
||||
|
||||
The above commits caused a regression that resulted in users seeing
|
||||
the following message,
|
||||
|
||||
$ sudo mount -v /sys/firmware/efi/efivars mount: Cannot allocate memory
|
||||
|
||||
whenever pstore EFI variables were present in the variable store,
|
||||
since their variable names failed to pass the following check,
|
||||
|
||||
/* GUID should be right after the first '-' */
|
||||
if (s - 1 != strchr(str, '-'))
|
||||
|
||||
as a typical pstore filename is of the form, dump-type0-10-1-<guid>.
|
||||
The fix is trivial since the guid portion of the filename is GUID_LEN
|
||||
bytes, we can use (len - GUID_LEN) to ensure the '-' character is
|
||||
where we expect it to be.
|
||||
|
||||
(The bogus ENOMEM error value will be fixed in a separate patch.)
|
||||
|
||||
Reported-by: Joseph Yasi <joe.yasi@gmail.com>
|
||||
Reported-by: Lingzhu Xiang <lxiang@redhat.com>
|
||||
Cc: Josh Boyer <jwboyer@redhat.com>
|
||||
Cc: Jeremy Kerr <jk@ozlabs.org>
|
||||
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
|
||||
---
|
||||
drivers/firmware/efivars.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
|
||||
index 919862b..fc54ddd 100644
|
||||
--- a/drivers/firmware/efivars.c
|
||||
+++ b/drivers/firmware/efivars.c
|
||||
@@ -967,8 +967,8 @@ static bool efivarfs_valid_name(const char *str, int len)
|
||||
if (len < GUID_LEN + 2)
|
||||
return false;
|
||||
|
||||
- /* GUID should be right after the first '-' */
|
||||
- if (s - 1 != strchr(str, '-'))
|
||||
+ /* GUID must be preceded by a '-' */
|
||||
+ if (*(s - 1) != '-')
|
||||
return false;
|
||||
|
||||
/*
|
||||
--
|
||||
1.8.1.2
|
||||
|
||||
|
||||
From f751b6c973fe5a480ff12c97df4b8ac4e9a666a7 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Fleming <matt.fleming@intel.com>
|
||||
Date: Tue, 5 Mar 2013 12:46:30 +0000
|
||||
Subject: [PATCH 4/4] efivarfs: return accurate error code in
|
||||
efivarfs_fill_super()
|
||||
|
||||
Joseph was hitting a failure case when mounting efivarfs which
|
||||
resulted in an incorrect error message,
|
||||
|
||||
$ sudo mount -v /sys/firmware/efi/efivars mount: Cannot allocate memory
|
||||
|
||||
triggered when efivarfs_valid_name() returned -EINVAL.
|
||||
|
||||
Make sure we pass accurate return values up the stack if
|
||||
efivarfs_fill_super() fails to build inodes for EFI variables.
|
||||
|
||||
Reported-by: Joseph Yasi <joe.yasi@gmail.com>
|
||||
Reported-by: Lingzhu Xiang <lxiang@redhat.com>
|
||||
Cc: Josh Boyer <jwboyer@redhat.com>
|
||||
Cc: Jeremy Kerr <jk@ozlabs.org>
|
||||
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
|
||||
---
|
||||
drivers/firmware/efivars.c | 20 +++++++++++++++-----
|
||||
1 file changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
|
||||
index fc54ddd..2a2e145 100644
|
||||
--- a/drivers/firmware/efivars.c
|
||||
+++ b/drivers/firmware/efivars.c
|
||||
@@ -1156,15 +1156,22 @@ static struct dentry_operations efivarfs_d_ops = {
|
||||
|
||||
static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
|
||||
{
|
||||
+ struct dentry *d;
|
||||
struct qstr q;
|
||||
+ int err;
|
||||
|
||||
q.name = name;
|
||||
q.len = strlen(name);
|
||||
|
||||
- if (efivarfs_d_hash(NULL, NULL, &q))
|
||||
- return NULL;
|
||||
+ err = efivarfs_d_hash(NULL, NULL, &q);
|
||||
+ if (err)
|
||||
+ return ERR_PTR(err);
|
||||
+
|
||||
+ d = d_alloc(parent, &q);
|
||||
+ if (d)
|
||||
+ return d;
|
||||
|
||||
- return d_alloc(parent, &q);
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
@@ -1174,6 +1181,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
struct efivar_entry *entry, *n;
|
||||
struct efivars *efivars = &__efivars;
|
||||
char *name;
|
||||
+ int err = -ENOMEM;
|
||||
|
||||
efivarfs_sb = sb;
|
||||
|
||||
@@ -1224,8 +1232,10 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto fail_name;
|
||||
|
||||
dentry = efivarfs_alloc_dentry(root, name);
|
||||
- if (!dentry)
|
||||
+ if (IS_ERR(dentry)) {
|
||||
+ err = PTR_ERR(dentry);
|
||||
goto fail_inode;
|
||||
+ }
|
||||
|
||||
/* copied by the above to local storage in the dentry. */
|
||||
kfree(name);
|
||||
@@ -1252,7 +1262,7 @@ fail_inode:
|
||||
fail_name:
|
||||
kfree(name);
|
||||
fail:
|
||||
- return -ENOMEM;
|
||||
+ return err;
|
||||
}
|
||||
|
||||
static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
|
||||
--
|
||||
1.8.1.2
|
||||
|
44
kernel.spec
44
kernel.spec
|
@ -62,7 +62,7 @@ Summary: The Linux kernel
|
|||
# For non-released -rc kernels, this will be appended after the rcX and
|
||||
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
|
||||
#
|
||||
%global baserelease 210
|
||||
%global baserelease 201
|
||||
%global fedora_build %{baserelease}
|
||||
|
||||
# base_sublevel is the kernel version we're starting with and patching
|
||||
|
@ -74,7 +74,7 @@ Summary: The Linux kernel
|
|||
%if 0%{?released_kernel}
|
||||
|
||||
# Do we have a -stable update to apply?
|
||||
%define stable_update 2
|
||||
%define stable_update 3
|
||||
# Is it a -stable RC?
|
||||
%define stable_rc 0
|
||||
# Set rpm version accordingly
|
||||
|
@ -95,7 +95,7 @@ Summary: The Linux kernel
|
|||
# The rc snapshot level
|
||||
%define rcrev 0
|
||||
# The git snapshot level
|
||||
%define gitrev 0
|
||||
%define gitrev 100
|
||||
# Set rpm version accordingly
|
||||
%define rpmversion 3.%{upstream_sublevel}.0
|
||||
%endif
|
||||
|
@ -718,8 +718,6 @@ Patch20000: 0001-efifb-Skip-DMI-checks-if-the-bootloader-knows-what-i.patch
|
|||
Patch20001: 0002-x86-EFI-Calculate-the-EFI-framebuffer-size-instead-o.patch
|
||||
|
||||
# ARM
|
||||
# http://lists.infradead.org/pipermail/linux-arm-kernel/2012-December/137164.html
|
||||
Patch21002: arm-alignment-faults.patch
|
||||
|
||||
# ARM tegra
|
||||
Patch21004: arm-tegra-nvec-kconfig.patch
|
||||
|
@ -756,21 +754,6 @@ Patch22262: x86-mm-Fix-vmalloc_fault-oops-during-lazy-MMU-updates.patch
|
|||
#rhbz 916544
|
||||
Patch22263: 0001-drivers-crypto-nx-fix-init-race-alignmasks-and-GCM-b.patch
|
||||
|
||||
#rhbz 917984
|
||||
Patch22264: efi-fixes-3.8.patch
|
||||
|
||||
#rhbz 918512 918521
|
||||
Patch22265: crypto-user-fix-info-leaks-in-report-API.patch
|
||||
|
||||
# CVE-2013-1792 rhbz 916646,919021
|
||||
Patch22266: keys-fix-race-with-concurrent-install_user_keyrings.patch
|
||||
|
||||
#rhbz 840391
|
||||
Patch22267: logitech-dj-do-not-directly-call-hid_output_raw_report-during-probe.patch
|
||||
|
||||
#rhbz 916444
|
||||
Patch22268: dmi_scan-fix-missing-check-for-_dmi_-signature-in-smbios_present.patch
|
||||
|
||||
#CVE-2013-1828 rhbz 919315 919316
|
||||
Patch22269: net-sctp-Validate-parameter-size-for-SCTP_GET_ASSOC_.patch
|
||||
|
||||
|
@ -804,7 +787,6 @@ Patch24108: signal-always-clear-sa_restorer-on-execve.patch
|
|||
Patch24109: drm-i915-bounds-check-execbuffer-relocation-count.patch
|
||||
|
||||
#rhbz 856863 892599
|
||||
Patch24110: mac80211-Fix-crash-due-to-un-canceled-work-items.patch
|
||||
Patch24111: cfg80211-mac80211-disconnect-on-suspend.patch
|
||||
Patch24112: mac80211_fixes_for_ieee80211_do_stop_while_suspend_v3.8.patch
|
||||
|
||||
|
@ -1380,7 +1362,6 @@ ApplyPatch vmbugon-warnon.patch
|
|||
#ApplyPatch arm-tegra-nvec-kconfig.patch
|
||||
ApplyPatch arm-tegra-usb-no-reset-linux33.patch
|
||||
#ApplyPatch arm-tegra-sdhci-module-fix.patch
|
||||
ApplyPatch arm-alignment-faults.patch
|
||||
|
||||
#
|
||||
# bugfixes to drivers and filesystems
|
||||
|
@ -1522,26 +1503,11 @@ ApplyPatch x86-mm-Fix-vmalloc_fault-oops-during-lazy-MMU-updates.patch
|
|||
#rhbz 916544
|
||||
ApplyPatch 0001-drivers-crypto-nx-fix-init-race-alignmasks-and-GCM-b.patch
|
||||
|
||||
#rhbz 917984
|
||||
ApplyPatch efi-fixes-3.8.patch
|
||||
|
||||
#rhbz 918512 918521
|
||||
ApplyPatch crypto-user-fix-info-leaks-in-report-API.patch
|
||||
|
||||
ApplyPatch userns-avoid-recursion-in-put_user_ns.patch
|
||||
|
||||
#rhbz 859346
|
||||
ApplyPatch fix-destroy_conntrack-GPF.patch
|
||||
|
||||
# CVE-2013-1792 rhbz 916646,919021
|
||||
ApplyPatch keys-fix-race-with-concurrent-install_user_keyrings.patch
|
||||
|
||||
#rhbz 840391
|
||||
ApplyPatch logitech-dj-do-not-directly-call-hid_output_raw_report-during-probe.patch
|
||||
|
||||
#rhbz 916444
|
||||
ApplyPatch dmi_scan-fix-missing-check-for-_dmi_-signature-in-smbios_present.patch
|
||||
|
||||
#CVE-2013-1828 rhbz 919315 919316
|
||||
ApplyPatch net-sctp-Validate-parameter-size-for-SCTP_GET_ASSOC_.patch
|
||||
|
||||
|
@ -1576,7 +1542,6 @@ ApplyPatch signal-always-clear-sa_restorer-on-execve.patch
|
|||
ApplyPatch drm-i915-bounds-check-execbuffer-relocation-count.patch
|
||||
|
||||
#rhbz 856863 892599
|
||||
ApplyPatch mac80211-Fix-crash-due-to-un-canceled-work-items.patch
|
||||
ApplyPatch cfg80211-mac80211-disconnect-on-suspend.patch
|
||||
ApplyPatch mac80211_fixes_for_ieee80211_do_stop_while_suspend_v3.8.patch
|
||||
|
||||
|
@ -2440,6 +2405,9 @@ fi
|
|||
# ||----w |
|
||||
# || ||
|
||||
%changelog
|
||||
* Thu Mar 14 2013 Justin M. Forbes <jforbes@redhat.com> 3.8.3-201
|
||||
- Linux v3.8.3
|
||||
|
||||
* Thu Mar 14 2013 Josh Boyer <jwboyer@redhat.com>
|
||||
- Fix divide by zero on host TSC calibration failure (rhbz 859282)
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
|
||||
index 58dfe08..c5ec083 100644
|
||||
--- a/security/keys/process_keys.c
|
||||
+++ b/security/keys/process_keys.c
|
||||
@@ -57,7 +57,7 @@ int install_user_keyrings(void)
|
||||
|
||||
kenter("%p{%u}", user, uid);
|
||||
|
||||
- if (user->uid_keyring) {
|
||||
+ if (user->uid_keyring && user->session_keyring) {
|
||||
kleave(" = 0 [exist]");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
From dcd9006b1b053c7b1cebe81333261d4fd492ffeb Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Date: Tue, 05 Mar 2013 16:09:00 +0000
|
||||
Subject: HID: logitech-dj: do not directly call hid_output_raw_report() during probe
|
||||
|
||||
hid_output_raw_report() makes a direct call to usb_control_msg(). However,
|
||||
some USB3 boards have shown that the usb device is not ready during the
|
||||
.probe(). This blocks the entire usb device, and the paired mice, keyboards
|
||||
are not functional. The dmesg output is the following:
|
||||
|
||||
[ 11.912287] logitech-djreceiver 0003:046D:C52B.0003: hiddev0,hidraw0: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:14.0-2/input2
|
||||
[ 11.912537] logitech-djreceiver 0003:046D:C52B.0003: logi_dj_probe:logi_dj_recv_query_paired_devices error:-32
|
||||
[ 11.912636] logitech-djreceiver: probe of 0003:046D:C52B.0003 failed with error -32
|
||||
|
||||
Relying on the scheduled call to usbhid_submit_report() fixes the problem.
|
||||
|
||||
related bugs:
|
||||
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1072082
|
||||
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1039143
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=840391
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=49781
|
||||
|
||||
Reported-and-tested-by: Bob Bowles <bobjohnbowles@gmail.com>
|
||||
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
||||
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
|
||||
---
|
||||
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
|
||||
index 9500f2f..8758f38c 100644
|
||||
--- a/drivers/hid/hid-logitech-dj.c
|
||||
+++ b/drivers/hid/hid-logitech-dj.c
|
||||
@@ -459,19 +459,25 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
|
||||
struct dj_report *dj_report)
|
||||
{
|
||||
struct hid_device *hdev = djrcv_dev->hdev;
|
||||
- int sent_bytes;
|
||||
+ struct hid_report *report;
|
||||
+ struct hid_report_enum *output_report_enum;
|
||||
+ u8 *data = (u8 *)(&dj_report->device_index);
|
||||
+ int i;
|
||||
|
||||
- if (!hdev->hid_output_raw_report) {
|
||||
- dev_err(&hdev->dev, "%s:"
|
||||
- "hid_output_raw_report is null\n", __func__);
|
||||
+ output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
|
||||
+ report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
|
||||
+
|
||||
+ if (!report) {
|
||||
+ dev_err(&hdev->dev, "%s: unable to find dj report\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
- sent_bytes = hdev->hid_output_raw_report(hdev, (u8 *) dj_report,
|
||||
- sizeof(struct dj_report),
|
||||
- HID_OUTPUT_REPORT);
|
||||
+ for (i = 0; i < report->field[0]->report_count; i++)
|
||||
+ report->field[0]->value[i] = data[i];
|
||||
+
|
||||
+ usbhid_submit_report(hdev, report, USB_DIR_OUT);
|
||||
|
||||
- return (sent_bytes < 0) ? sent_bytes : 0;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
||||
--
|
||||
cgit v0.9.1
|
|
@ -1,67 +0,0 @@
|
|||
From 499218595a2e8296b7492af32fcca141b7b8184a Mon Sep 17 00:00:00 2001
|
||||
From: Ben Greear <greearb@candelatech.com>
|
||||
Date: Wed, 20 Feb 2013 09:41:09 -0800
|
||||
Subject: [PATCH] mac80211: Fix crash due to un-canceled work-items
|
||||
|
||||
Some mlme work structs are not cancelled on disassociation
|
||||
nor interface deletion, which leads to them running after
|
||||
the memory has been freed
|
||||
|
||||
There is not a clean way to cancel these in the disassociation
|
||||
logic because they must be canceled outside of the ifmgd->mtx
|
||||
lock, so just cancel them in mgd_stop logic that tears down
|
||||
the station.
|
||||
|
||||
This fixes the crashes we see in 3.7.9+. The crash stack
|
||||
trace itself isn't so helpful, but this warning gives
|
||||
more useful info:
|
||||
|
||||
WARNING: at /home/greearb/git/linux-3.7.dev.y/lib/debugobjects.c:261 debug_print_object+0x7c/0x8d()
|
||||
ODEBUG: free active (active state 0) object type: work_struct hint: ieee80211_sta_monitor_work+0x0/0x14 [mac80211]
|
||||
Modules linked in: [...]
|
||||
Pid: 14743, comm: iw Tainted: G C O 3.7.9+ #11
|
||||
Call Trace:
|
||||
[<ffffffff81087ef8>] warn_slowpath_common+0x80/0x98
|
||||
[<ffffffff81087fa4>] warn_slowpath_fmt+0x41/0x43
|
||||
[<ffffffff812a2608>] debug_print_object+0x7c/0x8d
|
||||
[<ffffffff812a2bca>] debug_check_no_obj_freed+0x95/0x1c3
|
||||
[<ffffffff8114cc69>] slab_free_hook+0x70/0x79
|
||||
[<ffffffff8114ea3e>] kfree+0x62/0xb7
|
||||
[<ffffffff8149f465>] netdev_release+0x39/0x3e
|
||||
[<ffffffff8136ad67>] device_release+0x52/0x8a
|
||||
[<ffffffff812937db>] kobject_release+0x121/0x158
|
||||
[<ffffffff81293612>] kobject_put+0x4c/0x50
|
||||
[<ffffffff8148f0d7>] netdev_run_todo+0x25c/0x27e
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
net/mac80211/mlme.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
|
||||
index 6044c6d..b756d29 100644
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -4319,6 +4319,17 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
+ /*
|
||||
+ * Make sure some work items will not run after this,
|
||||
+ * they will not do anything but might not have been
|
||||
+ * cancelled when disconnecting.
|
||||
+ */
|
||||
+ cancel_work_sync(&ifmgd->monitor_work);
|
||||
+ cancel_work_sync(&ifmgd->beacon_connection_loss_work);
|
||||
+ cancel_work_sync(&ifmgd->request_smps_work);
|
||||
+ cancel_work_sync(&ifmgd->csa_connection_drop_work);
|
||||
+ cancel_work_sync(&ifmgd->chswitch_work);
|
||||
+
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
if (ifmgd->assoc_data)
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
--
|
||||
1.8.1.2
|
||||
|
Loading…
Reference in New Issue