mirror of
https://github.com/Fishwaldo/build.git
synced 2025-04-15 18:41:26 +00:00
2642 lines
84 KiB
Diff
2642 lines
84 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index e55476c4aef0..8a63ca1db77a 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 3
|
|
PATCHLEVEL = 10
|
|
-SUBLEVEL = 44
|
|
+SUBLEVEL = 45
|
|
EXTRAVERSION =
|
|
NAME = TOSSUG Baby Fish
|
|
|
|
diff --git a/arch/arm/mach-at91/sysirq_mask.c b/arch/arm/mach-at91/sysirq_mask.c
|
|
index 2ba694f9626b..f8bc3511a8c8 100644
|
|
--- a/arch/arm/mach-at91/sysirq_mask.c
|
|
+++ b/arch/arm/mach-at91/sysirq_mask.c
|
|
@@ -25,24 +25,28 @@
|
|
|
|
#include "generic.h"
|
|
|
|
-#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
|
|
-#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
|
|
+#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
|
|
+#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
|
|
+#define AT91_RTC_IRQ_MASK 0x1f /* Available IRQs mask */
|
|
|
|
void __init at91_sysirq_mask_rtc(u32 rtc_base)
|
|
{
|
|
void __iomem *base;
|
|
- u32 mask;
|
|
|
|
base = ioremap(rtc_base, 64);
|
|
if (!base)
|
|
return;
|
|
|
|
- mask = readl_relaxed(base + AT91_RTC_IMR);
|
|
- if (mask) {
|
|
- pr_info("AT91: Disabling rtc irq\n");
|
|
- writel_relaxed(mask, base + AT91_RTC_IDR);
|
|
- (void)readl_relaxed(base + AT91_RTC_IMR); /* flush */
|
|
- }
|
|
+ /*
|
|
+ * sam9x5 SoCs have the following errata:
|
|
+ * "RTC: Interrupt Mask Register cannot be used
|
|
+ * Interrupt Mask Register read always returns 0."
|
|
+ *
|
|
+ * Hence we're not relying on IMR values to disable
|
|
+ * interrupts.
|
|
+ */
|
|
+ writel_relaxed(AT91_RTC_IRQ_MASK, base + AT91_RTC_IDR);
|
|
+ (void)readl_relaxed(base + AT91_RTC_IMR); /* flush */
|
|
|
|
iounmap(base);
|
|
}
|
|
diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c
|
|
index dd203e59e6fd..426345ac6f6e 100644
|
|
--- a/arch/mips/kvm/kvm_mips.c
|
|
+++ b/arch/mips/kvm/kvm_mips.c
|
|
@@ -299,7 +299,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
|
|
if (cpu_has_veic || cpu_has_vint) {
|
|
size = 0x200 + VECTORSPACING * 64;
|
|
} else {
|
|
- size = 0x200;
|
|
+ size = 0x4000;
|
|
}
|
|
|
|
/* Save Linux EBASE */
|
|
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
|
|
index fd95862c65aa..224fc0c71b8a 100644
|
|
--- a/arch/sparc/net/bpf_jit_comp.c
|
|
+++ b/arch/sparc/net/bpf_jit_comp.c
|
|
@@ -83,9 +83,9 @@ static void bpf_flush_icache(void *start_, void *end_)
|
|
#define BNE (F2(0, 2) | CONDNE)
|
|
|
|
#ifdef CONFIG_SPARC64
|
|
-#define BNE_PTR (F2(0, 1) | CONDNE | (2 << 20))
|
|
+#define BE_PTR (F2(0, 1) | CONDE | (2 << 20))
|
|
#else
|
|
-#define BNE_PTR BNE
|
|
+#define BE_PTR BE
|
|
#endif
|
|
|
|
#define SETHI(K, REG) \
|
|
@@ -600,7 +600,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
case BPF_S_ANC_IFINDEX:
|
|
emit_skb_loadptr(dev, r_A);
|
|
emit_cmpi(r_A, 0);
|
|
- emit_branch(BNE_PTR, cleanup_addr + 4);
|
|
+ emit_branch(BE_PTR, cleanup_addr + 4);
|
|
emit_nop();
|
|
emit_load32(r_A, struct net_device, ifindex, r_A);
|
|
break;
|
|
@@ -613,7 +613,7 @@ void bpf_jit_compile(struct sk_filter *fp)
|
|
case BPF_S_ANC_HATYPE:
|
|
emit_skb_loadptr(dev, r_A);
|
|
emit_cmpi(r_A, 0);
|
|
- emit_branch(BNE_PTR, cleanup_addr + 4);
|
|
+ emit_branch(BE_PTR, cleanup_addr + 4);
|
|
emit_nop();
|
|
emit_load16(r_A, struct net_device, type, r_A);
|
|
break;
|
|
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
|
|
index 61d9fed5eb31..279d093524b4 100644
|
|
--- a/arch/x86/kvm/lapic.c
|
|
+++ b/arch/x86/kvm/lapic.c
|
|
@@ -370,6 +370,8 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
|
|
|
|
static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
|
|
{
|
|
+ /* Note that we never get here with APIC virtualization enabled. */
|
|
+
|
|
if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR))
|
|
++apic->isr_count;
|
|
BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
|
|
@@ -381,12 +383,48 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
|
|
apic->highest_isr_cache = vec;
|
|
}
|
|
|
|
+static inline int apic_find_highest_isr(struct kvm_lapic *apic)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ /*
|
|
+ * Note that isr_count is always 1, and highest_isr_cache
|
|
+ * is always -1, with APIC virtualization enabled.
|
|
+ */
|
|
+ if (!apic->isr_count)
|
|
+ return -1;
|
|
+ if (likely(apic->highest_isr_cache != -1))
|
|
+ return apic->highest_isr_cache;
|
|
+
|
|
+ result = find_highest_vector(apic->regs + APIC_ISR);
|
|
+ ASSERT(result == -1 || result >= 16);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
|
|
{
|
|
- if (__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
|
|
+ struct kvm_vcpu *vcpu;
|
|
+ if (!__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
|
|
+ return;
|
|
+
|
|
+ vcpu = apic->vcpu;
|
|
+
|
|
+ /*
|
|
+ * We do get here for APIC virtualization enabled if the guest
|
|
+ * uses the Hyper-V APIC enlightenment. In this case we may need
|
|
+ * to trigger a new interrupt delivery by writing the SVI field;
|
|
+ * on the other hand isr_count and highest_isr_cache are unused
|
|
+ * and must be left alone.
|
|
+ */
|
|
+ if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
|
|
+ kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
|
|
+ apic_find_highest_isr(apic));
|
|
+ else {
|
|
--apic->isr_count;
|
|
- BUG_ON(apic->isr_count < 0);
|
|
- apic->highest_isr_cache = -1;
|
|
+ BUG_ON(apic->isr_count < 0);
|
|
+ apic->highest_isr_cache = -1;
|
|
+ }
|
|
}
|
|
|
|
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
|
|
@@ -466,22 +504,6 @@ static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
|
|
__clear_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention);
|
|
}
|
|
|
|
-static inline int apic_find_highest_isr(struct kvm_lapic *apic)
|
|
-{
|
|
- int result;
|
|
-
|
|
- /* Note that isr_count is always 1 with vid enabled */
|
|
- if (!apic->isr_count)
|
|
- return -1;
|
|
- if (likely(apic->highest_isr_cache != -1))
|
|
- return apic->highest_isr_cache;
|
|
-
|
|
- result = find_highest_vector(apic->regs + APIC_ISR);
|
|
- ASSERT(result == -1 || result >= 16);
|
|
-
|
|
- return result;
|
|
-}
|
|
-
|
|
void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr)
|
|
{
|
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
|
@@ -1619,6 +1641,8 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
|
|
int vector = kvm_apic_has_interrupt(vcpu);
|
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
|
|
|
+ /* Note that we never get here with APIC virtualization enabled. */
|
|
+
|
|
if (vector == -1)
|
|
return -1;
|
|
|
|
diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
|
|
index 1512e41cd93d..43665d0d0905 100644
|
|
--- a/crypto/crypto_user.c
|
|
+++ b/crypto/crypto_user.c
|
|
@@ -466,7 +466,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
type -= CRYPTO_MSG_BASE;
|
|
link = &crypto_dispatch[type];
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
|
|
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
|
|
index 18c5b9b16645..3165811e2407 100644
|
|
--- a/drivers/connector/cn_proc.c
|
|
+++ b/drivers/connector/cn_proc.c
|
|
@@ -369,7 +369,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
|
|
return;
|
|
|
|
/* Can only change if privileged. */
|
|
- if (!capable(CAP_NET_ADMIN)) {
|
|
+ if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
|
|
err = EPERM;
|
|
goto out;
|
|
}
|
|
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
|
|
index deb5c25305af..694173f662d1 100644
|
|
--- a/drivers/hv/hv_balloon.c
|
|
+++ b/drivers/hv/hv_balloon.c
|
|
@@ -19,6 +19,7 @@
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/kernel.h>
|
|
+#include <linux/jiffies.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/init.h>
|
|
@@ -459,6 +460,11 @@ static bool do_hot_add;
|
|
*/
|
|
static uint pressure_report_delay = 45;
|
|
|
|
+/*
|
|
+ * The last time we posted a pressure report to host.
|
|
+ */
|
|
+static unsigned long last_post_time;
|
|
+
|
|
module_param(hot_add, bool, (S_IRUGO | S_IWUSR));
|
|
MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add");
|
|
|
|
@@ -542,6 +548,7 @@ struct hv_dynmem_device {
|
|
|
|
static struct hv_dynmem_device dm_device;
|
|
|
|
+static void post_status(struct hv_dynmem_device *dm);
|
|
#ifdef CONFIG_MEMORY_HOTPLUG
|
|
|
|
static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
|
|
@@ -612,7 +619,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
|
|
* have not been "onlined" within the allowed time.
|
|
*/
|
|
wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
|
|
-
|
|
+ post_status(&dm_device);
|
|
}
|
|
|
|
return;
|
|
@@ -951,11 +958,17 @@ static void post_status(struct hv_dynmem_device *dm)
|
|
{
|
|
struct dm_status status;
|
|
struct sysinfo val;
|
|
+ unsigned long now = jiffies;
|
|
+ unsigned long last_post = last_post_time;
|
|
|
|
if (pressure_report_delay > 0) {
|
|
--pressure_report_delay;
|
|
return;
|
|
}
|
|
+
|
|
+ if (!time_after(now, (last_post_time + HZ)))
|
|
+ return;
|
|
+
|
|
si_meminfo(&val);
|
|
memset(&status, 0, sizeof(struct dm_status));
|
|
status.hdr.type = DM_STATUS_REPORT;
|
|
@@ -983,6 +996,14 @@ static void post_status(struct hv_dynmem_device *dm)
|
|
if (status.hdr.trans_id != atomic_read(&trans_id))
|
|
return;
|
|
|
|
+ /*
|
|
+ * If the last post time that we sampled has changed,
|
|
+ * we have raced, don't post the status.
|
|
+ */
|
|
+ if (last_post != last_post_time)
|
|
+ return;
|
|
+
|
|
+ last_post_time = jiffies;
|
|
vmbus_sendpacket(dm->dev->channel, &status,
|
|
sizeof(struct dm_status),
|
|
(unsigned long)NULL,
|
|
@@ -1117,7 +1138,7 @@ static void balloon_up(struct work_struct *dummy)
|
|
|
|
if (ret == -EAGAIN)
|
|
msleep(20);
|
|
-
|
|
+ post_status(&dm_device);
|
|
} while (ret == -EAGAIN);
|
|
|
|
if (ret) {
|
|
@@ -1144,8 +1165,10 @@ static void balloon_down(struct hv_dynmem_device *dm,
|
|
struct dm_unballoon_response resp;
|
|
int i;
|
|
|
|
- for (i = 0; i < range_count; i++)
|
|
+ for (i = 0; i < range_count; i++) {
|
|
free_balloon_pages(dm, &range_array[i]);
|
|
+ post_status(&dm_device);
|
|
+ }
|
|
|
|
if (req->more_pages == 1)
|
|
return;
|
|
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
|
|
index e5b88d5d3b59..14fdaf0f9d23 100644
|
|
--- a/drivers/iio/adc/at91_adc.c
|
|
+++ b/drivers/iio/adc/at91_adc.c
|
|
@@ -161,12 +161,11 @@ static int at91_adc_channel_init(struct iio_dev *idev)
|
|
return idev->num_channels;
|
|
}
|
|
|
|
-static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
|
|
+static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
|
|
struct at91_adc_trigger *triggers,
|
|
const char *trigger_name)
|
|
{
|
|
struct at91_adc_state *st = iio_priv(idev);
|
|
- u8 value = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < st->trigger_number; i++) {
|
|
@@ -179,15 +178,16 @@ static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
|
|
return -ENOMEM;
|
|
|
|
if (strcmp(trigger_name, name) == 0) {
|
|
- value = triggers[i].value;
|
|
kfree(name);
|
|
- break;
|
|
+ if (triggers[i].value == 0)
|
|
+ return -EINVAL;
|
|
+ return triggers[i].value;
|
|
}
|
|
|
|
kfree(name);
|
|
}
|
|
|
|
- return value;
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
|
|
@@ -197,14 +197,14 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
|
|
struct iio_buffer *buffer = idev->buffer;
|
|
struct at91_adc_reg_desc *reg = st->registers;
|
|
u32 status = at91_adc_readl(st, reg->trigger_register);
|
|
- u8 value;
|
|
+ int value;
|
|
u8 bit;
|
|
|
|
value = at91_adc_get_trigger_value_by_name(idev,
|
|
st->trigger_list,
|
|
idev->trig->name);
|
|
- if (value == 0)
|
|
- return -EINVAL;
|
|
+ if (value < 0)
|
|
+ return value;
|
|
|
|
if (state) {
|
|
st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
|
|
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
|
|
index 9e6da72ad823..b2b5dcbf7122 100644
|
|
--- a/drivers/iio/adc/max1363.c
|
|
+++ b/drivers/iio/adc/max1363.c
|
|
@@ -1214,8 +1214,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
|
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
|
.default_mode = s0to11,
|
|
.info = &max1238_info,
|
|
- .channels = max1238_channels,
|
|
- .num_channels = ARRAY_SIZE(max1238_channels),
|
|
+ .channels = max1038_channels,
|
|
+ .num_channels = ARRAY_SIZE(max1038_channels),
|
|
},
|
|
[max11605] = {
|
|
.bits = 8,
|
|
@@ -1224,8 +1224,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
|
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
|
.default_mode = s0to11,
|
|
.info = &max1238_info,
|
|
- .channels = max1238_channels,
|
|
- .num_channels = ARRAY_SIZE(max1238_channels),
|
|
+ .channels = max1038_channels,
|
|
+ .num_channels = ARRAY_SIZE(max1038_channels),
|
|
},
|
|
[max11606] = {
|
|
.bits = 10,
|
|
@@ -1274,8 +1274,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
|
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
|
.default_mode = s0to11,
|
|
.info = &max1238_info,
|
|
- .channels = max1238_channels,
|
|
- .num_channels = ARRAY_SIZE(max1238_channels),
|
|
+ .channels = max1138_channels,
|
|
+ .num_channels = ARRAY_SIZE(max1138_channels),
|
|
},
|
|
[max11611] = {
|
|
.bits = 10,
|
|
@@ -1284,8 +1284,8 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = {
|
|
.num_modes = ARRAY_SIZE(max1238_mode_list),
|
|
.default_mode = s0to11,
|
|
.info = &max1238_info,
|
|
- .channels = max1238_channels,
|
|
- .num_channels = ARRAY_SIZE(max1238_channels),
|
|
+ .channels = max1138_channels,
|
|
+ .num_channels = ARRAY_SIZE(max1138_channels),
|
|
},
|
|
[max11612] = {
|
|
.bits = 12,
|
|
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
|
|
index af6c320a534e..53f829004a03 100644
|
|
--- a/drivers/iio/magnetometer/ak8975.c
|
|
+++ b/drivers/iio/magnetometer/ak8975.c
|
|
@@ -276,8 +276,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
|
|
{
|
|
struct ak8975_data *data = iio_priv(indio_dev);
|
|
struct i2c_client *client = data->client;
|
|
- u16 meas_reg;
|
|
- s16 raw;
|
|
int ret;
|
|
|
|
mutex_lock(&data->lock);
|
|
@@ -322,16 +320,11 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
|
|
dev_err(&client->dev, "Read axis data fails\n");
|
|
goto exit;
|
|
}
|
|
- meas_reg = ret;
|
|
|
|
mutex_unlock(&data->lock);
|
|
|
|
- /* Endian conversion of the measured values. */
|
|
- raw = (s16) (le16_to_cpu(meas_reg));
|
|
-
|
|
/* Clamp to valid range. */
|
|
- raw = clamp_t(s16, raw, -4096, 4095);
|
|
- *val = raw;
|
|
+ *val = clamp_t(s16, ret, -4096, 4095);
|
|
return IIO_VAL_INT;
|
|
|
|
exit:
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
|
|
index 1b195fc7f411..3fb2643d05b4 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
|
|
@@ -2129,13 +2129,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
|
|
/* Allow large DMA segments, up to the firmware limit of 1 GB */
|
|
dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
|
|
|
|
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
- if (!priv) {
|
|
- err = -ENOMEM;
|
|
- goto err_release_regions;
|
|
- }
|
|
-
|
|
- dev = &priv->dev;
|
|
+ dev = pci_get_drvdata(pdev);
|
|
+ priv = mlx4_priv(dev);
|
|
dev->pdev = pdev;
|
|
INIT_LIST_HEAD(&priv->ctx_list);
|
|
spin_lock_init(&priv->ctx_lock);
|
|
@@ -2300,8 +2295,7 @@ slave_start:
|
|
mlx4_sense_init(dev);
|
|
mlx4_start_sense(dev);
|
|
|
|
- priv->pci_dev_data = pci_dev_data;
|
|
- pci_set_drvdata(pdev, dev);
|
|
+ priv->removed = 0;
|
|
|
|
return 0;
|
|
|
|
@@ -2367,84 +2361,110 @@ err_disable_pdev:
|
|
|
|
static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
{
|
|
+ struct mlx4_priv *priv;
|
|
+ struct mlx4_dev *dev;
|
|
+
|
|
printk_once(KERN_INFO "%s", mlx4_version);
|
|
|
|
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ dev = &priv->dev;
|
|
+ pci_set_drvdata(pdev, dev);
|
|
+ priv->pci_dev_data = id->driver_data;
|
|
+
|
|
return __mlx4_init_one(pdev, id->driver_data);
|
|
}
|
|
|
|
-static void mlx4_remove_one(struct pci_dev *pdev)
|
|
+static void __mlx4_remove_one(struct pci_dev *pdev)
|
|
{
|
|
struct mlx4_dev *dev = pci_get_drvdata(pdev);
|
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
|
+ int pci_dev_data;
|
|
int p;
|
|
|
|
- if (dev) {
|
|
- /* in SRIOV it is not allowed to unload the pf's
|
|
- * driver while there are alive vf's */
|
|
- if (mlx4_is_master(dev)) {
|
|
- if (mlx4_how_many_lives_vf(dev))
|
|
- printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n");
|
|
- }
|
|
- mlx4_stop_sense(dev);
|
|
- mlx4_unregister_device(dev);
|
|
+ if (priv->removed)
|
|
+ return;
|
|
|
|
- for (p = 1; p <= dev->caps.num_ports; p++) {
|
|
- mlx4_cleanup_port_info(&priv->port[p]);
|
|
- mlx4_CLOSE_PORT(dev, p);
|
|
- }
|
|
+ pci_dev_data = priv->pci_dev_data;
|
|
|
|
- if (mlx4_is_master(dev))
|
|
- mlx4_free_resource_tracker(dev,
|
|
- RES_TR_FREE_SLAVES_ONLY);
|
|
-
|
|
- mlx4_cleanup_counters_table(dev);
|
|
- mlx4_cleanup_mcg_table(dev);
|
|
- mlx4_cleanup_qp_table(dev);
|
|
- mlx4_cleanup_srq_table(dev);
|
|
- mlx4_cleanup_cq_table(dev);
|
|
- mlx4_cmd_use_polling(dev);
|
|
- mlx4_cleanup_eq_table(dev);
|
|
- mlx4_cleanup_mr_table(dev);
|
|
- mlx4_cleanup_xrcd_table(dev);
|
|
- mlx4_cleanup_pd_table(dev);
|
|
+ /* in SRIOV it is not allowed to unload the pf's
|
|
+ * driver while there are alive vf's */
|
|
+ if (mlx4_is_master(dev)) {
|
|
+ if (mlx4_how_many_lives_vf(dev))
|
|
+ printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n");
|
|
+ }
|
|
+ mlx4_stop_sense(dev);
|
|
+ mlx4_unregister_device(dev);
|
|
|
|
- if (mlx4_is_master(dev))
|
|
- mlx4_free_resource_tracker(dev,
|
|
- RES_TR_FREE_STRUCTS_ONLY);
|
|
-
|
|
- iounmap(priv->kar);
|
|
- mlx4_uar_free(dev, &priv->driver_uar);
|
|
- mlx4_cleanup_uar_table(dev);
|
|
- if (!mlx4_is_slave(dev))
|
|
- mlx4_clear_steering(dev);
|
|
- mlx4_free_eq_table(dev);
|
|
- if (mlx4_is_master(dev))
|
|
- mlx4_multi_func_cleanup(dev);
|
|
- mlx4_close_hca(dev);
|
|
- if (mlx4_is_slave(dev))
|
|
- mlx4_multi_func_cleanup(dev);
|
|
- mlx4_cmd_cleanup(dev);
|
|
-
|
|
- if (dev->flags & MLX4_FLAG_MSI_X)
|
|
- pci_disable_msix(pdev);
|
|
- if (dev->flags & MLX4_FLAG_SRIOV) {
|
|
- mlx4_warn(dev, "Disabling SR-IOV\n");
|
|
- pci_disable_sriov(pdev);
|
|
- }
|
|
+ for (p = 1; p <= dev->caps.num_ports; p++) {
|
|
+ mlx4_cleanup_port_info(&priv->port[p]);
|
|
+ mlx4_CLOSE_PORT(dev, p);
|
|
+ }
|
|
+
|
|
+ if (mlx4_is_master(dev))
|
|
+ mlx4_free_resource_tracker(dev,
|
|
+ RES_TR_FREE_SLAVES_ONLY);
|
|
+
|
|
+ mlx4_cleanup_counters_table(dev);
|
|
+ mlx4_cleanup_qp_table(dev);
|
|
+ mlx4_cleanup_srq_table(dev);
|
|
+ mlx4_cleanup_cq_table(dev);
|
|
+ mlx4_cmd_use_polling(dev);
|
|
+ mlx4_cleanup_eq_table(dev);
|
|
+ mlx4_cleanup_mcg_table(dev);
|
|
+ mlx4_cleanup_mr_table(dev);
|
|
+ mlx4_cleanup_xrcd_table(dev);
|
|
+ mlx4_cleanup_pd_table(dev);
|
|
|
|
- if (!mlx4_is_slave(dev))
|
|
- mlx4_free_ownership(dev);
|
|
+ if (mlx4_is_master(dev))
|
|
+ mlx4_free_resource_tracker(dev,
|
|
+ RES_TR_FREE_STRUCTS_ONLY);
|
|
|
|
- kfree(dev->caps.qp0_tunnel);
|
|
- kfree(dev->caps.qp0_proxy);
|
|
- kfree(dev->caps.qp1_tunnel);
|
|
- kfree(dev->caps.qp1_proxy);
|
|
+ iounmap(priv->kar);
|
|
+ mlx4_uar_free(dev, &priv->driver_uar);
|
|
+ mlx4_cleanup_uar_table(dev);
|
|
+ if (!mlx4_is_slave(dev))
|
|
+ mlx4_clear_steering(dev);
|
|
+ mlx4_free_eq_table(dev);
|
|
+ if (mlx4_is_master(dev))
|
|
+ mlx4_multi_func_cleanup(dev);
|
|
+ mlx4_close_hca(dev);
|
|
+ if (mlx4_is_slave(dev))
|
|
+ mlx4_multi_func_cleanup(dev);
|
|
+ mlx4_cmd_cleanup(dev);
|
|
|
|
- kfree(priv);
|
|
- pci_release_regions(pdev);
|
|
- pci_disable_device(pdev);
|
|
- pci_set_drvdata(pdev, NULL);
|
|
+ if (dev->flags & MLX4_FLAG_MSI_X)
|
|
+ pci_disable_msix(pdev);
|
|
+ if (dev->flags & MLX4_FLAG_SRIOV) {
|
|
+ mlx4_warn(dev, "Disabling SR-IOV\n");
|
|
+ pci_disable_sriov(pdev);
|
|
}
|
|
+
|
|
+ if (!mlx4_is_slave(dev))
|
|
+ mlx4_free_ownership(dev);
|
|
+
|
|
+ kfree(dev->caps.qp0_tunnel);
|
|
+ kfree(dev->caps.qp0_proxy);
|
|
+ kfree(dev->caps.qp1_tunnel);
|
|
+ kfree(dev->caps.qp1_proxy);
|
|
+
|
|
+ pci_release_regions(pdev);
|
|
+ pci_disable_device(pdev);
|
|
+ memset(priv, 0, sizeof(*priv));
|
|
+ priv->pci_dev_data = pci_dev_data;
|
|
+ priv->removed = 1;
|
|
+}
|
|
+
|
|
+static void mlx4_remove_one(struct pci_dev *pdev)
|
|
+{
|
|
+ struct mlx4_dev *dev = pci_get_drvdata(pdev);
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
+
|
|
+ __mlx4_remove_one(pdev);
|
|
+ kfree(priv);
|
|
+ pci_set_drvdata(pdev, NULL);
|
|
}
|
|
|
|
int mlx4_restart_one(struct pci_dev *pdev)
|
|
@@ -2454,7 +2474,7 @@ int mlx4_restart_one(struct pci_dev *pdev)
|
|
int pci_dev_data;
|
|
|
|
pci_dev_data = priv->pci_dev_data;
|
|
- mlx4_remove_one(pdev);
|
|
+ __mlx4_remove_one(pdev);
|
|
return __mlx4_init_one(pdev, pci_dev_data);
|
|
}
|
|
|
|
@@ -2509,7 +2529,7 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table);
|
|
static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
|
|
pci_channel_state_t state)
|
|
{
|
|
- mlx4_remove_one(pdev);
|
|
+ __mlx4_remove_one(pdev);
|
|
|
|
return state == pci_channel_io_perm_failure ?
|
|
PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
|
|
@@ -2517,7 +2537,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
|
|
|
|
static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
|
|
{
|
|
- int ret = __mlx4_init_one(pdev, 0);
|
|
+ struct mlx4_dev *dev = pci_get_drvdata(pdev);
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
+ int ret;
|
|
+
|
|
+ ret = __mlx4_init_one(pdev, priv->pci_dev_data);
|
|
|
|
return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
|
|
}
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
|
|
index df15bb6631cc..da4f0002fd27 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
|
|
@@ -743,6 +743,7 @@ struct mlx4_priv {
|
|
spinlock_t ctx_lock;
|
|
|
|
int pci_dev_data;
|
|
+ int removed;
|
|
|
|
struct list_head pgdir_list;
|
|
struct mutex pgdir_mutex;
|
|
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
|
|
index c12aeaee22fa..155ef4bbde91 100644
|
|
--- a/drivers/net/macvlan.c
|
|
+++ b/drivers/net/macvlan.c
|
|
@@ -961,7 +961,6 @@ static int macvlan_device_event(struct notifier_block *unused,
|
|
list_for_each_entry_safe(vlan, next, &port->vlans, list)
|
|
vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill);
|
|
unregister_netdevice_many(&list_kill);
|
|
- list_del(&list_kill);
|
|
break;
|
|
case NETDEV_PRE_TYPE_CHANGE:
|
|
/* Forbid underlaying device to change its type. */
|
|
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
|
|
index fe3fd77821bf..12222290c802 100644
|
|
--- a/drivers/net/team/team.c
|
|
+++ b/drivers/net/team/team.c
|
|
@@ -1542,6 +1542,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
|
|
* to traverse list in reverse under rcu_read_lock
|
|
*/
|
|
mutex_lock(&team->lock);
|
|
+ team->port_mtu_change_allowed = true;
|
|
list_for_each_entry(port, &team->port_list, list) {
|
|
err = dev_set_mtu(port->dev, new_mtu);
|
|
if (err) {
|
|
@@ -1550,6 +1551,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
|
|
goto unwind;
|
|
}
|
|
}
|
|
+ team->port_mtu_change_allowed = false;
|
|
mutex_unlock(&team->lock);
|
|
|
|
dev->mtu = new_mtu;
|
|
@@ -1559,6 +1561,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
|
|
unwind:
|
|
list_for_each_entry_continue_reverse(port, &team->port_list, list)
|
|
dev_set_mtu(port->dev, dev->mtu);
|
|
+ team->port_mtu_change_allowed = false;
|
|
mutex_unlock(&team->lock);
|
|
|
|
return err;
|
|
@@ -2678,7 +2681,9 @@ static int team_device_event(struct notifier_block *unused,
|
|
break;
|
|
case NETDEV_CHANGEMTU:
|
|
/* Forbid to change mtu of underlaying device */
|
|
- return NOTIFY_BAD;
|
|
+ if (!port->team->port_mtu_change_allowed)
|
|
+ return NOTIFY_BAD;
|
|
+ break;
|
|
case NETDEV_PRE_TYPE_CHANGE:
|
|
/* Forbid to change type of underlaying device */
|
|
return NOTIFY_BAD;
|
|
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
|
index 7be4860ccfd7..6fb0082b3308 100644
|
|
--- a/drivers/net/usb/qmi_wwan.c
|
|
+++ b/drivers/net/usb/qmi_wwan.c
|
|
@@ -739,7 +739,12 @@ static const struct usb_device_id products[] = {
|
|
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
|
|
{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
|
|
{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */
|
|
- {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */
|
|
+ {QMI_FIXED_INTF(0x0b3c, 0xc000, 4)}, /* Olivetti Olicard 100 */
|
|
+ {QMI_FIXED_INTF(0x0b3c, 0xc001, 4)}, /* Olivetti Olicard 120 */
|
|
+ {QMI_FIXED_INTF(0x0b3c, 0xc002, 4)}, /* Olivetti Olicard 140 */
|
|
+ {QMI_FIXED_INTF(0x0b3c, 0xc004, 6)}, /* Olivetti Olicard 155 */
|
|
+ {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */
|
|
+ {QMI_FIXED_INTF(0x0b3c, 0xc00a, 6)}, /* Olivetti Olicard 160 */
|
|
{QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)}, /* Olivetti Olicard 500 */
|
|
{QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */
|
|
{QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */
|
|
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
|
|
index 9673edfff451..fcbd4eee52cc 100644
|
|
--- a/drivers/net/vxlan.c
|
|
+++ b/drivers/net/vxlan.c
|
|
@@ -1314,7 +1314,7 @@ static void vxlan_setup(struct net_device *dev)
|
|
|
|
eth_hw_addr_random(dev);
|
|
ether_setup(dev);
|
|
- dev->hard_header_len = ETH_HLEN + VXLAN_HEADROOM;
|
|
+ dev->needed_headroom = ETH_HLEN + VXLAN_HEADROOM;
|
|
|
|
dev->netdev_ops = &vxlan_netdev_ops;
|
|
dev->destructor = vxlan_free;
|
|
@@ -1454,7 +1454,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
|
|
dev->mtu = lowerdev->mtu - VXLAN_HEADROOM;
|
|
|
|
/* update header length based on lower device */
|
|
- dev->hard_header_len = lowerdev->hard_header_len +
|
|
+ dev->needed_headroom = lowerdev->hard_header_len +
|
|
VXLAN_HEADROOM;
|
|
}
|
|
|
|
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
|
|
index 1237c2173c6d..e51cc5fec98a 100644
|
|
--- a/drivers/rtc/rtc-at91rm9200.c
|
|
+++ b/drivers/rtc/rtc-at91rm9200.c
|
|
@@ -49,6 +49,7 @@ struct at91_rtc_config {
|
|
|
|
static const struct at91_rtc_config *at91_rtc_config;
|
|
static DECLARE_COMPLETION(at91_rtc_updated);
|
|
+static DECLARE_COMPLETION(at91_rtc_upd_rdy);
|
|
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
|
|
static void __iomem *at91_rtc_regs;
|
|
static int irq;
|
|
@@ -162,6 +163,8 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
|
|
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
|
|
+ wait_for_completion(&at91_rtc_upd_rdy);
|
|
+
|
|
/* Stop Time/Calendar from counting */
|
|
cr = at91_rtc_read(AT91_RTC_CR);
|
|
at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
|
|
@@ -184,7 +187,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
|
|
|
|
/* Restart Time/Calendar */
|
|
cr = at91_rtc_read(AT91_RTC_CR);
|
|
+ at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_SECEV);
|
|
at91_rtc_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
|
|
+ at91_rtc_write_ier(AT91_RTC_SECEV);
|
|
|
|
return 0;
|
|
}
|
|
@@ -291,8 +296,10 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
|
|
if (rtsr) { /* this interrupt is shared! Is it ours? */
|
|
if (rtsr & AT91_RTC_ALARM)
|
|
events |= (RTC_AF | RTC_IRQF);
|
|
- if (rtsr & AT91_RTC_SECEV)
|
|
- events |= (RTC_UF | RTC_IRQF);
|
|
+ if (rtsr & AT91_RTC_SECEV) {
|
|
+ complete(&at91_rtc_upd_rdy);
|
|
+ at91_rtc_write_idr(AT91_RTC_SECEV);
|
|
+ }
|
|
if (rtsr & AT91_RTC_ACKUPD)
|
|
complete(&at91_rtc_updated);
|
|
|
|
@@ -415,6 +422,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
|
}
|
|
platform_set_drvdata(pdev, rtc);
|
|
|
|
+ /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
|
|
+ * completion.
|
|
+ */
|
|
+ at91_rtc_write_ier(AT91_RTC_SECEV);
|
|
+
|
|
dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
|
|
return 0;
|
|
|
|
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
|
|
index fe30ea94ffe6..109802f776ed 100644
|
|
--- a/drivers/scsi/scsi_netlink.c
|
|
+++ b/drivers/scsi/scsi_netlink.c
|
|
@@ -77,7 +77,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
|
|
goto next_msg;
|
|
}
|
|
|
|
- if (!capable(CAP_SYS_ADMIN)) {
|
|
+ if (!netlink_capable(skb, CAP_SYS_ADMIN)) {
|
|
err = -EPERM;
|
|
goto next_msg;
|
|
}
|
|
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
|
|
index c99f890cc6c6..64c73adfa3b0 100644
|
|
--- a/drivers/staging/iio/light/tsl2x7x_core.c
|
|
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
|
|
@@ -672,9 +672,13 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
|
|
chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
|
|
chip->tsl2x7x_settings.prox_pulse_count;
|
|
chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
|
|
- chip->tsl2x7x_settings.prox_thres_low;
|
|
+ (chip->tsl2x7x_settings.prox_thres_low) & 0xFF;
|
|
+ chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] =
|
|
+ (chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF;
|
|
chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
|
|
- chip->tsl2x7x_settings.prox_thres_high;
|
|
+ (chip->tsl2x7x_settings.prox_thres_high) & 0xFF;
|
|
+ chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] =
|
|
+ (chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF;
|
|
|
|
/* and make sure we're not already on */
|
|
if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
|
|
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
|
|
index 130a1e4f96a1..3c9a8dfd1c2e 100644
|
|
--- a/drivers/target/iscsi/iscsi_target_auth.c
|
|
+++ b/drivers/target/iscsi/iscsi_target_auth.c
|
|
@@ -316,6 +316,16 @@ static int chap_server_compute_md5(
|
|
goto out;
|
|
}
|
|
/*
|
|
+ * During mutual authentication, the CHAP_C generated by the
|
|
+ * initiator must not match the original CHAP_C generated by
|
|
+ * the target.
|
|
+ */
|
|
+ if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) {
|
|
+ pr_err("initiator CHAP_C matches target CHAP_C, failing"
|
|
+ " login attempt\n");
|
|
+ goto out;
|
|
+ }
|
|
+ /*
|
|
* Generate CHAP_N and CHAP_R for mutual authentication.
|
|
*/
|
|
tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
|
|
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
|
|
index 89cce1a32059..fbf3f11aed2c 100644
|
|
--- a/drivers/usb/class/cdc-acm.c
|
|
+++ b/drivers/usb/class/cdc-acm.c
|
|
@@ -122,13 +122,23 @@ static void acm_release_minor(struct acm *acm)
|
|
static int acm_ctrl_msg(struct acm *acm, int request, int value,
|
|
void *buf, int len)
|
|
{
|
|
- int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
|
|
+ int retval;
|
|
+
|
|
+ retval = usb_autopm_get_interface(acm->control);
|
|
+ if (retval)
|
|
+ return retval;
|
|
+
|
|
+ retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
|
|
request, USB_RT_ACM, value,
|
|
acm->control->altsetting[0].desc.bInterfaceNumber,
|
|
buf, len, 5000);
|
|
+
|
|
dev_dbg(&acm->control->dev,
|
|
"%s - rq 0x%02x, val %#x, len %#x, result %d\n",
|
|
__func__, request, value, len, retval);
|
|
+
|
|
+ usb_autopm_put_interface(acm->control);
|
|
+
|
|
return retval < 0 ? retval : 0;
|
|
}
|
|
|
|
@@ -233,12 +243,9 @@ static int acm_write_start(struct acm *acm, int wbn)
|
|
acm->susp_count);
|
|
usb_autopm_get_interface_async(acm->control);
|
|
if (acm->susp_count) {
|
|
- if (!acm->delayed_wb)
|
|
- acm->delayed_wb = wb;
|
|
- else
|
|
- usb_autopm_put_interface_async(acm->control);
|
|
+ usb_anchor_urb(wb->urb, &acm->delayed);
|
|
spin_unlock_irqrestore(&acm->write_lock, flags);
|
|
- return 0; /* A white lie */
|
|
+ return 0;
|
|
}
|
|
usb_mark_last_busy(acm->dev);
|
|
|
|
@@ -516,6 +523,7 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
|
|
{
|
|
struct acm *acm = container_of(port, struct acm, port);
|
|
int retval = -ENODEV;
|
|
+ int i;
|
|
|
|
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
|
|
|
@@ -564,6 +572,8 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
|
|
return 0;
|
|
|
|
error_submit_read_urbs:
|
|
+ for (i = 0; i < acm->rx_buflimit; i++)
|
|
+ usb_kill_urb(acm->read_urbs[i]);
|
|
acm->ctrlout = 0;
|
|
acm_set_control(acm, acm->ctrlout);
|
|
error_set_control:
|
|
@@ -591,21 +601,35 @@ static void acm_port_destruct(struct tty_port *port)
|
|
static void acm_port_shutdown(struct tty_port *port)
|
|
{
|
|
struct acm *acm = container_of(port, struct acm, port);
|
|
+ struct urb *urb;
|
|
+ struct acm_wb *wb;
|
|
int i;
|
|
+ int pm_err;
|
|
|
|
dev_dbg(&acm->control->dev, "%s\n", __func__);
|
|
|
|
mutex_lock(&acm->mutex);
|
|
if (!acm->disconnected) {
|
|
- usb_autopm_get_interface(acm->control);
|
|
+ pm_err = usb_autopm_get_interface(acm->control);
|
|
acm_set_control(acm, acm->ctrlout = 0);
|
|
+
|
|
+ for (;;) {
|
|
+ urb = usb_get_from_anchor(&acm->delayed);
|
|
+ if (!urb)
|
|
+ break;
|
|
+ wb = urb->context;
|
|
+ wb->use = 0;
|
|
+ usb_autopm_put_interface_async(acm->control);
|
|
+ }
|
|
+
|
|
usb_kill_urb(acm->ctrlurb);
|
|
for (i = 0; i < ACM_NW; i++)
|
|
usb_kill_urb(acm->wb[i].urb);
|
|
for (i = 0; i < acm->rx_buflimit; i++)
|
|
usb_kill_urb(acm->read_urbs[i]);
|
|
acm->control->needs_remote_wakeup = 0;
|
|
- usb_autopm_put_interface(acm->control);
|
|
+ if (!pm_err)
|
|
+ usb_autopm_put_interface(acm->control);
|
|
}
|
|
mutex_unlock(&acm->mutex);
|
|
}
|
|
@@ -1190,6 +1214,7 @@ made_compressed_probe:
|
|
acm->bInterval = epread->bInterval;
|
|
tty_port_init(&acm->port);
|
|
acm->port.ops = &acm_port_ops;
|
|
+ init_usb_anchor(&acm->delayed);
|
|
|
|
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
|
if (!buf) {
|
|
@@ -1434,18 +1459,15 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
|
struct acm *acm = usb_get_intfdata(intf);
|
|
int cnt;
|
|
|
|
+ spin_lock_irq(&acm->read_lock);
|
|
+ spin_lock(&acm->write_lock);
|
|
if (PMSG_IS_AUTO(message)) {
|
|
- int b;
|
|
-
|
|
- spin_lock_irq(&acm->write_lock);
|
|
- b = acm->transmitting;
|
|
- spin_unlock_irq(&acm->write_lock);
|
|
- if (b)
|
|
+ if (acm->transmitting) {
|
|
+ spin_unlock(&acm->write_lock);
|
|
+ spin_unlock_irq(&acm->read_lock);
|
|
return -EBUSY;
|
|
+ }
|
|
}
|
|
-
|
|
- spin_lock_irq(&acm->read_lock);
|
|
- spin_lock(&acm->write_lock);
|
|
cnt = acm->susp_count++;
|
|
spin_unlock(&acm->write_lock);
|
|
spin_unlock_irq(&acm->read_lock);
|
|
@@ -1453,8 +1475,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
|
if (cnt)
|
|
return 0;
|
|
|
|
- if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
|
|
- stop_data_traffic(acm);
|
|
+ stop_data_traffic(acm);
|
|
|
|
return 0;
|
|
}
|
|
@@ -1462,29 +1483,24 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
|
|
static int acm_resume(struct usb_interface *intf)
|
|
{
|
|
struct acm *acm = usb_get_intfdata(intf);
|
|
- struct acm_wb *wb;
|
|
+ struct urb *urb;
|
|
int rv = 0;
|
|
- int cnt;
|
|
|
|
spin_lock_irq(&acm->read_lock);
|
|
- acm->susp_count -= 1;
|
|
- cnt = acm->susp_count;
|
|
- spin_unlock_irq(&acm->read_lock);
|
|
+ spin_lock(&acm->write_lock);
|
|
|
|
- if (cnt)
|
|
- return 0;
|
|
+ if (--acm->susp_count)
|
|
+ goto out;
|
|
|
|
if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
|
|
- rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
|
|
-
|
|
- spin_lock_irq(&acm->write_lock);
|
|
- if (acm->delayed_wb) {
|
|
- wb = acm->delayed_wb;
|
|
- acm->delayed_wb = NULL;
|
|
- spin_unlock_irq(&acm->write_lock);
|
|
- acm_start_wb(acm, wb);
|
|
- } else {
|
|
- spin_unlock_irq(&acm->write_lock);
|
|
+ rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
|
|
+
|
|
+ for (;;) {
|
|
+ urb = usb_get_from_anchor(&acm->delayed);
|
|
+ if (!urb)
|
|
+ break;
|
|
+
|
|
+ acm_start_wb(acm, urb->context);
|
|
}
|
|
|
|
/*
|
|
@@ -1492,12 +1508,14 @@ static int acm_resume(struct usb_interface *intf)
|
|
* do the write path at all cost
|
|
*/
|
|
if (rv < 0)
|
|
- goto err_out;
|
|
+ goto out;
|
|
|
|
- rv = acm_submit_read_urbs(acm, GFP_NOIO);
|
|
+ rv = acm_submit_read_urbs(acm, GFP_ATOMIC);
|
|
}
|
|
+out:
|
|
+ spin_unlock(&acm->write_lock);
|
|
+ spin_unlock_irq(&acm->read_lock);
|
|
|
|
-err_out:
|
|
return rv;
|
|
}
|
|
|
|
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
|
|
index 0f76e4af600e..1683ac161cf6 100644
|
|
--- a/drivers/usb/class/cdc-acm.h
|
|
+++ b/drivers/usb/class/cdc-acm.h
|
|
@@ -117,7 +117,7 @@ struct acm {
|
|
unsigned int throttled:1; /* actually throttled */
|
|
unsigned int throttle_req:1; /* throttle requested */
|
|
u8 bInterval;
|
|
- struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
|
|
+ struct usb_anchor delayed; /* writes queued for a device about to be woken */
|
|
};
|
|
|
|
#define CDC_DATA_INTERFACE_TYPE 0x0a
|
|
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
|
|
index 16fae6436d0e..25b8b15197b0 100644
|
|
--- a/include/linux/if_team.h
|
|
+++ b/include/linux/if_team.h
|
|
@@ -193,6 +193,7 @@ struct team {
|
|
bool user_carrier_enabled;
|
|
bool queue_override_enabled;
|
|
struct list_head *qom_lists; /* array of queue override mapping lists */
|
|
+ bool port_mtu_change_allowed;
|
|
long mode_priv[TEAM_MODE_PRIV_LONGS];
|
|
};
|
|
|
|
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
|
|
index 6358da5eeee8..9516dad45109 100644
|
|
--- a/include/linux/netlink.h
|
|
+++ b/include/linux/netlink.h
|
|
@@ -16,9 +16,10 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
|
|
}
|
|
|
|
enum netlink_skb_flags {
|
|
- NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */
|
|
- NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */
|
|
- NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */
|
|
+ NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */
|
|
+ NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */
|
|
+ NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */
|
|
+ NETLINK_SKB_DST = 0x8, /* Dst set in sendto or sendmsg */
|
|
};
|
|
|
|
struct netlink_skb_parms {
|
|
@@ -144,4 +145,11 @@ static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
|
return __netlink_dump_start(ssk, skb, nlh, control);
|
|
}
|
|
|
|
+bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
|
|
+ struct user_namespace *ns, int cap);
|
|
+bool netlink_ns_capable(const struct sk_buff *skb,
|
|
+ struct user_namespace *ns, int cap);
|
|
+bool netlink_capable(const struct sk_buff *skb, int cap);
|
|
+bool netlink_net_capable(const struct sk_buff *skb, int cap);
|
|
+
|
|
#endif /* __LINUX_NETLINK_H */
|
|
diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
|
|
index 302ab805b0bb..46cca4c06848 100644
|
|
--- a/include/linux/sock_diag.h
|
|
+++ b/include/linux/sock_diag.h
|
|
@@ -23,7 +23,7 @@ int sock_diag_check_cookie(void *sk, __u32 *cookie);
|
|
void sock_diag_save_cookie(void *sk, __u32 *cookie);
|
|
|
|
int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr);
|
|
-int sock_diag_put_filterinfo(struct sock *sk,
|
|
+int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
|
|
struct sk_buff *skb, int attrtype);
|
|
|
|
#endif
|
|
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
|
|
index 53f464d7cddc..6ca347a0717e 100644
|
|
--- a/include/net/inetpeer.h
|
|
+++ b/include/net/inetpeer.h
|
|
@@ -178,16 +178,9 @@ static inline void inet_peer_refcheck(const struct inet_peer *p)
|
|
/* can be called with or without local BH being disabled */
|
|
static inline int inet_getid(struct inet_peer *p, int more)
|
|
{
|
|
- int old, new;
|
|
more++;
|
|
inet_peer_refcheck(p);
|
|
- do {
|
|
- old = atomic_read(&p->ip_id_count);
|
|
- new = old + more;
|
|
- if (!new)
|
|
- new = 1;
|
|
- } while (atomic_cmpxchg(&p->ip_id_count, old, new) != old);
|
|
- return new;
|
|
+ return atomic_add_return(more, &p->ip_id_count) - more;
|
|
}
|
|
|
|
#endif /* _NET_INETPEER_H */
|
|
diff --git a/include/net/sock.h b/include/net/sock.h
|
|
index 8f32b779bc83..72f710d2f75a 100644
|
|
--- a/include/net/sock.h
|
|
+++ b/include/net/sock.h
|
|
@@ -2248,6 +2248,11 @@ extern void sock_enable_timestamp(struct sock *sk, int flag);
|
|
extern int sock_get_timestamp(struct sock *, struct timeval __user *);
|
|
extern int sock_get_timestampns(struct sock *, struct timespec __user *);
|
|
|
|
+bool sk_ns_capable(const struct sock *sk,
|
|
+ struct user_namespace *user_ns, int cap);
|
|
+bool sk_capable(const struct sock *sk, int cap);
|
|
+bool sk_net_capable(const struct sock *sk, int cap);
|
|
+
|
|
/*
|
|
* Enable debug/info messages
|
|
*/
|
|
diff --git a/include/sound/core.h b/include/sound/core.h
|
|
index 5bfe5136441c..97cd9c3592f7 100644
|
|
--- a/include/sound/core.h
|
|
+++ b/include/sound/core.h
|
|
@@ -120,6 +120,8 @@ struct snd_card {
|
|
int user_ctl_count; /* count of all user controls */
|
|
struct list_head controls; /* all controls for this card */
|
|
struct list_head ctl_files; /* active control files */
|
|
+ struct mutex user_ctl_lock; /* protects user controls against
|
|
+ concurrent access */
|
|
|
|
struct snd_info_entry *proc_root; /* root for soundcard specific files */
|
|
struct snd_info_entry *proc_id; /* the card id */
|
|
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
|
|
index 5759810e1c1b..21eed488783f 100644
|
|
--- a/include/uapi/sound/compress_offload.h
|
|
+++ b/include/uapi/sound/compress_offload.h
|
|
@@ -80,7 +80,7 @@ struct snd_compr_tstamp {
|
|
struct snd_compr_avail {
|
|
__u64 avail;
|
|
struct snd_compr_tstamp tstamp;
|
|
-};
|
|
+} __attribute__((packed));
|
|
|
|
enum snd_compr_direction {
|
|
SND_COMPRESS_PLAYBACK = 0,
|
|
diff --git a/kernel/audit.c b/kernel/audit.c
|
|
index 6def25f1b351..a6c632757e57 100644
|
|
--- a/kernel/audit.c
|
|
+++ b/kernel/audit.c
|
|
@@ -593,13 +593,13 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
|
|
case AUDIT_TTY_SET:
|
|
case AUDIT_TRIM:
|
|
case AUDIT_MAKE_EQUIV:
|
|
- if (!capable(CAP_AUDIT_CONTROL))
|
|
+ if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
|
|
err = -EPERM;
|
|
break;
|
|
case AUDIT_USER:
|
|
case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
|
|
case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
|
|
- if (!capable(CAP_AUDIT_WRITE))
|
|
+ if (!netlink_capable(skb, CAP_AUDIT_WRITE))
|
|
err = -EPERM;
|
|
break;
|
|
default: /* bad msg */
|
|
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
|
|
index 4251374578bc..67f7a2d2efbc 100644
|
|
--- a/kernel/time/tick-sched.c
|
|
+++ b/kernel/time/tick-sched.c
|
|
@@ -720,8 +720,10 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
|
|
return false;
|
|
}
|
|
|
|
- if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
|
|
+ if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) {
|
|
+ ts->sleep_length = (ktime_t) { .tv64 = NSEC_PER_SEC/HZ };
|
|
return false;
|
|
+ }
|
|
|
|
if (need_resched())
|
|
return false;
|
|
diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c
|
|
index 569985d522d5..8563081e8da3 100644
|
|
--- a/lib/lzo/lzo1x_decompress_safe.c
|
|
+++ b/lib/lzo/lzo1x_decompress_safe.c
|
|
@@ -19,11 +19,31 @@
|
|
#include <linux/lzo.h>
|
|
#include "lzodefs.h"
|
|
|
|
-#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x))
|
|
-#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
|
|
-#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun
|
|
-#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
|
|
-#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
|
|
+#define HAVE_IP(t, x) \
|
|
+ (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \
|
|
+ (((t + x) >= t) && ((t + x) >= x)))
|
|
+
|
|
+#define HAVE_OP(t, x) \
|
|
+ (((size_t)(op_end - op) >= (size_t)(t + x)) && \
|
|
+ (((t + x) >= t) && ((t + x) >= x)))
|
|
+
|
|
+#define NEED_IP(t, x) \
|
|
+ do { \
|
|
+ if (!HAVE_IP(t, x)) \
|
|
+ goto input_overrun; \
|
|
+ } while (0)
|
|
+
|
|
+#define NEED_OP(t, x) \
|
|
+ do { \
|
|
+ if (!HAVE_OP(t, x)) \
|
|
+ goto output_overrun; \
|
|
+ } while (0)
|
|
+
|
|
+#define TEST_LB(m_pos) \
|
|
+ do { \
|
|
+ if ((m_pos) < out) \
|
|
+ goto lookbehind_overrun; \
|
|
+ } while (0)
|
|
|
|
int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
|
unsigned char *out, size_t *out_len)
|
|
@@ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
|
|
while (unlikely(*ip == 0)) {
|
|
t += 255;
|
|
ip++;
|
|
- NEED_IP(1);
|
|
+ NEED_IP(1, 0);
|
|
}
|
|
t += 15 + *ip++;
|
|
}
|
|
t += 3;
|
|
copy_literal_run:
|
|
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
|
- if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
|
|
+ if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) {
|
|
const unsigned char *ie = ip + t;
|
|
unsigned char *oe = op + t;
|
|
do {
|
|
@@ -81,8 +101,8 @@ copy_literal_run:
|
|
} else
|
|
#endif
|
|
{
|
|
- NEED_OP(t);
|
|
- NEED_IP(t + 3);
|
|
+ NEED_OP(t, 0);
|
|
+ NEED_IP(t, 3);
|
|
do {
|
|
*op++ = *ip++;
|
|
} while (--t > 0);
|
|
@@ -95,7 +115,7 @@ copy_literal_run:
|
|
m_pos -= t >> 2;
|
|
m_pos -= *ip++ << 2;
|
|
TEST_LB(m_pos);
|
|
- NEED_OP(2);
|
|
+ NEED_OP(2, 0);
|
|
op[0] = m_pos[0];
|
|
op[1] = m_pos[1];
|
|
op += 2;
|
|
@@ -119,10 +139,10 @@ copy_literal_run:
|
|
while (unlikely(*ip == 0)) {
|
|
t += 255;
|
|
ip++;
|
|
- NEED_IP(1);
|
|
+ NEED_IP(1, 0);
|
|
}
|
|
t += 31 + *ip++;
|
|
- NEED_IP(2);
|
|
+ NEED_IP(2, 0);
|
|
}
|
|
m_pos = op - 1;
|
|
next = get_unaligned_le16(ip);
|
|
@@ -137,10 +157,10 @@ copy_literal_run:
|
|
while (unlikely(*ip == 0)) {
|
|
t += 255;
|
|
ip++;
|
|
- NEED_IP(1);
|
|
+ NEED_IP(1, 0);
|
|
}
|
|
t += 7 + *ip++;
|
|
- NEED_IP(2);
|
|
+ NEED_IP(2, 0);
|
|
}
|
|
next = get_unaligned_le16(ip);
|
|
ip += 2;
|
|
@@ -154,7 +174,7 @@ copy_literal_run:
|
|
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
|
if (op - m_pos >= 8) {
|
|
unsigned char *oe = op + t;
|
|
- if (likely(HAVE_OP(t + 15))) {
|
|
+ if (likely(HAVE_OP(t, 15))) {
|
|
do {
|
|
COPY8(op, m_pos);
|
|
op += 8;
|
|
@@ -164,7 +184,7 @@ copy_literal_run:
|
|
m_pos += 8;
|
|
} while (op < oe);
|
|
op = oe;
|
|
- if (HAVE_IP(6)) {
|
|
+ if (HAVE_IP(6, 0)) {
|
|
state = next;
|
|
COPY4(op, ip);
|
|
op += next;
|
|
@@ -172,7 +192,7 @@ copy_literal_run:
|
|
continue;
|
|
}
|
|
} else {
|
|
- NEED_OP(t);
|
|
+ NEED_OP(t, 0);
|
|
do {
|
|
*op++ = *m_pos++;
|
|
} while (op < oe);
|
|
@@ -181,7 +201,7 @@ copy_literal_run:
|
|
#endif
|
|
{
|
|
unsigned char *oe = op + t;
|
|
- NEED_OP(t);
|
|
+ NEED_OP(t, 0);
|
|
op[0] = m_pos[0];
|
|
op[1] = m_pos[1];
|
|
op += 2;
|
|
@@ -194,15 +214,15 @@ match_next:
|
|
state = next;
|
|
t = next;
|
|
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
|
- if (likely(HAVE_IP(6) && HAVE_OP(4))) {
|
|
+ if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) {
|
|
COPY4(op, ip);
|
|
op += t;
|
|
ip += t;
|
|
} else
|
|
#endif
|
|
{
|
|
- NEED_IP(t + 3);
|
|
- NEED_OP(t);
|
|
+ NEED_IP(t, 3);
|
|
+ NEED_OP(t, 0);
|
|
while (t > 0) {
|
|
*op++ = *ip++;
|
|
t--;
|
|
diff --git a/lib/nlattr.c b/lib/nlattr.c
|
|
index fc6754720ced..10ad042d01be 100644
|
|
--- a/lib/nlattr.c
|
|
+++ b/lib/nlattr.c
|
|
@@ -201,8 +201,8 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
|
|
}
|
|
|
|
if (unlikely(rem > 0))
|
|
- printk(KERN_WARNING "netlink: %d bytes leftover after parsing "
|
|
- "attributes.\n", rem);
|
|
+ pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
|
|
+ rem, current->comm);
|
|
|
|
err = 0;
|
|
errout:
|
|
diff --git a/net/can/gw.c b/net/can/gw.c
|
|
index 3ee690e8c7d3..de25455b4e3e 100644
|
|
--- a/net/can/gw.c
|
|
+++ b/net/can/gw.c
|
|
@@ -784,7 +784,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct cgw_job *gwj;
|
|
int err = 0;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (nlmsg_len(nlh) < sizeof(*r))
|
|
@@ -876,7 +876,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct can_can_gw ccgw;
|
|
int err = 0;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (nlmsg_len(nlh) < sizeof(*r))
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 56383a3e5d71..cca7ae0ba915 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -5827,6 +5827,9 @@ EXPORT_SYMBOL(unregister_netdevice_queue);
|
|
/**
|
|
* unregister_netdevice_many - unregister many devices
|
|
* @head: list of devices
|
|
+ *
|
|
+ * Note: As most callers use a stack allocated list_head,
|
|
+ * we force a list_del() to make sure stack wont be corrupted later.
|
|
*/
|
|
void unregister_netdevice_many(struct list_head *head)
|
|
{
|
|
@@ -5836,6 +5839,7 @@ void unregister_netdevice_many(struct list_head *head)
|
|
rollback_registered_many(head);
|
|
list_for_each_entry(dev, head, unreg_list)
|
|
net_set_todo(dev);
|
|
+ list_del(head);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(unregister_netdevice_many);
|
|
@@ -6252,7 +6256,6 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
|
|
}
|
|
}
|
|
unregister_netdevice_many(&dev_kill_list);
|
|
- list_del(&dev_kill_list);
|
|
rtnl_unlock();
|
|
}
|
|
|
|
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
|
|
index 87ec574ffac8..ae43dd807bb2 100644
|
|
--- a/net/core/rtnetlink.c
|
|
+++ b/net/core/rtnetlink.c
|
|
@@ -1044,6 +1044,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
|
struct nlattr *tb[IFLA_MAX+1];
|
|
u32 ext_filter_mask = 0;
|
|
int err;
|
|
+ int hdrlen;
|
|
|
|
s_h = cb->args[0];
|
|
s_idx = cb->args[1];
|
|
@@ -1051,8 +1052,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
|
rcu_read_lock();
|
|
cb->seq = net->dev_base_seq;
|
|
|
|
- if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
|
|
- ifla_policy) >= 0) {
|
|
+ /* A hack to preserve kernel<->userspace interface.
|
|
+ * The correct header is ifinfomsg. It is consistent with rtnl_getlink.
|
|
+ * However, before Linux v3.9 the code here assumed rtgenmsg and that's
|
|
+ * what iproute2 < v3.9.0 used.
|
|
+ * We can detect the old iproute2. Even including the IFLA_EXT_MASK
|
|
+ * attribute, its netlink message is shorter than struct ifinfomsg.
|
|
+ */
|
|
+ hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ?
|
|
+ sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg);
|
|
+
|
|
+ if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
|
|
|
|
if (tb[IFLA_EXT_MASK])
|
|
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
|
@@ -1294,7 +1304,8 @@ static int do_set_master(struct net_device *dev, int ifindex)
|
|
return 0;
|
|
}
|
|
|
|
-static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
|
+static int do_setlink(const struct sk_buff *skb,
|
|
+ struct net_device *dev, struct ifinfomsg *ifm,
|
|
struct nlattr **tb, char *ifname, int modified)
|
|
{
|
|
const struct net_device_ops *ops = dev->netdev_ops;
|
|
@@ -1306,7 +1317,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
|
err = PTR_ERR(net);
|
|
goto errout;
|
|
}
|
|
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
|
|
+ if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
|
|
err = -EPERM;
|
|
goto errout;
|
|
}
|
|
@@ -1560,7 +1571,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
if (err < 0)
|
|
goto errout;
|
|
|
|
- err = do_setlink(dev, ifm, tb, ifname, 0);
|
|
+ err = do_setlink(skb, dev, ifm, tb, ifname, 0);
|
|
errout:
|
|
return err;
|
|
}
|
|
@@ -1600,7 +1611,6 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
|
|
ops->dellink(dev, &list_kill);
|
|
unregister_netdevice_many(&list_kill);
|
|
- list_del(&list_kill);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1678,7 +1688,8 @@ err:
|
|
}
|
|
EXPORT_SYMBOL(rtnl_create_link);
|
|
|
|
-static int rtnl_group_changelink(struct net *net, int group,
|
|
+static int rtnl_group_changelink(const struct sk_buff *skb,
|
|
+ struct net *net, int group,
|
|
struct ifinfomsg *ifm,
|
|
struct nlattr **tb)
|
|
{
|
|
@@ -1687,7 +1698,7 @@ static int rtnl_group_changelink(struct net *net, int group,
|
|
|
|
for_each_netdev(net, dev) {
|
|
if (dev->group == group) {
|
|
- err = do_setlink(dev, ifm, tb, NULL, 0);
|
|
+ err = do_setlink(skb, dev, ifm, tb, NULL, 0);
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
@@ -1789,12 +1800,12 @@ replay:
|
|
modified = 1;
|
|
}
|
|
|
|
- return do_setlink(dev, ifm, tb, ifname, modified);
|
|
+ return do_setlink(skb, dev, ifm, tb, ifname, modified);
|
|
}
|
|
|
|
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
|
|
if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
|
|
- return rtnl_group_changelink(net,
|
|
+ return rtnl_group_changelink(skb, net,
|
|
nla_get_u32(tb[IFLA_GROUP]),
|
|
ifm, tb);
|
|
return -ENODEV;
|
|
@@ -1906,9 +1917,13 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct nlattr *tb[IFLA_MAX+1];
|
|
u32 ext_filter_mask = 0;
|
|
u16 min_ifinfo_dump_size = 0;
|
|
+ int hdrlen;
|
|
+
|
|
+ /* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */
|
|
+ hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ?
|
|
+ sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg);
|
|
|
|
- if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
|
|
- ifla_policy) >= 0) {
|
|
+ if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) {
|
|
if (tb[IFLA_EXT_MASK])
|
|
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
|
|
}
|
|
@@ -2179,7 +2194,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
int err = -EINVAL;
|
|
__u8 *addr;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
|
|
@@ -2635,7 +2650,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
sz_idx = type>>2;
|
|
kind = type&3;
|
|
|
|
- if (kind != 2 && !ns_capable(net->user_ns, CAP_NET_ADMIN))
|
|
+ if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
|
|
diff --git a/net/core/sock.c b/net/core/sock.c
|
|
index d743099250f4..af65d17517b8 100644
|
|
--- a/net/core/sock.c
|
|
+++ b/net/core/sock.c
|
|
@@ -142,6 +142,55 @@
|
|
static DEFINE_MUTEX(proto_list_mutex);
|
|
static LIST_HEAD(proto_list);
|
|
|
|
+/**
|
|
+ * sk_ns_capable - General socket capability test
|
|
+ * @sk: Socket to use a capability on or through
|
|
+ * @user_ns: The user namespace of the capability to use
|
|
+ * @cap: The capability to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket had when the socket was
|
|
+ * created and the current process has the capability @cap in the user
|
|
+ * namespace @user_ns.
|
|
+ */
|
|
+bool sk_ns_capable(const struct sock *sk,
|
|
+ struct user_namespace *user_ns, int cap)
|
|
+{
|
|
+ return file_ns_capable(sk->sk_socket->file, user_ns, cap) &&
|
|
+ ns_capable(user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(sk_ns_capable);
|
|
+
|
|
+/**
|
|
+ * sk_capable - Socket global capability test
|
|
+ * @sk: Socket to use a capability on or through
|
|
+ * @cap: The global capbility to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket had when the socket was
|
|
+ * created and the current process has the capability @cap in all user
|
|
+ * namespaces.
|
|
+ */
|
|
+bool sk_capable(const struct sock *sk, int cap)
|
|
+{
|
|
+ return sk_ns_capable(sk, &init_user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(sk_capable);
|
|
+
|
|
+/**
|
|
+ * sk_net_capable - Network namespace socket capability test
|
|
+ * @sk: Socket to use a capability on or through
|
|
+ * @cap: The capability to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket had when the socke was created
|
|
+ * and the current process has the capability @cap over the network namespace
|
|
+ * the socket is a member of.
|
|
+ */
|
|
+bool sk_net_capable(const struct sock *sk, int cap)
|
|
+{
|
|
+ return sk_ns_capable(sk, sock_net(sk)->user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(sk_net_capable);
|
|
+
|
|
+
|
|
#ifdef CONFIG_MEMCG_KMEM
|
|
int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
|
|
{
|
|
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
|
|
index 6a7fae228634..c38e7a2b5a8e 100644
|
|
--- a/net/core/sock_diag.c
|
|
+++ b/net/core/sock_diag.c
|
|
@@ -49,7 +49,7 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
|
|
}
|
|
EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
|
|
|
|
-int sock_diag_put_filterinfo(struct sock *sk,
|
|
+int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
|
|
struct sk_buff *skb, int attrtype)
|
|
{
|
|
struct nlattr *attr;
|
|
@@ -57,7 +57,7 @@ int sock_diag_put_filterinfo(struct sock *sk,
|
|
unsigned int len;
|
|
int err = 0;
|
|
|
|
- if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
|
|
+ if (!may_report_filterinfo) {
|
|
nla_reserve(skb, attrtype, 0);
|
|
return 0;
|
|
}
|
|
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
|
|
index 40d5829ed36a..1074ffb6d533 100644
|
|
--- a/net/dcb/dcbnl.c
|
|
+++ b/net/dcb/dcbnl.c
|
|
@@ -1670,7 +1670,7 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct nlmsghdr *reply_nlh = NULL;
|
|
const struct reply_func *fn;
|
|
|
|
- if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN))
|
|
+ if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
|
|
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
|
|
index 7d9197063ebb..b5e52100a89a 100644
|
|
--- a/net/decnet/dn_dev.c
|
|
+++ b/net/decnet/dn_dev.c
|
|
@@ -573,7 +573,7 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct dn_ifaddr __rcu **ifap;
|
|
int err = -EINVAL;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (!net_eq(net, &init_net))
|
|
@@ -617,7 +617,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct dn_ifaddr *ifa;
|
|
int err;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (!net_eq(net, &init_net))
|
|
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
|
|
index 57dc159245ec..d332aefb0846 100644
|
|
--- a/net/decnet/dn_fib.c
|
|
+++ b/net/decnet/dn_fib.c
|
|
@@ -505,7 +505,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct nlattr *attrs[RTA_MAX+1];
|
|
int err;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (!net_eq(net, &init_net))
|
|
@@ -530,7 +530,7 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
struct nlattr *attrs[RTA_MAX+1];
|
|
int err;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (!net_eq(net, &init_net))
|
|
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
|
|
index 2a7efe388344..f3dc69a41d63 100644
|
|
--- a/net/decnet/netfilter/dn_rtmsg.c
|
|
+++ b/net/decnet/netfilter/dn_rtmsg.c
|
|
@@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
|
|
if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
|
|
return;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
RCV_SKB_FAIL(-EPERM);
|
|
|
|
/* Eventually we might send routing messages too */
|
|
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
|
|
index 19e36376d2a0..5f3dc1df04bf 100644
|
|
--- a/net/ipv4/datagram.c
|
|
+++ b/net/ipv4/datagram.c
|
|
@@ -86,18 +86,26 @@ out:
|
|
}
|
|
EXPORT_SYMBOL(ip4_datagram_connect);
|
|
|
|
+/* Because UDP xmit path can manipulate sk_dst_cache without holding
|
|
+ * socket lock, we need to use sk_dst_set() here,
|
|
+ * even if we own the socket lock.
|
|
+ */
|
|
void ip4_datagram_release_cb(struct sock *sk)
|
|
{
|
|
const struct inet_sock *inet = inet_sk(sk);
|
|
const struct ip_options_rcu *inet_opt;
|
|
__be32 daddr = inet->inet_daddr;
|
|
+ struct dst_entry *dst;
|
|
struct flowi4 fl4;
|
|
struct rtable *rt;
|
|
|
|
- if (! __sk_dst_get(sk) || __sk_dst_check(sk, 0))
|
|
- return;
|
|
-
|
|
rcu_read_lock();
|
|
+
|
|
+ dst = __sk_dst_get(sk);
|
|
+ if (!dst || !dst->obsolete || dst->ops->check(dst, 0)) {
|
|
+ rcu_read_unlock();
|
|
+ return;
|
|
+ }
|
|
inet_opt = rcu_dereference(inet->inet_opt);
|
|
if (inet_opt && inet_opt->opt.srr)
|
|
daddr = inet_opt->opt.faddr;
|
|
@@ -105,8 +113,10 @@ void ip4_datagram_release_cb(struct sock *sk)
|
|
inet->inet_saddr, inet->inet_dport,
|
|
inet->inet_sport, sk->sk_protocol,
|
|
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
|
|
- if (!IS_ERR(rt))
|
|
- __sk_dst_set(sk, &rt->dst);
|
|
+
|
|
+ dst = !IS_ERR(rt) ? &rt->dst : NULL;
|
|
+ sk_dst_set(sk, dst);
|
|
+
|
|
rcu_read_unlock();
|
|
}
|
|
EXPORT_SYMBOL_GPL(ip4_datagram_release_cb);
|
|
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
|
|
index f5cc7b331511..897b784e9c05 100644
|
|
--- a/net/ipv4/ipip.c
|
|
+++ b/net/ipv4/ipip.c
|
|
@@ -149,13 +149,13 @@ static int ipip_err(struct sk_buff *skb, u32 info)
|
|
|
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
|
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
|
|
- t->dev->ifindex, 0, IPPROTO_IPIP, 0);
|
|
+ t->parms.link, 0, IPPROTO_IPIP, 0);
|
|
err = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (type == ICMP_REDIRECT) {
|
|
- ipv4_redirect(skb, dev_net(skb->dev), t->dev->ifindex, 0,
|
|
+ ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
|
|
IPPROTO_IPIP, 0);
|
|
err = 0;
|
|
goto out;
|
|
@@ -483,4 +483,5 @@ static void __exit ipip_fini(void)
|
|
module_init(ipip_init);
|
|
module_exit(ipip_fini);
|
|
MODULE_LICENSE("GPL");
|
|
+MODULE_ALIAS_RTNL_LINK("ipip");
|
|
MODULE_ALIAS_NETDEV("tunl0");
|
|
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
|
|
index e15d330919af..ba7d2b7ad9f9 100644
|
|
--- a/net/ipv4/tcp_input.c
|
|
+++ b/net/ipv4/tcp_input.c
|
|
@@ -2720,13 +2720,12 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
|
|
bool recovered = !before(tp->snd_una, tp->high_seq);
|
|
|
|
if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
|
|
- if (flag & FLAG_ORIG_SACK_ACKED) {
|
|
- /* Step 3.b. A timeout is spurious if not all data are
|
|
- * lost, i.e., never-retransmitted data are (s)acked.
|
|
- */
|
|
- tcp_try_undo_loss(sk, true);
|
|
+ /* Step 3.b. A timeout is spurious if not all data are
|
|
+ * lost, i.e., never-retransmitted data are (s)acked.
|
|
+ */
|
|
+ if (tcp_try_undo_loss(sk, flag & FLAG_ORIG_SACK_ACKED))
|
|
return;
|
|
- }
|
|
+
|
|
if (after(tp->snd_nxt, tp->high_seq) &&
|
|
(flag & FLAG_DATA_SACKED || is_dupack)) {
|
|
tp->frto = 0; /* Loss was real: 2nd part of step 3.a */
|
|
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
|
|
index 73d7f68da557..a0ecdf596f2f 100644
|
|
--- a/net/ipv6/ip6_tunnel.c
|
|
+++ b/net/ipv6/ip6_tunnel.c
|
|
@@ -61,6 +61,7 @@
|
|
MODULE_AUTHOR("Ville Nuorvala");
|
|
MODULE_DESCRIPTION("IPv6 tunneling device");
|
|
MODULE_LICENSE("GPL");
|
|
+MODULE_ALIAS_RTNL_LINK("ip6tnl");
|
|
MODULE_ALIAS_NETDEV("ip6tnl0");
|
|
|
|
#ifdef IP6_TNL_DEBUG
|
|
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
|
|
index c2e73e647e44..3d2c81a66d6a 100644
|
|
--- a/net/ipv6/output_core.c
|
|
+++ b/net/ipv6/output_core.c
|
|
@@ -9,7 +9,7 @@
|
|
void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
|
|
{
|
|
static atomic_t ipv6_fragmentation_id;
|
|
- int old, new;
|
|
+ int ident;
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
if (rt && !(rt->dst.flags & DST_NOPEER)) {
|
|
@@ -25,13 +25,8 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
|
|
}
|
|
}
|
|
#endif
|
|
- do {
|
|
- old = atomic_read(&ipv6_fragmentation_id);
|
|
- new = old + 1;
|
|
- if (!new)
|
|
- new = 1;
|
|
- } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
|
|
- fhdr->identification = htonl(new);
|
|
+ ident = atomic_inc_return(&ipv6_fragmentation_id);
|
|
+ fhdr->identification = htonl(ident);
|
|
}
|
|
EXPORT_SYMBOL(ipv6_select_ident);
|
|
|
|
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
|
|
index 620d326e8fdd..540d58921007 100644
|
|
--- a/net/ipv6/sit.c
|
|
+++ b/net/ipv6/sit.c
|
|
@@ -530,12 +530,12 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
|
|
|
|
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
|
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
|
|
- t->dev->ifindex, 0, IPPROTO_IPV6, 0);
|
|
+ t->parms.link, 0, IPPROTO_IPV6, 0);
|
|
err = 0;
|
|
goto out;
|
|
}
|
|
if (type == ICMP_REDIRECT) {
|
|
- ipv4_redirect(skb, dev_net(skb->dev), t->dev->ifindex, 0,
|
|
+ ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
|
|
IPPROTO_IPV6, 0);
|
|
err = 0;
|
|
goto out;
|
|
@@ -1654,4 +1654,5 @@ xfrm_tunnel_failed:
|
|
module_init(sit_init);
|
|
module_exit(sit_cleanup);
|
|
MODULE_LICENSE("GPL");
|
|
+MODULE_ALIAS_RTNL_LINK("sit");
|
|
MODULE_ALIAS_NETDEV("sit0");
|
|
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
|
|
index 514e90f470bf..2c64ab27b515 100644
|
|
--- a/net/mac80211/iface.c
|
|
+++ b/net/mac80211/iface.c
|
|
@@ -1746,7 +1746,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
|
|
}
|
|
mutex_unlock(&local->iflist_mtx);
|
|
unregister_netdevice_many(&unreg_list);
|
|
- list_del(&unreg_list);
|
|
|
|
list_for_each_entry_safe(sdata, tmp, &wdev_list, list) {
|
|
list_del(&sdata->list);
|
|
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
|
|
index 572d87dc116f..0a03662bfbef 100644
|
|
--- a/net/netfilter/nfnetlink.c
|
|
+++ b/net/netfilter/nfnetlink.c
|
|
@@ -147,7 +147,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
const struct nfnetlink_subsystem *ss;
|
|
int type, err;
|
|
|
|
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
|
+ if (!netlink_net_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
/* All the messages must at least contain nfgenmsg */
|
|
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
|
|
index c9c2a8441d32..be34adde692f 100644
|
|
--- a/net/netlink/af_netlink.c
|
|
+++ b/net/netlink/af_netlink.c
|
|
@@ -1219,7 +1219,74 @@ retry:
|
|
return err;
|
|
}
|
|
|
|
-static inline int netlink_capable(const struct socket *sock, unsigned int flag)
|
|
+/**
|
|
+ * __netlink_ns_capable - General netlink message capability test
|
|
+ * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace.
|
|
+ * @user_ns: The user namespace of the capability to use
|
|
+ * @cap: The capability to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket we received the message
|
|
+ * from had when the netlink socket was created and the sender of the
|
|
+ * message has has the capability @cap in the user namespace @user_ns.
|
|
+ */
|
|
+bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
|
|
+ struct user_namespace *user_ns, int cap)
|
|
+{
|
|
+ return ((nsp->flags & NETLINK_SKB_DST) ||
|
|
+ file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) &&
|
|
+ ns_capable(user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(__netlink_ns_capable);
|
|
+
|
|
+/**
|
|
+ * netlink_ns_capable - General netlink message capability test
|
|
+ * @skb: socket buffer holding a netlink command from userspace
|
|
+ * @user_ns: The user namespace of the capability to use
|
|
+ * @cap: The capability to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket we received the message
|
|
+ * from had when the netlink socket was created and the sender of the
|
|
+ * message has has the capability @cap in the user namespace @user_ns.
|
|
+ */
|
|
+bool netlink_ns_capable(const struct sk_buff *skb,
|
|
+ struct user_namespace *user_ns, int cap)
|
|
+{
|
|
+ return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(netlink_ns_capable);
|
|
+
|
|
+/**
|
|
+ * netlink_capable - Netlink global message capability test
|
|
+ * @skb: socket buffer holding a netlink command from userspace
|
|
+ * @cap: The capability to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket we received the message
|
|
+ * from had when the netlink socket was created and the sender of the
|
|
+ * message has has the capability @cap in all user namespaces.
|
|
+ */
|
|
+bool netlink_capable(const struct sk_buff *skb, int cap)
|
|
+{
|
|
+ return netlink_ns_capable(skb, &init_user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(netlink_capable);
|
|
+
|
|
+/**
|
|
+ * netlink_net_capable - Netlink network namespace message capability test
|
|
+ * @skb: socket buffer holding a netlink command from userspace
|
|
+ * @cap: The capability to use
|
|
+ *
|
|
+ * Test to see if the opener of the socket we received the message
|
|
+ * from had when the netlink socket was created and the sender of the
|
|
+ * message has has the capability @cap over the network namespace of
|
|
+ * the socket we received the message from.
|
|
+ */
|
|
+bool netlink_net_capable(const struct sk_buff *skb, int cap)
|
|
+{
|
|
+ return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap);
|
|
+}
|
|
+EXPORT_SYMBOL(netlink_net_capable);
|
|
+
|
|
+static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
|
|
{
|
|
return (nl_table[sock->sk->sk_protocol].flags & flag) ||
|
|
ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN);
|
|
@@ -1287,7 +1354,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
|
|
|
|
/* Only superuser is allowed to listen multicasts */
|
|
if (nladdr->nl_groups) {
|
|
- if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV))
|
|
+ if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
|
|
return -EPERM;
|
|
err = netlink_realloc_groups(sk);
|
|
if (err)
|
|
@@ -1349,7 +1416,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
|
|
return -EINVAL;
|
|
|
|
/* Only superuser is allowed to send multicasts */
|
|
- if (nladdr->nl_groups && !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
|
|
+ if (nladdr->nl_groups && !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
|
|
return -EPERM;
|
|
|
|
if (!nlk->portid)
|
|
@@ -1921,7 +1988,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
|
|
break;
|
|
case NETLINK_ADD_MEMBERSHIP:
|
|
case NETLINK_DROP_MEMBERSHIP: {
|
|
- if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV))
|
|
+ if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
|
|
return -EPERM;
|
|
err = netlink_realloc_groups(sk);
|
|
if (err)
|
|
@@ -2053,6 +2120,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
|
struct sk_buff *skb;
|
|
int err;
|
|
struct scm_cookie scm;
|
|
+ u32 netlink_skb_flags = 0;
|
|
|
|
if (msg->msg_flags&MSG_OOB)
|
|
return -EOPNOTSUPP;
|
|
@@ -2072,8 +2140,9 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
|
dst_group = ffs(addr->nl_groups);
|
|
err = -EPERM;
|
|
if ((dst_group || dst_portid) &&
|
|
- !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
|
|
+ !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
|
|
goto out;
|
|
+ netlink_skb_flags |= NETLINK_SKB_DST;
|
|
} else {
|
|
dst_portid = nlk->dst_portid;
|
|
dst_group = nlk->dst_group;
|
|
@@ -2103,6 +2172,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
|
NETLINK_CB(skb).portid = nlk->portid;
|
|
NETLINK_CB(skb).dst_group = dst_group;
|
|
NETLINK_CB(skb).creds = siocb->scm->creds;
|
|
+ NETLINK_CB(skb).flags = netlink_skb_flags;
|
|
|
|
err = -EFAULT;
|
|
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
|
|
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
|
|
index 393f17eea1a2..ade434b8abd8 100644
|
|
--- a/net/netlink/genetlink.c
|
|
+++ b/net/netlink/genetlink.c
|
|
@@ -592,7 +592,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
|
|
return -EOPNOTSUPP;
|
|
|
|
if ((ops->flags & GENL_ADMIN_PERM) &&
|
|
- !capable(CAP_NET_ADMIN))
|
|
+ !netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if (nlh->nlmsg_flags & NLM_F_DUMP) {
|
|
diff --git a/net/packet/diag.c b/net/packet/diag.c
|
|
index ec8b6e8a80b1..674b0a65df6c 100644
|
|
--- a/net/packet/diag.c
|
|
+++ b/net/packet/diag.c
|
|
@@ -127,6 +127,7 @@ static int pdiag_put_fanout(struct packet_sock *po, struct sk_buff *nlskb)
|
|
|
|
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
|
|
struct packet_diag_req *req,
|
|
+ bool may_report_filterinfo,
|
|
struct user_namespace *user_ns,
|
|
u32 portid, u32 seq, u32 flags, int sk_ino)
|
|
{
|
|
@@ -171,7 +172,8 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
|
|
goto out_nlmsg_trim;
|
|
|
|
if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
|
|
- sock_diag_put_filterinfo(sk, skb, PACKET_DIAG_FILTER))
|
|
+ sock_diag_put_filterinfo(may_report_filterinfo, sk, skb,
|
|
+ PACKET_DIAG_FILTER))
|
|
goto out_nlmsg_trim;
|
|
|
|
return nlmsg_end(skb, nlh);
|
|
@@ -187,9 +189,11 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
struct packet_diag_req *req;
|
|
struct net *net;
|
|
struct sock *sk;
|
|
+ bool may_report_filterinfo;
|
|
|
|
net = sock_net(skb->sk);
|
|
req = nlmsg_data(cb->nlh);
|
|
+ may_report_filterinfo = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
|
|
|
|
mutex_lock(&net->packet.sklist_lock);
|
|
sk_for_each(sk, &net->packet.sklist) {
|
|
@@ -199,6 +203,7 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
goto next;
|
|
|
|
if (sk_diag_fill(sk, skb, req,
|
|
+ may_report_filterinfo,
|
|
sk_user_ns(NETLINK_CB(cb->skb).sk),
|
|
NETLINK_CB(cb->skb).portid,
|
|
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
|
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
|
|
index dc15f4300808..b64151ade6b3 100644
|
|
--- a/net/phonet/pn_netlink.c
|
|
+++ b/net/phonet/pn_netlink.c
|
|
@@ -70,10 +70,10 @@ static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
int err;
|
|
u8 pnaddr;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_SYS_ADMIN))
|
|
return -EPERM;
|
|
|
|
ASSERT_RTNL();
|
|
@@ -233,10 +233,10 @@ static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
int err;
|
|
u8 dst;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_SYS_ADMIN))
|
|
return -EPERM;
|
|
|
|
ASSERT_RTNL();
|
|
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
|
|
index fd7072827a40..15d46b9166de 100644
|
|
--- a/net/sched/act_api.c
|
|
+++ b/net/sched/act_api.c
|
|
@@ -989,7 +989,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n)
|
|
u32 portid = skb ? NETLINK_CB(skb).portid : 0;
|
|
int ret = 0, ovr = 0;
|
|
|
|
- if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN))
|
|
+ if ((n->nlmsg_type != RTM_GETACTION) && !netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
|
|
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
|
|
index 8e118af90973..2ea40d1877a6 100644
|
|
--- a/net/sched/cls_api.c
|
|
+++ b/net/sched/cls_api.c
|
|
@@ -138,7 +138,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
|
|
int err;
|
|
int tp_created = 0;
|
|
|
|
- if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN))
|
|
+ if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
replay:
|
|
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
|
|
index 51b968d3febb..2d2f07945c85 100644
|
|
--- a/net/sched/sch_api.c
|
|
+++ b/net/sched/sch_api.c
|
|
@@ -1024,7 +1024,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
|
|
struct Qdisc *p = NULL;
|
|
int err;
|
|
|
|
- if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN))
|
|
+ if ((n->nlmsg_type != RTM_GETQDISC) && !netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
|
|
@@ -1091,7 +1091,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
|
|
struct Qdisc *q, *p;
|
|
int err;
|
|
|
|
- if (!capable(CAP_NET_ADMIN))
|
|
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
replay:
|
|
@@ -1431,7 +1431,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n)
|
|
u32 qid;
|
|
int err;
|
|
|
|
- if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN))
|
|
+ if ((n->nlmsg_type != RTM_GETTCLASS) && !netlink_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
|
|
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
|
|
index 91cfd8f94a19..229b3c3fb6c9 100644
|
|
--- a/net/sctp/associola.c
|
|
+++ b/net/sctp/associola.c
|
|
@@ -387,7 +387,7 @@ void sctp_association_free(struct sctp_association *asoc)
|
|
/* Only real associations count against the endpoint, so
|
|
* don't bother for if this is a temporary association.
|
|
*/
|
|
- if (!asoc->temp) {
|
|
+ if (!list_empty(&asoc->asocs)) {
|
|
list_del(&asoc->asocs);
|
|
|
|
/* Decrement the backlog value for a TCP-style listening
|
|
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
|
|
index 8bcd4985d0fb..1e6081fb6078 100644
|
|
--- a/net/tipc/netlink.c
|
|
+++ b/net/tipc/netlink.c
|
|
@@ -47,7 +47,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
|
|
int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
|
|
u16 cmd;
|
|
|
|
- if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
|
|
+ if ((req_userhdr->cmd & 0xC000) && (!netlink_capable(skb, CAP_NET_ADMIN)))
|
|
cmd = TIPC_CMD_NOT_NET_ADMIN;
|
|
else
|
|
cmd = req_userhdr->cmd;
|
|
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
|
|
index 3f565e495ac6..7a70a5a5671a 100644
|
|
--- a/net/xfrm/xfrm_user.c
|
|
+++ b/net/xfrm/xfrm_user.c
|
|
@@ -2362,7 +2362,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
link = &xfrm_dispatch[type];
|
|
|
|
/* All operations require privileges, even GET */
|
|
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
|
+ if (!netlink_net_capable(skb, CAP_NET_ADMIN))
|
|
return -EPERM;
|
|
|
|
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
|
|
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
|
|
index cdbde1762189..b9b2bebeb350 100644
|
|
--- a/security/integrity/evm/evm_main.c
|
|
+++ b/security/integrity/evm/evm_main.c
|
|
@@ -275,12 +275,20 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
|
|
* @xattr_value: pointer to the new extended attribute value
|
|
* @xattr_value_len: pointer to the new extended attribute value length
|
|
*
|
|
- * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that
|
|
- * the current value is valid.
|
|
+ * Before allowing the 'security.evm' protected xattr to be updated,
|
|
+ * verify the existing value is valid. As only the kernel should have
|
|
+ * access to the EVM encrypted key needed to calculate the HMAC, prevent
|
|
+ * userspace from writing HMAC value. Writing 'security.evm' requires
|
|
+ * requires CAP_SYS_ADMIN privileges.
|
|
*/
|
|
int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,
|
|
const void *xattr_value, size_t xattr_value_len)
|
|
{
|
|
+ const struct evm_ima_xattr_data *xattr_data = xattr_value;
|
|
+
|
|
+ if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0)
|
|
+ && (xattr_data->type == EVM_XATTR_HMAC))
|
|
+ return -EPERM;
|
|
return evm_protect_xattr(dentry, xattr_name, xattr_value,
|
|
xattr_value_len);
|
|
}
|
|
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
|
|
index a02e0791cf15..9da974c0f958 100644
|
|
--- a/security/integrity/ima/ima_crypto.c
|
|
+++ b/security/integrity/ima/ima_crypto.c
|
|
@@ -24,6 +24,36 @@
|
|
|
|
static struct crypto_shash *ima_shash_tfm;
|
|
|
|
+/**
|
|
+ * ima_kernel_read - read file content
|
|
+ *
|
|
+ * This is a function for reading file content instead of kernel_read().
|
|
+ * It does not perform locking checks to ensure it cannot be blocked.
|
|
+ * It does not perform security checks because it is irrelevant for IMA.
|
|
+ *
|
|
+ */
|
|
+static int ima_kernel_read(struct file *file, loff_t offset,
|
|
+ char *addr, unsigned long count)
|
|
+{
|
|
+ mm_segment_t old_fs;
|
|
+ char __user *buf = addr;
|
|
+ ssize_t ret;
|
|
+
|
|
+ if (!(file->f_mode & FMODE_READ))
|
|
+ return -EBADF;
|
|
+ if (!file->f_op->read && !file->f_op->aio_read)
|
|
+ return -EINVAL;
|
|
+
|
|
+ old_fs = get_fs();
|
|
+ set_fs(get_ds());
|
|
+ if (file->f_op->read)
|
|
+ ret = file->f_op->read(file, buf, count, &offset);
|
|
+ else
|
|
+ ret = do_sync_read(file, buf, count, &offset);
|
|
+ set_fs(old_fs);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
int ima_init_crypto(void)
|
|
{
|
|
long rc;
|
|
@@ -70,7 +100,7 @@ int ima_calc_file_hash(struct file *file, char *digest)
|
|
while (offset < i_size) {
|
|
int rbuf_len;
|
|
|
|
- rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
|
|
+ rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE);
|
|
if (rbuf_len < 0) {
|
|
rc = rbuf_len;
|
|
break;
|
|
diff --git a/sound/core/control.c b/sound/core/control.c
|
|
index d8aa206e8bde..98a29b26c5f4 100644
|
|
--- a/sound/core/control.c
|
|
+++ b/sound/core/control.c
|
|
@@ -289,6 +289,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
|
|
{
|
|
struct snd_kcontrol *kctl;
|
|
|
|
+ /* Make sure that the ids assigned to the control do not wrap around */
|
|
+ if (card->last_numid >= UINT_MAX - count)
|
|
+ card->last_numid = 0;
|
|
+
|
|
list_for_each_entry(kctl, &card->controls, list) {
|
|
if (kctl->id.numid < card->last_numid + 1 + count &&
|
|
kctl->id.numid + kctl->count > card->last_numid + 1) {
|
|
@@ -331,6 +335,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|
{
|
|
struct snd_ctl_elem_id id;
|
|
unsigned int idx;
|
|
+ unsigned int count;
|
|
int err = -EINVAL;
|
|
|
|
if (! kcontrol)
|
|
@@ -338,6 +343,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|
if (snd_BUG_ON(!card || !kcontrol->info))
|
|
goto error;
|
|
id = kcontrol->id;
|
|
+ if (id.index > UINT_MAX - kcontrol->count)
|
|
+ goto error;
|
|
+
|
|
down_write(&card->controls_rwsem);
|
|
if (snd_ctl_find_id(card, &id)) {
|
|
up_write(&card->controls_rwsem);
|
|
@@ -359,8 +367,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|
card->controls_count += kcontrol->count;
|
|
kcontrol->id.numid = card->last_numid + 1;
|
|
card->last_numid += kcontrol->count;
|
|
+ count = kcontrol->count;
|
|
up_write(&card->controls_rwsem);
|
|
- for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
|
|
+ for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
|
return 0;
|
|
|
|
@@ -389,6 +398,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
|
|
bool add_on_replace)
|
|
{
|
|
struct snd_ctl_elem_id id;
|
|
+ unsigned int count;
|
|
unsigned int idx;
|
|
struct snd_kcontrol *old;
|
|
int ret;
|
|
@@ -424,8 +434,9 @@ add:
|
|
card->controls_count += kcontrol->count;
|
|
kcontrol->id.numid = card->last_numid + 1;
|
|
card->last_numid += kcontrol->count;
|
|
+ count = kcontrol->count;
|
|
up_write(&card->controls_rwsem);
|
|
- for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
|
|
+ for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
|
return 0;
|
|
|
|
@@ -898,9 +909,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
|
result = kctl->put(kctl, control);
|
|
}
|
|
if (result > 0) {
|
|
+ struct snd_ctl_elem_id id = control->id;
|
|
up_read(&card->controls_rwsem);
|
|
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
|
- &control->id);
|
|
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -992,6 +1003,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
|
|
|
struct user_element {
|
|
struct snd_ctl_elem_info info;
|
|
+ struct snd_card *card;
|
|
void *elem_data; /* element data */
|
|
unsigned long elem_data_size; /* size of element data in bytes */
|
|
void *tlv_data; /* TLV data */
|
|
@@ -1035,7 +1047,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
|
|
{
|
|
struct user_element *ue = kcontrol->private_data;
|
|
|
|
+ mutex_lock(&ue->card->user_ctl_lock);
|
|
memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
|
|
+ mutex_unlock(&ue->card->user_ctl_lock);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1044,10 +1058,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
|
|
{
|
|
int change;
|
|
struct user_element *ue = kcontrol->private_data;
|
|
-
|
|
+
|
|
+ mutex_lock(&ue->card->user_ctl_lock);
|
|
change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
|
|
if (change)
|
|
memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
|
|
+ mutex_unlock(&ue->card->user_ctl_lock);
|
|
return change;
|
|
}
|
|
|
|
@@ -1067,19 +1083,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
|
|
new_data = memdup_user(tlv, size);
|
|
if (IS_ERR(new_data))
|
|
return PTR_ERR(new_data);
|
|
+ mutex_lock(&ue->card->user_ctl_lock);
|
|
change = ue->tlv_data_size != size;
|
|
if (!change)
|
|
change = memcmp(ue->tlv_data, new_data, size);
|
|
kfree(ue->tlv_data);
|
|
ue->tlv_data = new_data;
|
|
ue->tlv_data_size = size;
|
|
+ mutex_unlock(&ue->card->user_ctl_lock);
|
|
} else {
|
|
- if (! ue->tlv_data_size || ! ue->tlv_data)
|
|
- return -ENXIO;
|
|
- if (size < ue->tlv_data_size)
|
|
- return -ENOSPC;
|
|
+ int ret = 0;
|
|
+
|
|
+ mutex_lock(&ue->card->user_ctl_lock);
|
|
+ if (!ue->tlv_data_size || !ue->tlv_data) {
|
|
+ ret = -ENXIO;
|
|
+ goto err_unlock;
|
|
+ }
|
|
+ if (size < ue->tlv_data_size) {
|
|
+ ret = -ENOSPC;
|
|
+ goto err_unlock;
|
|
+ }
|
|
if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
|
|
- return -EFAULT;
|
|
+ ret = -EFAULT;
|
|
+err_unlock:
|
|
+ mutex_unlock(&ue->card->user_ctl_lock);
|
|
+ if (ret)
|
|
+ return ret;
|
|
}
|
|
return change;
|
|
}
|
|
@@ -1137,8 +1166,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|
struct user_element *ue;
|
|
int idx, err;
|
|
|
|
- if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
|
|
- return -ENOMEM;
|
|
if (info->count < 1)
|
|
return -EINVAL;
|
|
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
|
@@ -1147,21 +1174,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
|
|
info->id.numid = 0;
|
|
memset(&kctl, 0, sizeof(kctl));
|
|
- down_write(&card->controls_rwsem);
|
|
- _kctl = snd_ctl_find_id(card, &info->id);
|
|
- err = 0;
|
|
- if (_kctl) {
|
|
- if (replace)
|
|
- err = snd_ctl_remove(card, _kctl);
|
|
- else
|
|
- err = -EBUSY;
|
|
- } else {
|
|
- if (replace)
|
|
- err = -ENOENT;
|
|
+
|
|
+ if (replace) {
|
|
+ err = snd_ctl_remove_user_ctl(file, &info->id);
|
|
+ if (err)
|
|
+ return err;
|
|
}
|
|
- up_write(&card->controls_rwsem);
|
|
- if (err < 0)
|
|
- return err;
|
|
+
|
|
+ if (card->user_ctl_count >= MAX_USER_CONTROLS)
|
|
+ return -ENOMEM;
|
|
+
|
|
memcpy(&kctl.id, &info->id, sizeof(info->id));
|
|
kctl.count = info->owner ? info->owner : 1;
|
|
access |= SNDRV_CTL_ELEM_ACCESS_USER;
|
|
@@ -1211,6 +1233,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|
ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
|
|
if (ue == NULL)
|
|
return -ENOMEM;
|
|
+ ue->card = card;
|
|
ue->info = *info;
|
|
ue->info.access = 0;
|
|
ue->elem_data = (char *)ue + sizeof(*ue);
|
|
@@ -1322,8 +1345,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
|
}
|
|
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
|
if (err > 0) {
|
|
+ struct snd_ctl_elem_id id = kctl->id;
|
|
up_read(&card->controls_rwsem);
|
|
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
|
|
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
|
|
return 0;
|
|
}
|
|
} else {
|
|
diff --git a/sound/core/init.c b/sound/core/init.c
|
|
index 6ef06400dfc8..27791a58e448 100644
|
|
--- a/sound/core/init.c
|
|
+++ b/sound/core/init.c
|
|
@@ -208,6 +208,7 @@ int snd_card_create(int idx, const char *xid,
|
|
INIT_LIST_HEAD(&card->devices);
|
|
init_rwsem(&card->controls_rwsem);
|
|
rwlock_init(&card->ctl_files_rwlock);
|
|
+ mutex_init(&card->user_ctl_lock);
|
|
INIT_LIST_HEAD(&card->controls);
|
|
INIT_LIST_HEAD(&card->ctl_files);
|
|
spin_lock_init(&card->files_lock);
|
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
|
index 0923f09df503..0b85e857f1c7 100644
|
|
--- a/sound/pci/hda/patch_realtek.c
|
|
+++ b/sound/pci/hda/patch_realtek.c
|
|
@@ -3356,6 +3356,7 @@ enum {
|
|
ALC269_FIXUP_STEREO_DMIC,
|
|
ALC269_FIXUP_QUANTA_MUTE,
|
|
ALC269_FIXUP_LIFEBOOK,
|
|
+ ALC269_FIXUP_LIFEBOOK_EXTMIC,
|
|
ALC269_FIXUP_AMIC,
|
|
ALC269_FIXUP_DMIC,
|
|
ALC269VB_FIXUP_AMIC,
|
|
@@ -3463,6 +3464,13 @@ static const struct hda_fixup alc269_fixups[] = {
|
|
.chained = true,
|
|
.chain_id = ALC269_FIXUP_QUANTA_MUTE
|
|
},
|
|
+ [ALC269_FIXUP_LIFEBOOK_EXTMIC] = {
|
|
+ .type = HDA_FIXUP_PINS,
|
|
+ .v.pins = (const struct hda_pintbl[]) {
|
|
+ { 0x19, 0x01a1903c }, /* headset mic, with jack detect */
|
|
+ { }
|
|
+ },
|
|
+ },
|
|
[ALC269_FIXUP_AMIC] = {
|
|
.type = HDA_FIXUP_PINS,
|
|
.v.pins = (const struct hda_pintbl[]) {
|
|
@@ -3713,6 +3721,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
|
|
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
|
|
SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
|
|
+ SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
|
|
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
|
|
SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
|
|
SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
|
|
@@ -4664,6 +4673,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
|
|
{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
|
|
{ .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 },
|
|
{ .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
|
|
+ { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 },
|
|
{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
|
|
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
|
|
{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
|
|
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
|
|
index 4fdcc1cefc25..9b7746c9546f 100644
|
|
--- a/sound/soc/codecs/max98090.c
|
|
+++ b/sound/soc/codecs/max98090.c
|
|
@@ -255,6 +255,7 @@ static struct reg_default max98090_reg[] = {
|
|
static bool max98090_volatile_register(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
+ case M98090_REG_SOFTWARE_RESET:
|
|
case M98090_REG_DEVICE_STATUS:
|
|
case M98090_REG_JACK_STATUS:
|
|
case M98090_REG_REVISION_ID:
|
|
@@ -2343,6 +2344,8 @@ static int max98090_runtime_resume(struct device *dev)
|
|
|
|
regcache_cache_only(max98090->regmap, false);
|
|
|
|
+ max98090_reset(max98090);
|
|
+
|
|
regcache_sync(max98090->regmap);
|
|
|
|
return 0;
|