Merge 5.10.33 into android12-5.10
Changes in 5.10.33 vhost-vdpa: protect concurrent access to vhost device iotlb gpio: omap: Save and restore sysconfig KEYS: trusted: Fix TPM reservation for seal/unseal vdpa/mlx5: Set err = -ENOMEM in case dma_map_sg_attrs fails pinctrl: lewisburg: Update number of pins in community block: return -EBUSY when there are open partitions in blkdev_reread_part pinctrl: core: Show pin numbers for the controllers with base = 0 arm64: dts: allwinner: Revert SD card CD GPIO for Pine64-LTS bpf: Permits pointers on stack for helper calls bpf: Allow variable-offset stack access bpf: Refactor and streamline bounds check into helper bpf: Tighten speculative pointer arithmetic mask locking/qrwlock: Fix ordering in queued_write_lock_slowpath() perf/x86/intel/uncore: Remove uncore extra PCI dev HSWEP_PCI_PCU_3 perf/x86/kvm: Fix Broadwell Xeon stepping in isolation_ucodes[] perf auxtrace: Fix potential NULL pointer dereference perf map: Fix error return code in maps__clone() HID: google: add don USB id HID: alps: fix error return code in alps_input_configured() HID cp2112: fix support for multiple gpiochips HID: wacom: Assign boolean values to a bool variable soc: qcom: geni: shield geni_icc_get() for ACPI boot dmaengine: xilinx: dpdma: Fix descriptor issuing on video group dmaengine: xilinx: dpdma: Fix race condition in done IRQ ARM: dts: Fix swapped mmc order for omap3 net: geneve: check skb is large enough for IPv4/IPv6 header dmaengine: tegra20: Fix runtime PM imbalance on error s390/entry: save the caller of psw_idle arm64: kprobes: Restore local irqflag if kprobes is cancelled xen-netback: Check for hotplug-status existence before watching cavium/liquidio: Fix duplicate argument kasan: fix hwasan build for gcc csky: change a Kconfig symbol name to fix e1000 build error ia64: fix discontig.c section mismatches ia64: tools: remove duplicate definition of ia64_mf() on ia64 x86/crash: Fix crash_setup_memmap_entries() out-of-bounds access net: hso: fix NULL-deref on disconnect regression USB: CDC-ACM: fix poison/unpoison imbalance Linux 5.10.33 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I638db3c919ad938eaaaac3d687175252edcd7990
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
VERSION = 5
|
VERSION = 5
|
||||||
PATCHLEVEL = 10
|
PATCHLEVEL = 10
|
||||||
SUBLEVEL = 32
|
SUBLEVEL = 33
|
||||||
EXTRAVERSION =
|
EXTRAVERSION =
|
||||||
NAME = Dare mighty things
|
NAME = Dare mighty things
|
||||||
|
|
||||||
|
@@ -24,6 +24,9 @@
|
|||||||
i2c0 = &i2c1;
|
i2c0 = &i2c1;
|
||||||
i2c1 = &i2c2;
|
i2c1 = &i2c2;
|
||||||
i2c2 = &i2c3;
|
i2c2 = &i2c3;
|
||||||
|
mmc0 = &mmc1;
|
||||||
|
mmc1 = &mmc2;
|
||||||
|
mmc2 = &mmc3;
|
||||||
serial0 = &uart1;
|
serial0 = &uart1;
|
||||||
serial1 = &uart2;
|
serial1 = &uart2;
|
||||||
serial2 = &uart3;
|
serial2 = &uart3;
|
||||||
|
@@ -10,5 +10,5 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
&mmc0 {
|
&mmc0 {
|
||||||
cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 push-push switch */
|
broken-cd; /* card detect is broken on *some* boards */
|
||||||
};
|
};
|
||||||
|
@@ -286,10 +286,12 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
|
|||||||
if (!instruction_pointer(regs))
|
if (!instruction_pointer(regs))
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
if (kcb->kprobe_status == KPROBE_REENTER)
|
if (kcb->kprobe_status == KPROBE_REENTER) {
|
||||||
restore_previous_kprobe(kcb);
|
restore_previous_kprobe(kcb);
|
||||||
else
|
} else {
|
||||||
|
kprobes_restore_local_irqflag(kcb, regs);
|
||||||
reset_current_kprobe();
|
reset_current_kprobe();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case KPROBE_HIT_ACTIVE:
|
case KPROBE_HIT_ACTIVE:
|
||||||
|
@@ -292,7 +292,7 @@ config FORCE_MAX_ZONEORDER
|
|||||||
int "Maximum zone order"
|
int "Maximum zone order"
|
||||||
default "11"
|
default "11"
|
||||||
|
|
||||||
config RAM_BASE
|
config DRAM_BASE
|
||||||
hex "DRAM start addr (the same with memory-section in dts)"
|
hex "DRAM start addr (the same with memory-section in dts)"
|
||||||
default 0x0
|
default 0x0
|
||||||
|
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
#define SSEG_SIZE 0x20000000
|
#define SSEG_SIZE 0x20000000
|
||||||
#define LOWMEM_LIMIT (SSEG_SIZE * 2)
|
#define LOWMEM_LIMIT (SSEG_SIZE * 2)
|
||||||
|
|
||||||
#define PHYS_OFFSET_OFFSET (CONFIG_RAM_BASE & (SSEG_SIZE - 1))
|
#define PHYS_OFFSET_OFFSET (CONFIG_DRAM_BASE & (SSEG_SIZE - 1))
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
@@ -94,7 +94,7 @@ static int __init build_node_maps(unsigned long start, unsigned long len,
|
|||||||
* acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
|
* acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
|
||||||
* called yet. Note that node 0 will also count all non-existent cpus.
|
* called yet. Note that node 0 will also count all non-existent cpus.
|
||||||
*/
|
*/
|
||||||
static int __meminit early_nr_cpus_node(int node)
|
static int early_nr_cpus_node(int node)
|
||||||
{
|
{
|
||||||
int cpu, n = 0;
|
int cpu, n = 0;
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ static int __meminit early_nr_cpus_node(int node)
|
|||||||
* compute_pernodesize - compute size of pernode data
|
* compute_pernodesize - compute size of pernode data
|
||||||
* @node: the node id.
|
* @node: the node id.
|
||||||
*/
|
*/
|
||||||
static unsigned long __meminit compute_pernodesize(int node)
|
static unsigned long compute_pernodesize(int node)
|
||||||
{
|
{
|
||||||
unsigned long pernodesize = 0, cpus;
|
unsigned long pernodesize = 0, cpus;
|
||||||
|
|
||||||
@@ -366,7 +366,7 @@ static void __init reserve_pernode_space(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __meminit scatter_node_data(void)
|
static void scatter_node_data(void)
|
||||||
{
|
{
|
||||||
pg_data_t **dst;
|
pg_data_t **dst;
|
||||||
int node;
|
int node;
|
||||||
|
@@ -994,6 +994,7 @@ ENDPROC(ext_int_handler)
|
|||||||
* Load idle PSW.
|
* Load idle PSW.
|
||||||
*/
|
*/
|
||||||
ENTRY(psw_idle)
|
ENTRY(psw_idle)
|
||||||
|
stg %r14,(__SF_GPRS+8*8)(%r15)
|
||||||
stg %r3,__SF_EMPTY(%r15)
|
stg %r3,__SF_EMPTY(%r15)
|
||||||
larl %r1,.Lpsw_idle_exit
|
larl %r1,.Lpsw_idle_exit
|
||||||
stg %r1,__SF_EMPTY+8(%r15)
|
stg %r1,__SF_EMPTY+8(%r15)
|
||||||
|
@@ -4387,7 +4387,7 @@ static const struct x86_cpu_desc isolation_ucodes[] = {
|
|||||||
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 3, 0x07000009),
|
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 3, 0x07000009),
|
||||||
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 4, 0x0f000009),
|
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 4, 0x0f000009),
|
||||||
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 5, 0x0e000002),
|
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_D, 5, 0x0e000002),
|
||||||
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_X, 2, 0x0b000014),
|
INTEL_CPU_DESC(INTEL_FAM6_BROADWELL_X, 1, 0x0b000014),
|
||||||
INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 3, 0x00000021),
|
INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 3, 0x00000021),
|
||||||
INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 4, 0x00000000),
|
INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 4, 0x00000000),
|
||||||
INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 5, 0x00000000),
|
INTEL_CPU_DESC(INTEL_FAM6_SKYLAKE_X, 5, 0x00000000),
|
||||||
|
@@ -1159,7 +1159,6 @@ enum {
|
|||||||
SNBEP_PCI_QPI_PORT0_FILTER,
|
SNBEP_PCI_QPI_PORT0_FILTER,
|
||||||
SNBEP_PCI_QPI_PORT1_FILTER,
|
SNBEP_PCI_QPI_PORT1_FILTER,
|
||||||
BDX_PCI_QPI_PORT2_FILTER,
|
BDX_PCI_QPI_PORT2_FILTER,
|
||||||
HSWEP_PCI_PCU_3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
|
static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
|
||||||
@@ -2816,22 +2815,33 @@ static struct intel_uncore_type *hswep_msr_uncores[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HSWEP_PCU_DID 0x2fc0
|
||||||
|
#define HSWEP_PCU_CAPID4_OFFET 0x94
|
||||||
|
#define hswep_get_chop(_cap) (((_cap) >> 6) & 0x3)
|
||||||
|
|
||||||
|
static bool hswep_has_limit_sbox(unsigned int device)
|
||||||
|
{
|
||||||
|
struct pci_dev *dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
|
||||||
|
u32 capid4;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pci_read_config_dword(dev, HSWEP_PCU_CAPID4_OFFET, &capid4);
|
||||||
|
if (!hswep_get_chop(capid4))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void hswep_uncore_cpu_init(void)
|
void hswep_uncore_cpu_init(void)
|
||||||
{
|
{
|
||||||
int pkg = boot_cpu_data.logical_proc_id;
|
|
||||||
|
|
||||||
if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
|
if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
|
||||||
hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
|
hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
|
||||||
|
|
||||||
/* Detect 6-8 core systems with only two SBOXes */
|
/* Detect 6-8 core systems with only two SBOXes */
|
||||||
if (uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3]) {
|
if (hswep_has_limit_sbox(HSWEP_PCU_DID))
|
||||||
u32 capid4;
|
|
||||||
|
|
||||||
pci_read_config_dword(uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3],
|
|
||||||
0x94, &capid4);
|
|
||||||
if (((capid4 >> 6) & 0x3) == 0)
|
|
||||||
hswep_uncore_sbox.num_boxes = 2;
|
hswep_uncore_sbox.num_boxes = 2;
|
||||||
}
|
|
||||||
|
|
||||||
uncore_msr_uncores = hswep_msr_uncores;
|
uncore_msr_uncores = hswep_msr_uncores;
|
||||||
}
|
}
|
||||||
@@ -3094,11 +3104,6 @@ static const struct pci_device_id hswep_uncore_pci_ids[] = {
|
|||||||
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
||||||
SNBEP_PCI_QPI_PORT1_FILTER),
|
SNBEP_PCI_QPI_PORT1_FILTER),
|
||||||
},
|
},
|
||||||
{ /* PCU.3 (for Capability registers) */
|
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fc0),
|
|
||||||
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
|
||||||
HSWEP_PCI_PCU_3),
|
|
||||||
},
|
|
||||||
{ /* end: all zeroes */ }
|
{ /* end: all zeroes */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3190,27 +3195,18 @@ static struct event_constraint bdx_uncore_pcu_constraints[] = {
|
|||||||
EVENT_CONSTRAINT_END
|
EVENT_CONSTRAINT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BDX_PCU_DID 0x6fc0
|
||||||
|
|
||||||
void bdx_uncore_cpu_init(void)
|
void bdx_uncore_cpu_init(void)
|
||||||
{
|
{
|
||||||
int pkg = topology_phys_to_logical_pkg(boot_cpu_data.phys_proc_id);
|
|
||||||
|
|
||||||
if (bdx_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
|
if (bdx_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
|
||||||
bdx_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
|
bdx_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
|
||||||
uncore_msr_uncores = bdx_msr_uncores;
|
uncore_msr_uncores = bdx_msr_uncores;
|
||||||
|
|
||||||
/* BDX-DE doesn't have SBOX */
|
|
||||||
if (boot_cpu_data.x86_model == 86) {
|
|
||||||
uncore_msr_uncores[BDX_MSR_UNCORE_SBOX] = NULL;
|
|
||||||
/* Detect systems with no SBOXes */
|
/* Detect systems with no SBOXes */
|
||||||
} else if (uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3]) {
|
if ((boot_cpu_data.x86_model == 86) || hswep_has_limit_sbox(BDX_PCU_DID))
|
||||||
struct pci_dev *pdev;
|
uncore_msr_uncores[BDX_MSR_UNCORE_SBOX] = NULL;
|
||||||
u32 capid4;
|
|
||||||
|
|
||||||
pdev = uncore_extra_pci_dev[pkg].dev[HSWEP_PCI_PCU_3];
|
|
||||||
pci_read_config_dword(pdev, 0x94, &capid4);
|
|
||||||
if (((capid4 >> 6) & 0x3) == 0)
|
|
||||||
bdx_msr_uncores[BDX_MSR_UNCORE_SBOX] = NULL;
|
|
||||||
}
|
|
||||||
hswep_uncore_pcu.constraints = bdx_uncore_pcu_constraints;
|
hswep_uncore_pcu.constraints = bdx_uncore_pcu_constraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3431,11 +3427,6 @@ static const struct pci_device_id bdx_uncore_pci_ids[] = {
|
|||||||
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
||||||
BDX_PCI_QPI_PORT2_FILTER),
|
BDX_PCI_QPI_PORT2_FILTER),
|
||||||
},
|
},
|
||||||
{ /* PCU.3 (for Capability registers) */
|
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fc0),
|
|
||||||
.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
|
|
||||||
HSWEP_PCI_PCU_3),
|
|
||||||
},
|
|
||||||
{ /* end: all zeroes */ }
|
{ /* end: all zeroes */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -337,7 +337,7 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params)
|
|||||||
struct crash_memmap_data cmd;
|
struct crash_memmap_data cmd;
|
||||||
struct crash_mem *cmem;
|
struct crash_mem *cmem;
|
||||||
|
|
||||||
cmem = vzalloc(sizeof(struct crash_mem));
|
cmem = vzalloc(struct_size(cmem, ranges, 1));
|
||||||
if (!cmem)
|
if (!cmem)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@@ -98,6 +98,8 @@ static int blkdev_reread_part(struct block_device *bdev, fmode_t mode)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
if (bdev->bd_part_count)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reopen the device to revalidate the driver state and force a
|
* Reopen the device to revalidate the driver state and force a
|
||||||
|
@@ -723,7 +723,7 @@ static void tegra_dma_issue_pending(struct dma_chan *dc)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (!tdc->busy) {
|
if (!tdc->busy) {
|
||||||
err = pm_runtime_get_sync(tdc->tdma->dev);
|
err = pm_runtime_resume_and_get(tdc->tdma->dev);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(tdc2dev(tdc), "Failed to enable DMA\n");
|
dev_err(tdc2dev(tdc), "Failed to enable DMA\n");
|
||||||
goto end;
|
goto end;
|
||||||
@@ -818,7 +818,7 @@ static void tegra_dma_synchronize(struct dma_chan *dc)
|
|||||||
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
|
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = pm_runtime_get_sync(tdc->tdma->dev);
|
err = pm_runtime_resume_and_get(tdc->tdma->dev);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(tdc2dev(tdc), "Failed to synchronize DMA: %d\n", err);
|
dev_err(tdc2dev(tdc), "Failed to synchronize DMA: %d\n", err);
|
||||||
return;
|
return;
|
||||||
|
@@ -839,6 +839,7 @@ static void xilinx_dpdma_chan_queue_transfer(struct xilinx_dpdma_chan *chan)
|
|||||||
struct xilinx_dpdma_tx_desc *desc;
|
struct xilinx_dpdma_tx_desc *desc;
|
||||||
struct virt_dma_desc *vdesc;
|
struct virt_dma_desc *vdesc;
|
||||||
u32 reg, channels;
|
u32 reg, channels;
|
||||||
|
bool first_frame;
|
||||||
|
|
||||||
lockdep_assert_held(&chan->lock);
|
lockdep_assert_held(&chan->lock);
|
||||||
|
|
||||||
@@ -852,14 +853,6 @@ static void xilinx_dpdma_chan_queue_transfer(struct xilinx_dpdma_chan *chan)
|
|||||||
chan->running = true;
|
chan->running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan->video_group)
|
|
||||||
channels = xilinx_dpdma_chan_video_group_ready(chan);
|
|
||||||
else
|
|
||||||
channels = BIT(chan->id);
|
|
||||||
|
|
||||||
if (!channels)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vdesc = vchan_next_desc(&chan->vchan);
|
vdesc = vchan_next_desc(&chan->vchan);
|
||||||
if (!vdesc)
|
if (!vdesc)
|
||||||
return;
|
return;
|
||||||
@@ -884,13 +877,26 @@ static void xilinx_dpdma_chan_queue_transfer(struct xilinx_dpdma_chan *chan)
|
|||||||
FIELD_PREP(XILINX_DPDMA_CH_DESC_START_ADDRE_MASK,
|
FIELD_PREP(XILINX_DPDMA_CH_DESC_START_ADDRE_MASK,
|
||||||
upper_32_bits(sw_desc->dma_addr)));
|
upper_32_bits(sw_desc->dma_addr)));
|
||||||
|
|
||||||
if (chan->first_frame)
|
first_frame = chan->first_frame;
|
||||||
|
chan->first_frame = false;
|
||||||
|
|
||||||
|
if (chan->video_group) {
|
||||||
|
channels = xilinx_dpdma_chan_video_group_ready(chan);
|
||||||
|
/*
|
||||||
|
* Trigger the transfer only when all channels in the group are
|
||||||
|
* ready.
|
||||||
|
*/
|
||||||
|
if (!channels)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
channels = BIT(chan->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_frame)
|
||||||
reg = XILINX_DPDMA_GBL_TRIG_MASK(channels);
|
reg = XILINX_DPDMA_GBL_TRIG_MASK(channels);
|
||||||
else
|
else
|
||||||
reg = XILINX_DPDMA_GBL_RETRIG_MASK(channels);
|
reg = XILINX_DPDMA_GBL_RETRIG_MASK(channels);
|
||||||
|
|
||||||
chan->first_frame = false;
|
|
||||||
|
|
||||||
dpdma_write(xdev->reg, XILINX_DPDMA_GBL, reg);
|
dpdma_write(xdev->reg, XILINX_DPDMA_GBL, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,13 +1048,14 @@ static int xilinx_dpdma_chan_stop(struct xilinx_dpdma_chan *chan)
|
|||||||
*/
|
*/
|
||||||
static void xilinx_dpdma_chan_done_irq(struct xilinx_dpdma_chan *chan)
|
static void xilinx_dpdma_chan_done_irq(struct xilinx_dpdma_chan *chan)
|
||||||
{
|
{
|
||||||
struct xilinx_dpdma_tx_desc *active = chan->desc.active;
|
struct xilinx_dpdma_tx_desc *active;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&chan->lock, flags);
|
spin_lock_irqsave(&chan->lock, flags);
|
||||||
|
|
||||||
xilinx_dpdma_debugfs_desc_done_irq(chan);
|
xilinx_dpdma_debugfs_desc_done_irq(chan);
|
||||||
|
|
||||||
|
active = chan->desc.active;
|
||||||
if (active)
|
if (active)
|
||||||
vchan_cyclic_callback(&active->vdesc);
|
vchan_cyclic_callback(&active->vdesc);
|
||||||
else
|
else
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
|
#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
|
||||||
|
|
||||||
struct gpio_regs {
|
struct gpio_regs {
|
||||||
|
u32 sysconfig;
|
||||||
u32 irqenable1;
|
u32 irqenable1;
|
||||||
u32 irqenable2;
|
u32 irqenable2;
|
||||||
u32 wake_en;
|
u32 wake_en;
|
||||||
@@ -1072,6 +1073,7 @@ static void omap_gpio_init_context(struct gpio_bank *p)
|
|||||||
const struct omap_gpio_reg_offs *regs = p->regs;
|
const struct omap_gpio_reg_offs *regs = p->regs;
|
||||||
void __iomem *base = p->base;
|
void __iomem *base = p->base;
|
||||||
|
|
||||||
|
p->context.sysconfig = readl_relaxed(base + regs->sysconfig);
|
||||||
p->context.ctrl = readl_relaxed(base + regs->ctrl);
|
p->context.ctrl = readl_relaxed(base + regs->ctrl);
|
||||||
p->context.oe = readl_relaxed(base + regs->direction);
|
p->context.oe = readl_relaxed(base + regs->direction);
|
||||||
p->context.wake_en = readl_relaxed(base + regs->wkup_en);
|
p->context.wake_en = readl_relaxed(base + regs->wkup_en);
|
||||||
@@ -1091,6 +1093,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
|
|||||||
const struct omap_gpio_reg_offs *regs = bank->regs;
|
const struct omap_gpio_reg_offs *regs = bank->regs;
|
||||||
void __iomem *base = bank->base;
|
void __iomem *base = bank->base;
|
||||||
|
|
||||||
|
writel_relaxed(bank->context.sysconfig, base + regs->sysconfig);
|
||||||
writel_relaxed(bank->context.wake_en, base + regs->wkup_en);
|
writel_relaxed(bank->context.wake_en, base + regs->wkup_en);
|
||||||
writel_relaxed(bank->context.ctrl, base + regs->ctrl);
|
writel_relaxed(bank->context.ctrl, base + regs->ctrl);
|
||||||
writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0);
|
writel_relaxed(bank->context.leveldetect0, base + regs->leveldetect0);
|
||||||
@@ -1118,6 +1121,10 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
|
|||||||
|
|
||||||
bank->saved_datain = readl_relaxed(base + bank->regs->datain);
|
bank->saved_datain = readl_relaxed(base + bank->regs->datain);
|
||||||
|
|
||||||
|
/* Save syconfig, it's runtime value can be different from init value */
|
||||||
|
if (bank->loses_context)
|
||||||
|
bank->context.sysconfig = readl_relaxed(base + bank->regs->sysconfig);
|
||||||
|
|
||||||
if (!bank->enabled_non_wakeup_gpios)
|
if (!bank->enabled_non_wakeup_gpios)
|
||||||
goto update_gpio_context_count;
|
goto update_gpio_context_count;
|
||||||
|
|
||||||
@@ -1282,6 +1289,7 @@ out_unlock:
|
|||||||
|
|
||||||
static const struct omap_gpio_reg_offs omap2_gpio_regs = {
|
static const struct omap_gpio_reg_offs omap2_gpio_regs = {
|
||||||
.revision = OMAP24XX_GPIO_REVISION,
|
.revision = OMAP24XX_GPIO_REVISION,
|
||||||
|
.sysconfig = OMAP24XX_GPIO_SYSCONFIG,
|
||||||
.direction = OMAP24XX_GPIO_OE,
|
.direction = OMAP24XX_GPIO_OE,
|
||||||
.datain = OMAP24XX_GPIO_DATAIN,
|
.datain = OMAP24XX_GPIO_DATAIN,
|
||||||
.dataout = OMAP24XX_GPIO_DATAOUT,
|
.dataout = OMAP24XX_GPIO_DATAOUT,
|
||||||
@@ -1305,6 +1313,7 @@ static const struct omap_gpio_reg_offs omap2_gpio_regs = {
|
|||||||
|
|
||||||
static const struct omap_gpio_reg_offs omap4_gpio_regs = {
|
static const struct omap_gpio_reg_offs omap4_gpio_regs = {
|
||||||
.revision = OMAP4_GPIO_REVISION,
|
.revision = OMAP4_GPIO_REVISION,
|
||||||
|
.sysconfig = OMAP4_GPIO_SYSCONFIG,
|
||||||
.direction = OMAP4_GPIO_OE,
|
.direction = OMAP4_GPIO_OE,
|
||||||
.datain = OMAP4_GPIO_DATAIN,
|
.datain = OMAP4_GPIO_DATAIN,
|
||||||
.dataout = OMAP4_GPIO_DATAOUT,
|
.dataout = OMAP4_GPIO_DATAOUT,
|
||||||
|
@@ -761,6 +761,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||||||
|
|
||||||
if (input_register_device(data->input2)) {
|
if (input_register_device(data->input2)) {
|
||||||
input_free_device(input2);
|
input_free_device(input2);
|
||||||
|
ret = -ENOENT;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -161,6 +161,7 @@ struct cp2112_device {
|
|||||||
atomic_t read_avail;
|
atomic_t read_avail;
|
||||||
atomic_t xfer_avail;
|
atomic_t xfer_avail;
|
||||||
struct gpio_chip gc;
|
struct gpio_chip gc;
|
||||||
|
struct irq_chip irq;
|
||||||
u8 *in_out_buffer;
|
u8 *in_out_buffer;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
|
||||||
@@ -1175,16 +1176,6 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip cp2112_gpio_irqchip = {
|
|
||||||
.name = "cp2112-gpio",
|
|
||||||
.irq_startup = cp2112_gpio_irq_startup,
|
|
||||||
.irq_shutdown = cp2112_gpio_irq_shutdown,
|
|
||||||
.irq_ack = cp2112_gpio_irq_ack,
|
|
||||||
.irq_mask = cp2112_gpio_irq_mask,
|
|
||||||
.irq_unmask = cp2112_gpio_irq_unmask,
|
|
||||||
.irq_set_type = cp2112_gpio_irq_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
|
static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
|
||||||
int pin)
|
int pin)
|
||||||
{
|
{
|
||||||
@@ -1339,8 +1330,17 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||||||
dev->gc.can_sleep = 1;
|
dev->gc.can_sleep = 1;
|
||||||
dev->gc.parent = &hdev->dev;
|
dev->gc.parent = &hdev->dev;
|
||||||
|
|
||||||
|
dev->irq.name = "cp2112-gpio";
|
||||||
|
dev->irq.irq_startup = cp2112_gpio_irq_startup;
|
||||||
|
dev->irq.irq_shutdown = cp2112_gpio_irq_shutdown;
|
||||||
|
dev->irq.irq_ack = cp2112_gpio_irq_ack;
|
||||||
|
dev->irq.irq_mask = cp2112_gpio_irq_mask;
|
||||||
|
dev->irq.irq_unmask = cp2112_gpio_irq_unmask;
|
||||||
|
dev->irq.irq_set_type = cp2112_gpio_irq_type;
|
||||||
|
dev->irq.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||||
|
|
||||||
girq = &dev->gc.irq;
|
girq = &dev->gc.irq;
|
||||||
girq->chip = &cp2112_gpio_irqchip;
|
girq->chip = &dev->irq;
|
||||||
/* The event comes from the outside so no parent handler */
|
/* The event comes from the outside so no parent handler */
|
||||||
girq->parent_handler = NULL;
|
girq->parent_handler = NULL;
|
||||||
girq->num_parents = 0;
|
girq->num_parents = 0;
|
||||||
|
@@ -526,6 +526,8 @@ static void hammer_remove(struct hid_device *hdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct hid_device_id hammer_devices[] = {
|
static const struct hid_device_id hammer_devices[] = {
|
||||||
|
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||||
|
USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) },
|
||||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||||
USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
|
USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
|
||||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||||
|
@@ -486,6 +486,7 @@
|
|||||||
#define USB_DEVICE_ID_GOOGLE_MASTERBALL 0x503c
|
#define USB_DEVICE_ID_GOOGLE_MASTERBALL 0x503c
|
||||||
#define USB_DEVICE_ID_GOOGLE_MAGNEMITE 0x503d
|
#define USB_DEVICE_ID_GOOGLE_MAGNEMITE 0x503d
|
||||||
#define USB_DEVICE_ID_GOOGLE_MOONBALL 0x5044
|
#define USB_DEVICE_ID_GOOGLE_MOONBALL 0x5044
|
||||||
|
#define USB_DEVICE_ID_GOOGLE_DON 0x5050
|
||||||
|
|
||||||
#define USB_VENDOR_ID_GOTOP 0x08f2
|
#define USB_VENDOR_ID_GOTOP 0x08f2
|
||||||
#define USB_DEVICE_ID_SUPER_Q2 0x007f
|
#define USB_DEVICE_ID_SUPER_Q2 0x007f
|
||||||
|
@@ -2533,7 +2533,7 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
|
|||||||
!wacom_wac->shared->is_touch_on) {
|
!wacom_wac->shared->is_touch_on) {
|
||||||
if (!wacom_wac->shared->touch_down)
|
if (!wacom_wac->shared->touch_down)
|
||||||
return;
|
return;
|
||||||
prox = 0;
|
prox = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wacom_wac->hid_data.num_received++;
|
wacom_wac->hid_data.num_received++;
|
||||||
|
@@ -412,7 +412,7 @@
|
|||||||
| CN6XXX_INTR_M0UNWI_ERR \
|
| CN6XXX_INTR_M0UNWI_ERR \
|
||||||
| CN6XXX_INTR_M1UPB0_ERR \
|
| CN6XXX_INTR_M1UPB0_ERR \
|
||||||
| CN6XXX_INTR_M1UPWI_ERR \
|
| CN6XXX_INTR_M1UPWI_ERR \
|
||||||
| CN6XXX_INTR_M1UPB0_ERR \
|
| CN6XXX_INTR_M1UNB0_ERR \
|
||||||
| CN6XXX_INTR_M1UNWI_ERR \
|
| CN6XXX_INTR_M1UNWI_ERR \
|
||||||
| CN6XXX_INTR_INSTR_DB_OF_ERR \
|
| CN6XXX_INTR_INSTR_DB_OF_ERR \
|
||||||
| CN6XXX_INTR_SLIST_DB_OF_ERR \
|
| CN6XXX_INTR_SLIST_DB_OF_ERR \
|
||||||
|
@@ -890,6 +890,9 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
|
|||||||
__be16 sport;
|
__be16 sport;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
|
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
|
||||||
rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
|
rt = geneve_get_v4_rt(skb, dev, gs4, &fl4, info,
|
||||||
geneve->cfg.info.key.tp_dst, sport);
|
geneve->cfg.info.key.tp_dst, sport);
|
||||||
@@ -984,6 +987,9 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
|
|||||||
__be16 sport;
|
__be16 sport;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
|
sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
|
||||||
dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
|
dst = geneve_get_v6_dst(skb, dev, gs6, &fl6, info,
|
||||||
geneve->cfg.info.key.tp_dst, sport);
|
geneve->cfg.info.key.tp_dst, sport);
|
||||||
|
@@ -3104,7 +3104,7 @@ static void hso_free_interface(struct usb_interface *interface)
|
|||||||
cancel_work_sync(&serial_table[i]->async_put_intf);
|
cancel_work_sync(&serial_table[i]->async_put_intf);
|
||||||
cancel_work_sync(&serial_table[i]->async_get_intf);
|
cancel_work_sync(&serial_table[i]->async_get_intf);
|
||||||
hso_serial_tty_unregister(serial);
|
hso_serial_tty_unregister(serial);
|
||||||
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
|
kref_put(&serial->parent->ref, hso_serial_ref_free);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -824,11 +824,15 @@ static void connect(struct backend_info *be)
|
|||||||
xenvif_carrier_on(be->vif);
|
xenvif_carrier_on(be->vif);
|
||||||
|
|
||||||
unregister_hotplug_status_watch(be);
|
unregister_hotplug_status_watch(be);
|
||||||
err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, NULL,
|
if (xenbus_exists(XBT_NIL, dev->nodename, "hotplug-status")) {
|
||||||
hotplug_status_changed,
|
err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
|
||||||
"%s/%s", dev->nodename, "hotplug-status");
|
NULL, hotplug_status_changed,
|
||||||
if (!err)
|
"%s/%s", dev->nodename,
|
||||||
|
"hotplug-status");
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
be->have_hotplug_status_watch = 1;
|
be->have_hotplug_status_watch = 1;
|
||||||
|
}
|
||||||
|
|
||||||
netif_tx_wake_all_queues(be->vif->dev);
|
netif_tx_wake_all_queues(be->vif->dev);
|
||||||
|
|
||||||
|
@@ -1604,8 +1604,8 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
|
|||||||
unsigned i, pin;
|
unsigned i, pin;
|
||||||
#ifdef CONFIG_GPIOLIB
|
#ifdef CONFIG_GPIOLIB
|
||||||
struct pinctrl_gpio_range *range;
|
struct pinctrl_gpio_range *range;
|
||||||
unsigned int gpio_num;
|
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
|
int gpio_num;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
|
seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
|
||||||
@@ -1625,7 +1625,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
|
|||||||
seq_printf(s, "pin %d (%s) ", pin, desc->name);
|
seq_printf(s, "pin %d (%s) ", pin, desc->name);
|
||||||
|
|
||||||
#ifdef CONFIG_GPIOLIB
|
#ifdef CONFIG_GPIOLIB
|
||||||
gpio_num = 0;
|
gpio_num = -1;
|
||||||
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
|
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
|
||||||
if ((pin >= range->pin_base) &&
|
if ((pin >= range->pin_base) &&
|
||||||
(pin < (range->pin_base + range->npins))) {
|
(pin < (range->pin_base + range->npins))) {
|
||||||
@@ -1633,10 +1633,12 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (gpio_num >= 0)
|
||||||
chip = gpio_to_chip(gpio_num);
|
chip = gpio_to_chip(gpio_num);
|
||||||
if (chip && chip->gpiodev && chip->gpiodev->base)
|
else
|
||||||
seq_printf(s, "%u:%s ", gpio_num -
|
chip = NULL;
|
||||||
chip->gpiodev->base, chip->label);
|
if (chip)
|
||||||
|
seq_printf(s, "%u:%s ", gpio_num - chip->gpiodev->base, chip->label);
|
||||||
else
|
else
|
||||||
seq_puts(s, "0:? ");
|
seq_puts(s, "0:? ");
|
||||||
#endif
|
#endif
|
||||||
|
@@ -299,9 +299,9 @@ static const struct pinctrl_pin_desc lbg_pins[] = {
|
|||||||
static const struct intel_community lbg_communities[] = {
|
static const struct intel_community lbg_communities[] = {
|
||||||
LBG_COMMUNITY(0, 0, 71),
|
LBG_COMMUNITY(0, 0, 71),
|
||||||
LBG_COMMUNITY(1, 72, 132),
|
LBG_COMMUNITY(1, 72, 132),
|
||||||
LBG_COMMUNITY(3, 133, 144),
|
LBG_COMMUNITY(3, 133, 143),
|
||||||
LBG_COMMUNITY(4, 145, 180),
|
LBG_COMMUNITY(4, 144, 178),
|
||||||
LBG_COMMUNITY(5, 181, 246),
|
LBG_COMMUNITY(5, 179, 246),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_pinctrl_soc_data lbg_soc_data = {
|
static const struct intel_pinctrl_soc_data lbg_soc_data = {
|
||||||
|
@@ -741,6 +741,9 @@ int geni_icc_get(struct geni_se *se, const char *icc_ddr)
|
|||||||
int i, err;
|
int i, err;
|
||||||
const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};
|
const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};
|
||||||
|
|
||||||
|
if (has_acpi_companion(se->dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
|
for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
|
||||||
if (!icc_names[i])
|
if (!icc_names[i])
|
||||||
continue;
|
continue;
|
||||||
|
@@ -1637,12 +1637,13 @@ static int acm_resume(struct usb_interface *intf)
|
|||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
acm_unpoison_urbs(acm);
|
|
||||||
spin_lock_irq(&acm->write_lock);
|
spin_lock_irq(&acm->write_lock);
|
||||||
|
|
||||||
if (--acm->susp_count)
|
if (--acm->susp_count)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
acm_unpoison_urbs(acm);
|
||||||
|
|
||||||
if (tty_port_initialized(&acm->port)) {
|
if (tty_port_initialized(&acm->port)) {
|
||||||
rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
|
rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
|
||||||
|
|
||||||
|
@@ -273,8 +273,10 @@ done:
|
|||||||
mr->log_size = log_entity_size;
|
mr->log_size = log_entity_size;
|
||||||
mr->nsg = nsg;
|
mr->nsg = nsg;
|
||||||
mr->nent = dma_map_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
|
mr->nent = dma_map_sg_attrs(dma, mr->sg_head.sgl, mr->nsg, DMA_BIDIRECTIONAL, 0);
|
||||||
if (!mr->nent)
|
if (!mr->nent) {
|
||||||
|
err = -ENOMEM;
|
||||||
goto err_map;
|
goto err_map;
|
||||||
|
}
|
||||||
|
|
||||||
err = create_direct_mr(mvdev, mr);
|
err = create_direct_mr(mvdev, mr);
|
||||||
if (err)
|
if (err)
|
||||||
|
@@ -749,9 +749,11 @@ static int vhost_vdpa_process_iotlb_msg(struct vhost_dev *dev,
|
|||||||
const struct vdpa_config_ops *ops = vdpa->config;
|
const struct vdpa_config_ops *ops = vdpa->config;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
|
mutex_lock(&dev->mutex);
|
||||||
|
|
||||||
r = vhost_dev_check_owner(dev);
|
r = vhost_dev_check_owner(dev);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
goto unlock;
|
||||||
|
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case VHOST_IOTLB_UPDATE:
|
case VHOST_IOTLB_UPDATE:
|
||||||
@@ -772,6 +774,8 @@ static int vhost_vdpa_process_iotlb_msg(struct vhost_dev *dev,
|
|||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&dev->mutex);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@@ -1259,6 +1259,11 @@ static inline bool bpf_allow_ptr_leaks(void)
|
|||||||
return perfmon_capable();
|
return perfmon_capable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool bpf_allow_uninit_stack(void)
|
||||||
|
{
|
||||||
|
return perfmon_capable();
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool bpf_allow_ptr_to_map_access(void)
|
static inline bool bpf_allow_ptr_to_map_access(void)
|
||||||
{
|
{
|
||||||
return perfmon_capable();
|
return perfmon_capable();
|
||||||
|
@@ -187,7 +187,7 @@ struct bpf_func_state {
|
|||||||
* 0 = main function, 1 = first callee.
|
* 0 = main function, 1 = first callee.
|
||||||
*/
|
*/
|
||||||
u32 frameno;
|
u32 frameno;
|
||||||
/* subprog number == index within subprog_stack_depth
|
/* subprog number == index within subprog_info
|
||||||
* zero == main subprog
|
* zero == main subprog
|
||||||
*/
|
*/
|
||||||
u32 subprogno;
|
u32 subprogno;
|
||||||
@@ -390,6 +390,7 @@ struct bpf_verifier_env {
|
|||||||
u32 used_map_cnt; /* number of used maps */
|
u32 used_map_cnt; /* number of used maps */
|
||||||
u32 id_gen; /* used to generate unique reg IDs */
|
u32 id_gen; /* used to generate unique reg IDs */
|
||||||
bool allow_ptr_leaks;
|
bool allow_ptr_leaks;
|
||||||
|
bool allow_uninit_stack;
|
||||||
bool allow_ptr_to_map_access;
|
bool allow_ptr_to_map_access;
|
||||||
bool bpf_capable;
|
bool bpf_capable;
|
||||||
bool bypass_spec_v1;
|
bool bypass_spec_v1;
|
||||||
|
@@ -85,6 +85,7 @@
|
|||||||
* omap2+ specific GPIO registers
|
* omap2+ specific GPIO registers
|
||||||
*/
|
*/
|
||||||
#define OMAP24XX_GPIO_REVISION 0x0000
|
#define OMAP24XX_GPIO_REVISION 0x0000
|
||||||
|
#define OMAP24XX_GPIO_SYSCONFIG 0x0010
|
||||||
#define OMAP24XX_GPIO_IRQSTATUS1 0x0018
|
#define OMAP24XX_GPIO_IRQSTATUS1 0x0018
|
||||||
#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
|
#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
|
||||||
#define OMAP24XX_GPIO_IRQENABLE2 0x002c
|
#define OMAP24XX_GPIO_IRQENABLE2 0x002c
|
||||||
@@ -108,6 +109,7 @@
|
|||||||
#define OMAP24XX_GPIO_SETDATAOUT 0x0094
|
#define OMAP24XX_GPIO_SETDATAOUT 0x0094
|
||||||
|
|
||||||
#define OMAP4_GPIO_REVISION 0x0000
|
#define OMAP4_GPIO_REVISION 0x0000
|
||||||
|
#define OMAP4_GPIO_SYSCONFIG 0x0010
|
||||||
#define OMAP4_GPIO_EOI 0x0020
|
#define OMAP4_GPIO_EOI 0x0020
|
||||||
#define OMAP4_GPIO_IRQSTATUSRAW0 0x0024
|
#define OMAP4_GPIO_IRQSTATUSRAW0 0x0024
|
||||||
#define OMAP4_GPIO_IRQSTATUSRAW1 0x0028
|
#define OMAP4_GPIO_IRQSTATUSRAW1 0x0028
|
||||||
@@ -148,6 +150,7 @@
|
|||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
struct omap_gpio_reg_offs {
|
struct omap_gpio_reg_offs {
|
||||||
u16 revision;
|
u16 revision;
|
||||||
|
u16 sysconfig;
|
||||||
u16 direction;
|
u16 direction;
|
||||||
u16 datain;
|
u16 datain;
|
||||||
u16 dataout;
|
u16 dataout;
|
||||||
|
@@ -2268,12 +2268,14 @@ static void save_register_state(struct bpf_func_state *state,
|
|||||||
state->stack[spi].slot_type[i] = STACK_SPILL;
|
state->stack[spi].slot_type[i] = STACK_SPILL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check_stack_read/write functions track spill/fill of registers,
|
/* check_stack_{read,write}_fixed_off functions track spill/fill of registers,
|
||||||
* stack boundary and alignment are checked in check_mem_access()
|
* stack boundary and alignment are checked in check_mem_access()
|
||||||
*/
|
*/
|
||||||
static int check_stack_write(struct bpf_verifier_env *env,
|
static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
|
||||||
struct bpf_func_state *state, /* func where register points to */
|
/* stack frame we're writing to */
|
||||||
int off, int size, int value_regno, int insn_idx)
|
struct bpf_func_state *state,
|
||||||
|
int off, int size, int value_regno,
|
||||||
|
int insn_idx)
|
||||||
{
|
{
|
||||||
struct bpf_func_state *cur; /* state of the current function */
|
struct bpf_func_state *cur; /* state of the current function */
|
||||||
int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err;
|
int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err;
|
||||||
@@ -2399,9 +2401,175 @@ static int check_stack_write(struct bpf_verifier_env *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_stack_read(struct bpf_verifier_env *env,
|
/* Write the stack: 'stack[ptr_regno + off] = value_regno'. 'ptr_regno' is
|
||||||
struct bpf_func_state *reg_state /* func where register points to */,
|
* known to contain a variable offset.
|
||||||
int off, int size, int value_regno)
|
* This function checks whether the write is permitted and conservatively
|
||||||
|
* tracks the effects of the write, considering that each stack slot in the
|
||||||
|
* dynamic range is potentially written to.
|
||||||
|
*
|
||||||
|
* 'off' includes 'regno->off'.
|
||||||
|
* 'value_regno' can be -1, meaning that an unknown value is being written to
|
||||||
|
* the stack.
|
||||||
|
*
|
||||||
|
* Spilled pointers in range are not marked as written because we don't know
|
||||||
|
* what's going to be actually written. This means that read propagation for
|
||||||
|
* future reads cannot be terminated by this write.
|
||||||
|
*
|
||||||
|
* For privileged programs, uninitialized stack slots are considered
|
||||||
|
* initialized by this write (even though we don't know exactly what offsets
|
||||||
|
* are going to be written to). The idea is that we don't want the verifier to
|
||||||
|
* reject future reads that access slots written to through variable offsets.
|
||||||
|
*/
|
||||||
|
static int check_stack_write_var_off(struct bpf_verifier_env *env,
|
||||||
|
/* func where register points to */
|
||||||
|
struct bpf_func_state *state,
|
||||||
|
int ptr_regno, int off, int size,
|
||||||
|
int value_regno, int insn_idx)
|
||||||
|
{
|
||||||
|
struct bpf_func_state *cur; /* state of the current function */
|
||||||
|
int min_off, max_off;
|
||||||
|
int i, err;
|
||||||
|
struct bpf_reg_state *ptr_reg = NULL, *value_reg = NULL;
|
||||||
|
bool writing_zero = false;
|
||||||
|
/* set if the fact that we're writing a zero is used to let any
|
||||||
|
* stack slots remain STACK_ZERO
|
||||||
|
*/
|
||||||
|
bool zero_used = false;
|
||||||
|
|
||||||
|
cur = env->cur_state->frame[env->cur_state->curframe];
|
||||||
|
ptr_reg = &cur->regs[ptr_regno];
|
||||||
|
min_off = ptr_reg->smin_value + off;
|
||||||
|
max_off = ptr_reg->smax_value + off + size;
|
||||||
|
if (value_regno >= 0)
|
||||||
|
value_reg = &cur->regs[value_regno];
|
||||||
|
if (value_reg && register_is_null(value_reg))
|
||||||
|
writing_zero = true;
|
||||||
|
|
||||||
|
err = realloc_func_state(state, round_up(-min_off, BPF_REG_SIZE),
|
||||||
|
state->acquired_refs, true);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
|
||||||
|
/* Variable offset writes destroy any spilled pointers in range. */
|
||||||
|
for (i = min_off; i < max_off; i++) {
|
||||||
|
u8 new_type, *stype;
|
||||||
|
int slot, spi;
|
||||||
|
|
||||||
|
slot = -i - 1;
|
||||||
|
spi = slot / BPF_REG_SIZE;
|
||||||
|
stype = &state->stack[spi].slot_type[slot % BPF_REG_SIZE];
|
||||||
|
|
||||||
|
if (!env->allow_ptr_leaks
|
||||||
|
&& *stype != NOT_INIT
|
||||||
|
&& *stype != SCALAR_VALUE) {
|
||||||
|
/* Reject the write if there's are spilled pointers in
|
||||||
|
* range. If we didn't reject here, the ptr status
|
||||||
|
* would be erased below (even though not all slots are
|
||||||
|
* actually overwritten), possibly opening the door to
|
||||||
|
* leaks.
|
||||||
|
*/
|
||||||
|
verbose(env, "spilled ptr in range of var-offset stack write; insn %d, ptr off: %d",
|
||||||
|
insn_idx, i);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Erase all spilled pointers. */
|
||||||
|
state->stack[spi].spilled_ptr.type = NOT_INIT;
|
||||||
|
|
||||||
|
/* Update the slot type. */
|
||||||
|
new_type = STACK_MISC;
|
||||||
|
if (writing_zero && *stype == STACK_ZERO) {
|
||||||
|
new_type = STACK_ZERO;
|
||||||
|
zero_used = true;
|
||||||
|
}
|
||||||
|
/* If the slot is STACK_INVALID, we check whether it's OK to
|
||||||
|
* pretend that it will be initialized by this write. The slot
|
||||||
|
* might not actually be written to, and so if we mark it as
|
||||||
|
* initialized future reads might leak uninitialized memory.
|
||||||
|
* For privileged programs, we will accept such reads to slots
|
||||||
|
* that may or may not be written because, if we're reject
|
||||||
|
* them, the error would be too confusing.
|
||||||
|
*/
|
||||||
|
if (*stype == STACK_INVALID && !env->allow_uninit_stack) {
|
||||||
|
verbose(env, "uninit stack in range of var-offset write prohibited for !root; insn %d, off: %d",
|
||||||
|
insn_idx, i);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*stype = new_type;
|
||||||
|
}
|
||||||
|
if (zero_used) {
|
||||||
|
/* backtracking doesn't work for STACK_ZERO yet. */
|
||||||
|
err = mark_chain_precision(env, value_regno);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When register 'dst_regno' is assigned some values from stack[min_off,
|
||||||
|
* max_off), we set the register's type according to the types of the
|
||||||
|
* respective stack slots. If all the stack values are known to be zeros, then
|
||||||
|
* so is the destination reg. Otherwise, the register is considered to be
|
||||||
|
* SCALAR. This function does not deal with register filling; the caller must
|
||||||
|
* ensure that all spilled registers in the stack range have been marked as
|
||||||
|
* read.
|
||||||
|
*/
|
||||||
|
static void mark_reg_stack_read(struct bpf_verifier_env *env,
|
||||||
|
/* func where src register points to */
|
||||||
|
struct bpf_func_state *ptr_state,
|
||||||
|
int min_off, int max_off, int dst_regno)
|
||||||
|
{
|
||||||
|
struct bpf_verifier_state *vstate = env->cur_state;
|
||||||
|
struct bpf_func_state *state = vstate->frame[vstate->curframe];
|
||||||
|
int i, slot, spi;
|
||||||
|
u8 *stype;
|
||||||
|
int zeros = 0;
|
||||||
|
|
||||||
|
for (i = min_off; i < max_off; i++) {
|
||||||
|
slot = -i - 1;
|
||||||
|
spi = slot / BPF_REG_SIZE;
|
||||||
|
stype = ptr_state->stack[spi].slot_type;
|
||||||
|
if (stype[slot % BPF_REG_SIZE] != STACK_ZERO)
|
||||||
|
break;
|
||||||
|
zeros++;
|
||||||
|
}
|
||||||
|
if (zeros == max_off - min_off) {
|
||||||
|
/* any access_size read into register is zero extended,
|
||||||
|
* so the whole register == const_zero
|
||||||
|
*/
|
||||||
|
__mark_reg_const_zero(&state->regs[dst_regno]);
|
||||||
|
/* backtracking doesn't support STACK_ZERO yet,
|
||||||
|
* so mark it precise here, so that later
|
||||||
|
* backtracking can stop here.
|
||||||
|
* Backtracking may not need this if this register
|
||||||
|
* doesn't participate in pointer adjustment.
|
||||||
|
* Forward propagation of precise flag is not
|
||||||
|
* necessary either. This mark is only to stop
|
||||||
|
* backtracking. Any register that contributed
|
||||||
|
* to const 0 was marked precise before spill.
|
||||||
|
*/
|
||||||
|
state->regs[dst_regno].precise = true;
|
||||||
|
} else {
|
||||||
|
/* have read misc data from the stack */
|
||||||
|
mark_reg_unknown(env, state->regs, dst_regno);
|
||||||
|
}
|
||||||
|
state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the stack at 'off' and put the results into the register indicated by
|
||||||
|
* 'dst_regno'. It handles reg filling if the addressed stack slot is a
|
||||||
|
* spilled reg.
|
||||||
|
*
|
||||||
|
* 'dst_regno' can be -1, meaning that the read value is not going to a
|
||||||
|
* register.
|
||||||
|
*
|
||||||
|
* The access is assumed to be within the current stack bounds.
|
||||||
|
*/
|
||||||
|
static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
|
||||||
|
/* func where src register points to */
|
||||||
|
struct bpf_func_state *reg_state,
|
||||||
|
int off, int size, int dst_regno)
|
||||||
{
|
{
|
||||||
struct bpf_verifier_state *vstate = env->cur_state;
|
struct bpf_verifier_state *vstate = env->cur_state;
|
||||||
struct bpf_func_state *state = vstate->frame[vstate->curframe];
|
struct bpf_func_state *state = vstate->frame[vstate->curframe];
|
||||||
@@ -2409,11 +2577,6 @@ static int check_stack_read(struct bpf_verifier_env *env,
|
|||||||
struct bpf_reg_state *reg;
|
struct bpf_reg_state *reg;
|
||||||
u8 *stype;
|
u8 *stype;
|
||||||
|
|
||||||
if (reg_state->allocated_stack <= slot) {
|
|
||||||
verbose(env, "invalid read from stack off %d+0 size %d\n",
|
|
||||||
off, size);
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
stype = reg_state->stack[spi].slot_type;
|
stype = reg_state->stack[spi].slot_type;
|
||||||
reg = ®_state->stack[spi].spilled_ptr;
|
reg = ®_state->stack[spi].spilled_ptr;
|
||||||
|
|
||||||
@@ -2424,9 +2587,9 @@ static int check_stack_read(struct bpf_verifier_env *env,
|
|||||||
verbose(env, "invalid size of register fill\n");
|
verbose(env, "invalid size of register fill\n");
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
if (value_regno >= 0) {
|
if (dst_regno >= 0) {
|
||||||
mark_reg_unknown(env, state->regs, value_regno);
|
mark_reg_unknown(env, state->regs, dst_regno);
|
||||||
state->regs[value_regno].live |= REG_LIVE_WRITTEN;
|
state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
|
||||||
}
|
}
|
||||||
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
|
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2438,16 +2601,16 @@ static int check_stack_read(struct bpf_verifier_env *env,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value_regno >= 0) {
|
if (dst_regno >= 0) {
|
||||||
/* restore register state from stack */
|
/* restore register state from stack */
|
||||||
state->regs[value_regno] = *reg;
|
state->regs[dst_regno] = *reg;
|
||||||
/* mark reg as written since spilled pointer state likely
|
/* mark reg as written since spilled pointer state likely
|
||||||
* has its liveness marks cleared by is_state_visited()
|
* has its liveness marks cleared by is_state_visited()
|
||||||
* which resets stack/reg liveness for state transitions
|
* which resets stack/reg liveness for state transitions
|
||||||
*/
|
*/
|
||||||
state->regs[value_regno].live |= REG_LIVE_WRITTEN;
|
state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
|
||||||
} else if (__is_pointer_value(env->allow_ptr_leaks, reg)) {
|
} else if (__is_pointer_value(env->allow_ptr_leaks, reg)) {
|
||||||
/* If value_regno==-1, the caller is asking us whether
|
/* If dst_regno==-1, the caller is asking us whether
|
||||||
* it is acceptable to use this value as a SCALAR_VALUE
|
* it is acceptable to use this value as a SCALAR_VALUE
|
||||||
* (e.g. for XADD).
|
* (e.g. for XADD).
|
||||||
* We must not allow unprivileged callers to do that
|
* We must not allow unprivileged callers to do that
|
||||||
@@ -2459,70 +2622,167 @@ static int check_stack_read(struct bpf_verifier_env *env,
|
|||||||
}
|
}
|
||||||
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
|
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
|
||||||
} else {
|
} else {
|
||||||
int zeros = 0;
|
u8 type;
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
if (stype[(slot - i) % BPF_REG_SIZE] == STACK_MISC)
|
type = stype[(slot - i) % BPF_REG_SIZE];
|
||||||
|
if (type == STACK_MISC)
|
||||||
continue;
|
continue;
|
||||||
if (stype[(slot - i) % BPF_REG_SIZE] == STACK_ZERO) {
|
if (type == STACK_ZERO)
|
||||||
zeros++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
verbose(env, "invalid read from stack off %d+%d size %d\n",
|
verbose(env, "invalid read from stack off %d+%d size %d\n",
|
||||||
off, i, size);
|
off, i, size);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
|
mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
|
||||||
if (value_regno >= 0) {
|
if (dst_regno >= 0)
|
||||||
if (zeros == size) {
|
mark_reg_stack_read(env, reg_state, off, off + size, dst_regno);
|
||||||
/* any size read into register is zero extended,
|
|
||||||
* so the whole register == const_zero
|
|
||||||
*/
|
|
||||||
__mark_reg_const_zero(&state->regs[value_regno]);
|
|
||||||
/* backtracking doesn't support STACK_ZERO yet,
|
|
||||||
* so mark it precise here, so that later
|
|
||||||
* backtracking can stop here.
|
|
||||||
* Backtracking may not need this if this register
|
|
||||||
* doesn't participate in pointer adjustment.
|
|
||||||
* Forward propagation of precise flag is not
|
|
||||||
* necessary either. This mark is only to stop
|
|
||||||
* backtracking. Any register that contributed
|
|
||||||
* to const 0 was marked precise before spill.
|
|
||||||
*/
|
|
||||||
state->regs[value_regno].precise = true;
|
|
||||||
} else {
|
|
||||||
/* have read misc data from the stack */
|
|
||||||
mark_reg_unknown(env, state->regs, value_regno);
|
|
||||||
}
|
|
||||||
state->regs[value_regno].live |= REG_LIVE_WRITTEN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_stack_access(struct bpf_verifier_env *env,
|
enum stack_access_src {
|
||||||
const struct bpf_reg_state *reg,
|
ACCESS_DIRECT = 1, /* the access is performed by an instruction */
|
||||||
int off, int size)
|
ACCESS_HELPER = 2, /* the access is performed by a helper */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int check_stack_range_initialized(struct bpf_verifier_env *env,
|
||||||
|
int regno, int off, int access_size,
|
||||||
|
bool zero_size_allowed,
|
||||||
|
enum stack_access_src type,
|
||||||
|
struct bpf_call_arg_meta *meta);
|
||||||
|
|
||||||
|
static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno)
|
||||||
{
|
{
|
||||||
/* Stack accesses must be at a fixed offset, so that we
|
return cur_regs(env) + regno;
|
||||||
* can determine what type of data were returned. See
|
}
|
||||||
* check_stack_read().
|
|
||||||
|
/* Read the stack at 'ptr_regno + off' and put the result into the register
|
||||||
|
* 'dst_regno'.
|
||||||
|
* 'off' includes the pointer register's fixed offset(i.e. 'ptr_regno.off'),
|
||||||
|
* but not its variable offset.
|
||||||
|
* 'size' is assumed to be <= reg size and the access is assumed to be aligned.
|
||||||
|
*
|
||||||
|
* As opposed to check_stack_read_fixed_off, this function doesn't deal with
|
||||||
|
* filling registers (i.e. reads of spilled register cannot be detected when
|
||||||
|
* the offset is not fixed). We conservatively mark 'dst_regno' as containing
|
||||||
|
* SCALAR_VALUE. That's why we assert that the 'ptr_regno' has a variable
|
||||||
|
* offset; for a fixed offset check_stack_read_fixed_off should be used
|
||||||
|
* instead.
|
||||||
*/
|
*/
|
||||||
if (!tnum_is_const(reg->var_off)) {
|
static int check_stack_read_var_off(struct bpf_verifier_env *env,
|
||||||
|
int ptr_regno, int off, int size, int dst_regno)
|
||||||
|
{
|
||||||
|
/* The state of the source register. */
|
||||||
|
struct bpf_reg_state *reg = reg_state(env, ptr_regno);
|
||||||
|
struct bpf_func_state *ptr_state = func(env, reg);
|
||||||
|
int err;
|
||||||
|
int min_off, max_off;
|
||||||
|
|
||||||
|
/* Note that we pass a NULL meta, so raw access will not be permitted.
|
||||||
|
*/
|
||||||
|
err = check_stack_range_initialized(env, ptr_regno, off, size,
|
||||||
|
false, ACCESS_DIRECT, NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
min_off = reg->smin_value + off;
|
||||||
|
max_off = reg->smax_value + off;
|
||||||
|
mark_reg_stack_read(env, ptr_state, min_off, max_off + size, dst_regno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check_stack_read dispatches to check_stack_read_fixed_off or
|
||||||
|
* check_stack_read_var_off.
|
||||||
|
*
|
||||||
|
* The caller must ensure that the offset falls within the allocated stack
|
||||||
|
* bounds.
|
||||||
|
*
|
||||||
|
* 'dst_regno' is a register which will receive the value from the stack. It
|
||||||
|
* can be -1, meaning that the read value is not going to a register.
|
||||||
|
*/
|
||||||
|
static int check_stack_read(struct bpf_verifier_env *env,
|
||||||
|
int ptr_regno, int off, int size,
|
||||||
|
int dst_regno)
|
||||||
|
{
|
||||||
|
struct bpf_reg_state *reg = reg_state(env, ptr_regno);
|
||||||
|
struct bpf_func_state *state = func(env, reg);
|
||||||
|
int err;
|
||||||
|
/* Some accesses are only permitted with a static offset. */
|
||||||
|
bool var_off = !tnum_is_const(reg->var_off);
|
||||||
|
|
||||||
|
/* The offset is required to be static when reads don't go to a
|
||||||
|
* register, in order to not leak pointers (see
|
||||||
|
* check_stack_read_fixed_off).
|
||||||
|
*/
|
||||||
|
if (dst_regno < 0 && var_off) {
|
||||||
char tn_buf[48];
|
char tn_buf[48];
|
||||||
|
|
||||||
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||||
verbose(env, "variable stack access var_off=%s off=%d size=%d\n",
|
verbose(env, "variable offset stack pointer cannot be passed into helper function; var_off=%s off=%d size=%d\n",
|
||||||
tn_buf, off, size);
|
tn_buf, off, size);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
/* Variable offset is prohibited for unprivileged mode for simplicity
|
||||||
|
* since it requires corresponding support in Spectre masking for stack
|
||||||
|
* ALU. See also retrieve_ptr_limit().
|
||||||
|
*/
|
||||||
|
if (!env->bypass_spec_v1 && var_off) {
|
||||||
|
char tn_buf[48];
|
||||||
|
|
||||||
if (off >= 0 || off < -MAX_BPF_STACK) {
|
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||||
verbose(env, "invalid stack off=%d size=%d\n", off, size);
|
verbose(env, "R%d variable offset stack access prohibited for !root, var_off=%s\n",
|
||||||
|
ptr_regno, tn_buf);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (!var_off) {
|
||||||
|
off += reg->var_off.value;
|
||||||
|
err = check_stack_read_fixed_off(env, state, off, size,
|
||||||
|
dst_regno);
|
||||||
|
} else {
|
||||||
|
/* Variable offset stack reads need more conservative handling
|
||||||
|
* than fixed offset ones. Note that dst_regno >= 0 on this
|
||||||
|
* branch.
|
||||||
|
*/
|
||||||
|
err = check_stack_read_var_off(env, ptr_regno, off, size,
|
||||||
|
dst_regno);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* check_stack_write dispatches to check_stack_write_fixed_off or
|
||||||
|
* check_stack_write_var_off.
|
||||||
|
*
|
||||||
|
* 'ptr_regno' is the register used as a pointer into the stack.
|
||||||
|
* 'off' includes 'ptr_regno->off', but not its variable offset (if any).
|
||||||
|
* 'value_regno' is the register whose value we're writing to the stack. It can
|
||||||
|
* be -1, meaning that we're not writing from a register.
|
||||||
|
*
|
||||||
|
* The caller must ensure that the offset falls within the maximum stack size.
|
||||||
|
*/
|
||||||
|
static int check_stack_write(struct bpf_verifier_env *env,
|
||||||
|
int ptr_regno, int off, int size,
|
||||||
|
int value_regno, int insn_idx)
|
||||||
|
{
|
||||||
|
struct bpf_reg_state *reg = reg_state(env, ptr_regno);
|
||||||
|
struct bpf_func_state *state = func(env, reg);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (tnum_is_const(reg->var_off)) {
|
||||||
|
off += reg->var_off.value;
|
||||||
|
err = check_stack_write_fixed_off(env, state, off, size,
|
||||||
|
value_regno, insn_idx);
|
||||||
|
} else {
|
||||||
|
/* Variable offset stack reads need more conservative handling
|
||||||
|
* than fixed offset ones.
|
||||||
|
*/
|
||||||
|
err = check_stack_write_var_off(env, state,
|
||||||
|
ptr_regno, off, size,
|
||||||
|
value_regno, insn_idx);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_map_access_type(struct bpf_verifier_env *env, u32 regno,
|
static int check_map_access_type(struct bpf_verifier_env *env, u32 regno,
|
||||||
@@ -2851,11 +3111,6 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx,
|
|||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno)
|
|
||||||
{
|
|
||||||
return cur_regs(env) + regno;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
|
static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
|
||||||
{
|
{
|
||||||
return __is_pointer_value(env->allow_ptr_leaks, reg_state(env, regno));
|
return __is_pointer_value(env->allow_ptr_leaks, reg_state(env, regno));
|
||||||
@@ -2974,8 +3229,8 @@ static int check_ptr_alignment(struct bpf_verifier_env *env,
|
|||||||
break;
|
break;
|
||||||
case PTR_TO_STACK:
|
case PTR_TO_STACK:
|
||||||
pointer_desc = "stack ";
|
pointer_desc = "stack ";
|
||||||
/* The stack spill tracking logic in check_stack_write()
|
/* The stack spill tracking logic in check_stack_write_fixed_off()
|
||||||
* and check_stack_read() relies on stack accesses being
|
* and check_stack_read_fixed_off() relies on stack accesses being
|
||||||
* aligned.
|
* aligned.
|
||||||
*/
|
*/
|
||||||
strict = true;
|
strict = true;
|
||||||
@@ -3393,6 +3648,91 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check that the stack access at the given offset is within bounds. The
|
||||||
|
* maximum valid offset is -1.
|
||||||
|
*
|
||||||
|
* The minimum valid offset is -MAX_BPF_STACK for writes, and
|
||||||
|
* -state->allocated_stack for reads.
|
||||||
|
*/
|
||||||
|
static int check_stack_slot_within_bounds(int off,
|
||||||
|
struct bpf_func_state *state,
|
||||||
|
enum bpf_access_type t)
|
||||||
|
{
|
||||||
|
int min_valid_off;
|
||||||
|
|
||||||
|
if (t == BPF_WRITE)
|
||||||
|
min_valid_off = -MAX_BPF_STACK;
|
||||||
|
else
|
||||||
|
min_valid_off = -state->allocated_stack;
|
||||||
|
|
||||||
|
if (off < min_valid_off || off > -1)
|
||||||
|
return -EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the stack access at 'regno + off' falls within the maximum stack
|
||||||
|
* bounds.
|
||||||
|
*
|
||||||
|
* 'off' includes `regno->offset`, but not its dynamic part (if any).
|
||||||
|
*/
|
||||||
|
static int check_stack_access_within_bounds(
|
||||||
|
struct bpf_verifier_env *env,
|
||||||
|
int regno, int off, int access_size,
|
||||||
|
enum stack_access_src src, enum bpf_access_type type)
|
||||||
|
{
|
||||||
|
struct bpf_reg_state *regs = cur_regs(env);
|
||||||
|
struct bpf_reg_state *reg = regs + regno;
|
||||||
|
struct bpf_func_state *state = func(env, reg);
|
||||||
|
int min_off, max_off;
|
||||||
|
int err;
|
||||||
|
char *err_extra;
|
||||||
|
|
||||||
|
if (src == ACCESS_HELPER)
|
||||||
|
/* We don't know if helpers are reading or writing (or both). */
|
||||||
|
err_extra = " indirect access to";
|
||||||
|
else if (type == BPF_READ)
|
||||||
|
err_extra = " read from";
|
||||||
|
else
|
||||||
|
err_extra = " write to";
|
||||||
|
|
||||||
|
if (tnum_is_const(reg->var_off)) {
|
||||||
|
min_off = reg->var_off.value + off;
|
||||||
|
if (access_size > 0)
|
||||||
|
max_off = min_off + access_size - 1;
|
||||||
|
else
|
||||||
|
max_off = min_off;
|
||||||
|
} else {
|
||||||
|
if (reg->smax_value >= BPF_MAX_VAR_OFF ||
|
||||||
|
reg->smin_value <= -BPF_MAX_VAR_OFF) {
|
||||||
|
verbose(env, "invalid unbounded variable-offset%s stack R%d\n",
|
||||||
|
err_extra, regno);
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
min_off = reg->smin_value + off;
|
||||||
|
if (access_size > 0)
|
||||||
|
max_off = reg->smax_value + off + access_size - 1;
|
||||||
|
else
|
||||||
|
max_off = min_off;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = check_stack_slot_within_bounds(min_off, state, type);
|
||||||
|
if (!err)
|
||||||
|
err = check_stack_slot_within_bounds(max_off, state, type);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
if (tnum_is_const(reg->var_off)) {
|
||||||
|
verbose(env, "invalid%s stack R%d off=%d size=%d\n",
|
||||||
|
err_extra, regno, off, access_size);
|
||||||
|
} else {
|
||||||
|
char tn_buf[48];
|
||||||
|
|
||||||
|
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||||
|
verbose(env, "invalid variable-offset%s stack R%d var_off=%s size=%d\n",
|
||||||
|
err_extra, regno, tn_buf, access_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* check whether memory at (regno + off) is accessible for t = (read | write)
|
/* check whether memory at (regno + off) is accessible for t = (read | write)
|
||||||
* if t==write, value_regno is a register which value is stored into memory
|
* if t==write, value_regno is a register which value is stored into memory
|
||||||
@@ -3505,8 +3845,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (reg->type == PTR_TO_STACK) {
|
} else if (reg->type == PTR_TO_STACK) {
|
||||||
off += reg->var_off.value;
|
/* Basic bounds checks. */
|
||||||
err = check_stack_access(env, reg, off, size);
|
err = check_stack_access_within_bounds(env, regno, off, size, ACCESS_DIRECT, t);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -3515,12 +3855,12 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (t == BPF_WRITE)
|
if (t == BPF_READ)
|
||||||
err = check_stack_write(env, state, off, size,
|
err = check_stack_read(env, regno, off, size,
|
||||||
value_regno, insn_idx);
|
|
||||||
else
|
|
||||||
err = check_stack_read(env, state, off, size,
|
|
||||||
value_regno);
|
value_regno);
|
||||||
|
else
|
||||||
|
err = check_stack_write(env, regno, off, size,
|
||||||
|
value_regno, insn_idx);
|
||||||
} else if (reg_is_pkt_pointer(reg)) {
|
} else if (reg_is_pkt_pointer(reg)) {
|
||||||
if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) {
|
if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) {
|
||||||
verbose(env, "cannot write into packet\n");
|
verbose(env, "cannot write into packet\n");
|
||||||
@@ -3642,49 +3982,53 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins
|
|||||||
BPF_SIZE(insn->code), BPF_WRITE, -1, true);
|
BPF_SIZE(insn->code), BPF_WRITE, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __check_stack_boundary(struct bpf_verifier_env *env, u32 regno,
|
/* When register 'regno' is used to read the stack (either directly or through
|
||||||
int off, int access_size,
|
* a helper function) make sure that it's within stack boundary and, depending
|
||||||
bool zero_size_allowed)
|
* on the access type, that all elements of the stack are initialized.
|
||||||
{
|
*
|
||||||
struct bpf_reg_state *reg = reg_state(env, regno);
|
* 'off' includes 'regno->off', but not its dynamic part (if any).
|
||||||
|
*
|
||||||
if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 ||
|
* All registers that have been spilled on the stack in the slots within the
|
||||||
access_size < 0 || (access_size == 0 && !zero_size_allowed)) {
|
* read offsets are marked as read.
|
||||||
if (tnum_is_const(reg->var_off)) {
|
|
||||||
verbose(env, "invalid stack type R%d off=%d access_size=%d\n",
|
|
||||||
regno, off, access_size);
|
|
||||||
} else {
|
|
||||||
char tn_buf[48];
|
|
||||||
|
|
||||||
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
|
||||||
verbose(env, "invalid stack type R%d var_off=%s access_size=%d\n",
|
|
||||||
regno, tn_buf, access_size);
|
|
||||||
}
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* when register 'regno' is passed into function that will read 'access_size'
|
|
||||||
* bytes from that pointer, make sure that it's within stack boundary
|
|
||||||
* and all elements of stack are initialized.
|
|
||||||
* Unlike most pointer bounds-checking functions, this one doesn't take an
|
|
||||||
* 'off' argument, so it has to add in reg->off itself.
|
|
||||||
*/
|
*/
|
||||||
static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
|
static int check_stack_range_initialized(
|
||||||
|
struct bpf_verifier_env *env, int regno, int off,
|
||||||
int access_size, bool zero_size_allowed,
|
int access_size, bool zero_size_allowed,
|
||||||
struct bpf_call_arg_meta *meta)
|
enum stack_access_src type, struct bpf_call_arg_meta *meta)
|
||||||
{
|
{
|
||||||
struct bpf_reg_state *reg = reg_state(env, regno);
|
struct bpf_reg_state *reg = reg_state(env, regno);
|
||||||
struct bpf_func_state *state = func(env, reg);
|
struct bpf_func_state *state = func(env, reg);
|
||||||
int err, min_off, max_off, i, j, slot, spi;
|
int err, min_off, max_off, i, j, slot, spi;
|
||||||
|
char *err_extra = type == ACCESS_HELPER ? " indirect" : "";
|
||||||
|
enum bpf_access_type bounds_check_type;
|
||||||
|
/* Some accesses can write anything into the stack, others are
|
||||||
|
* read-only.
|
||||||
|
*/
|
||||||
|
bool clobber = false;
|
||||||
|
|
||||||
if (tnum_is_const(reg->var_off)) {
|
if (access_size == 0 && !zero_size_allowed) {
|
||||||
min_off = max_off = reg->var_off.value + reg->off;
|
verbose(env, "invalid zero-sized read\n");
|
||||||
err = __check_stack_boundary(env, regno, min_off, access_size,
|
return -EACCES;
|
||||||
zero_size_allowed);
|
}
|
||||||
|
|
||||||
|
if (type == ACCESS_HELPER) {
|
||||||
|
/* The bounds checks for writes are more permissive than for
|
||||||
|
* reads. However, if raw_mode is not set, we'll do extra
|
||||||
|
* checks below.
|
||||||
|
*/
|
||||||
|
bounds_check_type = BPF_WRITE;
|
||||||
|
clobber = true;
|
||||||
|
} else {
|
||||||
|
bounds_check_type = BPF_READ;
|
||||||
|
}
|
||||||
|
err = check_stack_access_within_bounds(env, regno, off, access_size,
|
||||||
|
type, bounds_check_type);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
||||||
|
if (tnum_is_const(reg->var_off)) {
|
||||||
|
min_off = max_off = reg->var_off.value + off;
|
||||||
} else {
|
} else {
|
||||||
/* Variable offset is prohibited for unprivileged mode for
|
/* Variable offset is prohibited for unprivileged mode for
|
||||||
* simplicity since it requires corresponding support in
|
* simplicity since it requires corresponding support in
|
||||||
@@ -3695,8 +4039,8 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
|
|||||||
char tn_buf[48];
|
char tn_buf[48];
|
||||||
|
|
||||||
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||||
verbose(env, "R%d indirect variable offset stack access prohibited for !root, var_off=%s\n",
|
verbose(env, "R%d%s variable offset stack access prohibited for !root, var_off=%s\n",
|
||||||
regno, tn_buf);
|
regno, err_extra, tn_buf);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
/* Only initialized buffer on stack is allowed to be accessed
|
/* Only initialized buffer on stack is allowed to be accessed
|
||||||
@@ -3708,28 +4052,8 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
|
|||||||
if (meta && meta->raw_mode)
|
if (meta && meta->raw_mode)
|
||||||
meta = NULL;
|
meta = NULL;
|
||||||
|
|
||||||
if (reg->smax_value >= BPF_MAX_VAR_OFF ||
|
min_off = reg->smin_value + off;
|
||||||
reg->smax_value <= -BPF_MAX_VAR_OFF) {
|
max_off = reg->smax_value + off;
|
||||||
verbose(env, "R%d unbounded indirect variable offset stack access\n",
|
|
||||||
regno);
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
min_off = reg->smin_value + reg->off;
|
|
||||||
max_off = reg->smax_value + reg->off;
|
|
||||||
err = __check_stack_boundary(env, regno, min_off, access_size,
|
|
||||||
zero_size_allowed);
|
|
||||||
if (err) {
|
|
||||||
verbose(env, "R%d min value is outside of stack bound\n",
|
|
||||||
regno);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
err = __check_stack_boundary(env, regno, max_off, access_size,
|
|
||||||
zero_size_allowed);
|
|
||||||
if (err) {
|
|
||||||
verbose(env, "R%d max value is outside of stack bound\n",
|
|
||||||
regno);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta && meta->raw_mode) {
|
if (meta && meta->raw_mode) {
|
||||||
@@ -3749,8 +4073,10 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
|
|||||||
if (*stype == STACK_MISC)
|
if (*stype == STACK_MISC)
|
||||||
goto mark;
|
goto mark;
|
||||||
if (*stype == STACK_ZERO) {
|
if (*stype == STACK_ZERO) {
|
||||||
|
if (clobber) {
|
||||||
/* helper can write anything into the stack */
|
/* helper can write anything into the stack */
|
||||||
*stype = STACK_MISC;
|
*stype = STACK_MISC;
|
||||||
|
}
|
||||||
goto mark;
|
goto mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3759,23 +4085,26 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
|
|||||||
goto mark;
|
goto mark;
|
||||||
|
|
||||||
if (state->stack[spi].slot_type[0] == STACK_SPILL &&
|
if (state->stack[spi].slot_type[0] == STACK_SPILL &&
|
||||||
state->stack[spi].spilled_ptr.type == SCALAR_VALUE) {
|
(state->stack[spi].spilled_ptr.type == SCALAR_VALUE ||
|
||||||
|
env->allow_ptr_leaks)) {
|
||||||
|
if (clobber) {
|
||||||
__mark_reg_unknown(env, &state->stack[spi].spilled_ptr);
|
__mark_reg_unknown(env, &state->stack[spi].spilled_ptr);
|
||||||
for (j = 0; j < BPF_REG_SIZE; j++)
|
for (j = 0; j < BPF_REG_SIZE; j++)
|
||||||
state->stack[spi].slot_type[j] = STACK_MISC;
|
state->stack[spi].slot_type[j] = STACK_MISC;
|
||||||
|
}
|
||||||
goto mark;
|
goto mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (tnum_is_const(reg->var_off)) {
|
if (tnum_is_const(reg->var_off)) {
|
||||||
verbose(env, "invalid indirect read from stack off %d+%d size %d\n",
|
verbose(env, "invalid%s read from stack R%d off %d+%d size %d\n",
|
||||||
min_off, i - min_off, access_size);
|
err_extra, regno, min_off, i - min_off, access_size);
|
||||||
} else {
|
} else {
|
||||||
char tn_buf[48];
|
char tn_buf[48];
|
||||||
|
|
||||||
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||||
verbose(env, "invalid indirect read from stack var_off %s+%d size %d\n",
|
verbose(env, "invalid%s read from stack R%d var_off %s+%d size %d\n",
|
||||||
tn_buf, i - min_off, access_size);
|
err_extra, regno, tn_buf, i - min_off, access_size);
|
||||||
}
|
}
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
mark:
|
mark:
|
||||||
@@ -3824,8 +4153,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
|
|||||||
"rdwr",
|
"rdwr",
|
||||||
&env->prog->aux->max_rdwr_access);
|
&env->prog->aux->max_rdwr_access);
|
||||||
case PTR_TO_STACK:
|
case PTR_TO_STACK:
|
||||||
return check_stack_boundary(env, regno, access_size,
|
return check_stack_range_initialized(
|
||||||
zero_size_allowed, meta);
|
env,
|
||||||
|
regno, reg->off, access_size,
|
||||||
|
zero_size_allowed, ACCESS_HELPER, meta);
|
||||||
default: /* scalar_value or invalid ptr */
|
default: /* scalar_value or invalid ptr */
|
||||||
/* Allow zero-byte read from NULL, regardless of pointer type */
|
/* Allow zero-byte read from NULL, regardless of pointer type */
|
||||||
if (zero_size_allowed && access_size == 0 &&
|
if (zero_size_allowed && access_size == 0 &&
|
||||||
@@ -5343,7 +5674,7 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
|
|||||||
bool off_is_neg = off_reg->smin_value < 0;
|
bool off_is_neg = off_reg->smin_value < 0;
|
||||||
bool mask_to_left = (opcode == BPF_ADD && off_is_neg) ||
|
bool mask_to_left = (opcode == BPF_ADD && off_is_neg) ||
|
||||||
(opcode == BPF_SUB && !off_is_neg);
|
(opcode == BPF_SUB && !off_is_neg);
|
||||||
u32 off, max = 0, ptr_limit = 0;
|
u32 max = 0, ptr_limit = 0;
|
||||||
|
|
||||||
if (!tnum_is_const(off_reg->var_off) &&
|
if (!tnum_is_const(off_reg->var_off) &&
|
||||||
(off_reg->smin_value < 0) != (off_reg->smax_value < 0))
|
(off_reg->smin_value < 0) != (off_reg->smax_value < 0))
|
||||||
@@ -5352,26 +5683,18 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
|
|||||||
switch (ptr_reg->type) {
|
switch (ptr_reg->type) {
|
||||||
case PTR_TO_STACK:
|
case PTR_TO_STACK:
|
||||||
/* Offset 0 is out-of-bounds, but acceptable start for the
|
/* Offset 0 is out-of-bounds, but acceptable start for the
|
||||||
* left direction, see BPF_REG_FP.
|
* left direction, see BPF_REG_FP. Also, unknown scalar
|
||||||
|
* offset where we would need to deal with min/max bounds is
|
||||||
|
* currently prohibited for unprivileged.
|
||||||
*/
|
*/
|
||||||
max = MAX_BPF_STACK + mask_to_left;
|
max = MAX_BPF_STACK + mask_to_left;
|
||||||
/* Indirect variable offset stack access is prohibited in
|
ptr_limit = -(ptr_reg->var_off.value + ptr_reg->off);
|
||||||
* unprivileged mode so it's not handled here.
|
|
||||||
*/
|
|
||||||
off = ptr_reg->off + ptr_reg->var_off.value;
|
|
||||||
if (mask_to_left)
|
|
||||||
ptr_limit = MAX_BPF_STACK + off;
|
|
||||||
else
|
|
||||||
ptr_limit = -off - 1;
|
|
||||||
break;
|
break;
|
||||||
case PTR_TO_MAP_VALUE:
|
case PTR_TO_MAP_VALUE:
|
||||||
max = ptr_reg->map_ptr->value_size;
|
max = ptr_reg->map_ptr->value_size;
|
||||||
if (mask_to_left) {
|
ptr_limit = (mask_to_left ?
|
||||||
ptr_limit = ptr_reg->umax_value + ptr_reg->off;
|
ptr_reg->smin_value :
|
||||||
} else {
|
ptr_reg->umax_value) + ptr_reg->off;
|
||||||
off = ptr_reg->smin_value + ptr_reg->off;
|
|
||||||
ptr_limit = ptr_reg->map_ptr->value_size - off - 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return REASON_TYPE;
|
return REASON_TYPE;
|
||||||
@@ -5426,10 +5749,12 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
|
|||||||
struct bpf_insn *insn,
|
struct bpf_insn *insn,
|
||||||
const struct bpf_reg_state *ptr_reg,
|
const struct bpf_reg_state *ptr_reg,
|
||||||
const struct bpf_reg_state *off_reg,
|
const struct bpf_reg_state *off_reg,
|
||||||
struct bpf_reg_state *dst_reg)
|
struct bpf_reg_state *dst_reg,
|
||||||
|
struct bpf_insn_aux_data *tmp_aux,
|
||||||
|
const bool commit_window)
|
||||||
{
|
{
|
||||||
|
struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : tmp_aux;
|
||||||
struct bpf_verifier_state *vstate = env->cur_state;
|
struct bpf_verifier_state *vstate = env->cur_state;
|
||||||
struct bpf_insn_aux_data *aux = cur_aux(env);
|
|
||||||
bool off_is_neg = off_reg->smin_value < 0;
|
bool off_is_neg = off_reg->smin_value < 0;
|
||||||
bool ptr_is_dst_reg = ptr_reg == dst_reg;
|
bool ptr_is_dst_reg = ptr_reg == dst_reg;
|
||||||
u8 opcode = BPF_OP(insn->code);
|
u8 opcode = BPF_OP(insn->code);
|
||||||
@@ -5448,18 +5773,33 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
|
|||||||
if (vstate->speculative)
|
if (vstate->speculative)
|
||||||
goto do_sim;
|
goto do_sim;
|
||||||
|
|
||||||
alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
|
|
||||||
alu_state |= ptr_is_dst_reg ?
|
|
||||||
BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
|
|
||||||
|
|
||||||
err = retrieve_ptr_limit(ptr_reg, off_reg, &alu_limit, opcode);
|
err = retrieve_ptr_limit(ptr_reg, off_reg, &alu_limit, opcode);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
if (commit_window) {
|
||||||
|
/* In commit phase we narrow the masking window based on
|
||||||
|
* the observed pointer move after the simulated operation.
|
||||||
|
*/
|
||||||
|
alu_state = tmp_aux->alu_state;
|
||||||
|
alu_limit = abs(tmp_aux->alu_limit - alu_limit);
|
||||||
|
} else {
|
||||||
|
alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
|
||||||
|
alu_state |= ptr_is_dst_reg ?
|
||||||
|
BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
|
||||||
|
}
|
||||||
|
|
||||||
err = update_alu_sanitation_state(aux, alu_state, alu_limit);
|
err = update_alu_sanitation_state(aux, alu_state, alu_limit);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
do_sim:
|
do_sim:
|
||||||
|
/* If we're in commit phase, we're done here given we already
|
||||||
|
* pushed the truncated dst_reg into the speculative verification
|
||||||
|
* stack.
|
||||||
|
*/
|
||||||
|
if (commit_window)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Simulate and find potential out-of-bounds access under
|
/* Simulate and find potential out-of-bounds access under
|
||||||
* speculative execution from truncation as a result of
|
* speculative execution from truncation as a result of
|
||||||
* masking when off was not within expected range. If off
|
* masking when off was not within expected range. If off
|
||||||
@@ -5518,6 +5858,72 @@ static int sanitize_err(struct bpf_verifier_env *env,
|
|||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check that stack access falls within stack limits and that 'reg' doesn't
|
||||||
|
* have a variable offset.
|
||||||
|
*
|
||||||
|
* Variable offset is prohibited for unprivileged mode for simplicity since it
|
||||||
|
* requires corresponding support in Spectre masking for stack ALU. See also
|
||||||
|
* retrieve_ptr_limit().
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 'off' includes 'reg->off'.
|
||||||
|
*/
|
||||||
|
static int check_stack_access_for_ptr_arithmetic(
|
||||||
|
struct bpf_verifier_env *env,
|
||||||
|
int regno,
|
||||||
|
const struct bpf_reg_state *reg,
|
||||||
|
int off)
|
||||||
|
{
|
||||||
|
if (!tnum_is_const(reg->var_off)) {
|
||||||
|
char tn_buf[48];
|
||||||
|
|
||||||
|
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||||
|
verbose(env, "R%d variable stack access prohibited for !root, var_off=%s off=%d\n",
|
||||||
|
regno, tn_buf, off);
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off >= 0 || off < -MAX_BPF_STACK) {
|
||||||
|
verbose(env, "R%d stack pointer arithmetic goes out of range, "
|
||||||
|
"prohibited for !root; off=%d\n", regno, off);
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sanitize_check_bounds(struct bpf_verifier_env *env,
|
||||||
|
const struct bpf_insn *insn,
|
||||||
|
const struct bpf_reg_state *dst_reg)
|
||||||
|
{
|
||||||
|
u32 dst = insn->dst_reg;
|
||||||
|
|
||||||
|
/* For unprivileged we require that resulting offset must be in bounds
|
||||||
|
* in order to be able to sanitize access later on.
|
||||||
|
*/
|
||||||
|
if (env->bypass_spec_v1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (dst_reg->type) {
|
||||||
|
case PTR_TO_STACK:
|
||||||
|
if (check_stack_access_for_ptr_arithmetic(env, dst, dst_reg,
|
||||||
|
dst_reg->off + dst_reg->var_off.value))
|
||||||
|
return -EACCES;
|
||||||
|
break;
|
||||||
|
case PTR_TO_MAP_VALUE:
|
||||||
|
if (check_map_access(env, dst, dst_reg->off, 1, false)) {
|
||||||
|
verbose(env, "R%d pointer arithmetic of map value goes out of range, "
|
||||||
|
"prohibited for !root\n", dst);
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
|
/* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
|
||||||
* Caller should also handle BPF_MOV case separately.
|
* Caller should also handle BPF_MOV case separately.
|
||||||
* If we return -EACCES, caller may want to try again treating pointer as a
|
* If we return -EACCES, caller may want to try again treating pointer as a
|
||||||
@@ -5536,6 +5942,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
|||||||
smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
|
smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
|
||||||
u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
|
u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
|
||||||
umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
|
umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
|
||||||
|
struct bpf_insn_aux_data tmp_aux = {};
|
||||||
u8 opcode = BPF_OP(insn->code);
|
u8 opcode = BPF_OP(insn->code);
|
||||||
u32 dst = insn->dst_reg;
|
u32 dst = insn->dst_reg;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -5602,12 +6009,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
|||||||
/* pointer types do not carry 32-bit bounds at the moment. */
|
/* pointer types do not carry 32-bit bounds at the moment. */
|
||||||
__mark_reg32_unbounded(dst_reg);
|
__mark_reg32_unbounded(dst_reg);
|
||||||
|
|
||||||
switch (opcode) {
|
if (sanitize_needed(opcode)) {
|
||||||
case BPF_ADD:
|
ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
|
||||||
ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg);
|
&tmp_aux, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return sanitize_err(env, insn, ret, off_reg, dst_reg);
|
return sanitize_err(env, insn, ret, off_reg, dst_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case BPF_ADD:
|
||||||
/* We can take a fixed offset as long as it doesn't overflow
|
/* We can take a fixed offset as long as it doesn't overflow
|
||||||
* the s32 'off' field
|
* the s32 'off' field
|
||||||
*/
|
*/
|
||||||
@@ -5658,10 +6068,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BPF_SUB:
|
case BPF_SUB:
|
||||||
ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg);
|
|
||||||
if (ret < 0)
|
|
||||||
return sanitize_err(env, insn, ret, off_reg, dst_reg);
|
|
||||||
|
|
||||||
if (dst_reg == off_reg) {
|
if (dst_reg == off_reg) {
|
||||||
/* scalar -= pointer. Creates an unknown scalar */
|
/* scalar -= pointer. Creates an unknown scalar */
|
||||||
verbose(env, "R%d tried to subtract pointer from scalar\n",
|
verbose(env, "R%d tried to subtract pointer from scalar\n",
|
||||||
@@ -5742,22 +6148,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
|||||||
__reg_deduce_bounds(dst_reg);
|
__reg_deduce_bounds(dst_reg);
|
||||||
__reg_bound_offset(dst_reg);
|
__reg_bound_offset(dst_reg);
|
||||||
|
|
||||||
/* For unprivileged we require that resulting offset must be in bounds
|
if (sanitize_check_bounds(env, insn, dst_reg) < 0)
|
||||||
* in order to be able to sanitize access later on.
|
|
||||||
*/
|
|
||||||
if (!env->bypass_spec_v1) {
|
|
||||||
if (dst_reg->type == PTR_TO_MAP_VALUE &&
|
|
||||||
check_map_access(env, dst, dst_reg->off, 1, false)) {
|
|
||||||
verbose(env, "R%d pointer arithmetic of map value goes out of range, "
|
|
||||||
"prohibited for !root\n", dst);
|
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
} else if (dst_reg->type == PTR_TO_STACK &&
|
if (sanitize_needed(opcode)) {
|
||||||
check_stack_access(env, dst_reg, dst_reg->off +
|
ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg,
|
||||||
dst_reg->var_off.value, 1)) {
|
&tmp_aux, true);
|
||||||
verbose(env, "R%d stack pointer arithmetic goes out of range, "
|
if (ret < 0)
|
||||||
"prohibited for !root\n", dst);
|
return sanitize_err(env, insn, ret, off_reg, dst_reg);
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -11951,6 +12348,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
|
|||||||
env->strict_alignment = false;
|
env->strict_alignment = false;
|
||||||
|
|
||||||
env->allow_ptr_leaks = bpf_allow_ptr_leaks();
|
env->allow_ptr_leaks = bpf_allow_ptr_leaks();
|
||||||
|
env->allow_uninit_stack = bpf_allow_uninit_stack();
|
||||||
env->allow_ptr_to_map_access = bpf_allow_ptr_to_map_access();
|
env->allow_ptr_to_map_access = bpf_allow_ptr_to_map_access();
|
||||||
env->bypass_spec_v1 = bpf_bypass_spec_v1();
|
env->bypass_spec_v1 = bpf_bypass_spec_v1();
|
||||||
env->bypass_spec_v4 = bpf_bypass_spec_v4();
|
env->bypass_spec_v4 = bpf_bypass_spec_v4();
|
||||||
|
@@ -61,6 +61,8 @@ EXPORT_SYMBOL(queued_read_lock_slowpath);
|
|||||||
*/
|
*/
|
||||||
void queued_write_lock_slowpath(struct qrwlock *lock)
|
void queued_write_lock_slowpath(struct qrwlock *lock)
|
||||||
{
|
{
|
||||||
|
int cnts;
|
||||||
|
|
||||||
/* Put the writer into the wait queue */
|
/* Put the writer into the wait queue */
|
||||||
arch_spin_lock(&lock->wait_lock);
|
arch_spin_lock(&lock->wait_lock);
|
||||||
|
|
||||||
@@ -74,9 +76,8 @@ void queued_write_lock_slowpath(struct qrwlock *lock)
|
|||||||
|
|
||||||
/* When no more readers or writers, set the locked flag */
|
/* When no more readers or writers, set the locked flag */
|
||||||
do {
|
do {
|
||||||
atomic_cond_read_acquire(&lock->cnts, VAL == _QW_WAITING);
|
cnts = atomic_cond_read_relaxed(&lock->cnts, VAL == _QW_WAITING);
|
||||||
} while (atomic_cmpxchg_relaxed(&lock->cnts, _QW_WAITING,
|
} while (!atomic_try_cmpxchg_acquire(&lock->cnts, &cnts, _QW_LOCKED));
|
||||||
_QW_LOCKED) != _QW_WAITING);
|
|
||||||
unlock:
|
unlock:
|
||||||
arch_spin_unlock(&lock->wait_lock);
|
arch_spin_unlock(&lock->wait_lock);
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
CFLAGS_KASAN_NOSANITIZE := -fno-builtin
|
CFLAGS_KASAN_NOSANITIZE := -fno-builtin
|
||||||
KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
|
KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
|
||||||
|
|
||||||
|
cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
|
||||||
|
|
||||||
ifdef CONFIG_KASAN_STACK
|
ifdef CONFIG_KASAN_STACK
|
||||||
stack_enable := 1
|
stack_enable := 1
|
||||||
else
|
else
|
||||||
@@ -18,8 +20,6 @@ endif
|
|||||||
|
|
||||||
CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
|
CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
|
||||||
|
|
||||||
cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
|
|
||||||
|
|
||||||
# -fasan-shadow-offset fails without -fsanitize
|
# -fasan-shadow-offset fails without -fsanitize
|
||||||
CFLAGS_KASAN_SHADOW := $(call cc-option, -fsanitize=kernel-address \
|
CFLAGS_KASAN_SHADOW := $(call cc-option, -fsanitize=kernel-address \
|
||||||
-fasan-shadow-offset=$(KASAN_SHADOW_OFFSET), \
|
-fasan-shadow-offset=$(KASAN_SHADOW_OFFSET), \
|
||||||
@@ -42,14 +42,14 @@ endif # CONFIG_KASAN_GENERIC
|
|||||||
ifdef CONFIG_KASAN_SW_TAGS
|
ifdef CONFIG_KASAN_SW_TAGS
|
||||||
|
|
||||||
ifdef CONFIG_KASAN_INLINE
|
ifdef CONFIG_KASAN_INLINE
|
||||||
instrumentation_flags := -mllvm -hwasan-mapping-offset=$(KASAN_SHADOW_OFFSET)
|
instrumentation_flags := $(call cc-param,hwasan-mapping-offset=$(KASAN_SHADOW_OFFSET))
|
||||||
else
|
else
|
||||||
instrumentation_flags := -mllvm -hwasan-instrument-with-calls=1
|
instrumentation_flags := $(call cc-param,hwasan-instrument-with-calls=1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
|
CFLAGS_KASAN := -fsanitize=kernel-hwaddress \
|
||||||
-mllvm -hwasan-instrument-stack=$(stack_enable) \
|
$(call cc-param,hwasan-instrument-stack=$(stack_enable)) \
|
||||||
-mllvm -hwasan-use-short-granules=0 \
|
$(call cc-param,hwasan-use-short-granules=0) \
|
||||||
$(instrumentation_flags)
|
$(instrumentation_flags)
|
||||||
|
|
||||||
endif # CONFIG_KASAN_SW_TAGS
|
endif # CONFIG_KASAN_SW_TAGS
|
||||||
|
@@ -79,7 +79,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
|||||||
if (i == ARRAY_SIZE(tpm2_hash_map))
|
if (i == ARRAY_SIZE(tpm2_hash_map))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
|
rc = tpm_try_get_ops(chip);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@@ -39,9 +39,6 @@
|
|||||||
* sequential memory pages only.
|
* sequential memory pages only.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* XXX From arch/ia64/include/uapi/asm/gcc_intrin.h */
|
|
||||||
#define ia64_mf() asm volatile ("mf" ::: "memory")
|
|
||||||
|
|
||||||
#define mb() ia64_mf()
|
#define mb() ia64_mf()
|
||||||
#define rmb() mb()
|
#define rmb() mb()
|
||||||
#define wmb() mb()
|
#define wmb() mb()
|
||||||
|
@@ -636,7 +636,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itr)
|
if (itr && itr->parse_snapshot_options)
|
||||||
return itr->parse_snapshot_options(itr, opts, str);
|
return itr->parse_snapshot_options(itr, opts, str);
|
||||||
|
|
||||||
pr_err("No AUX area tracing to snapshot\n");
|
pr_err("No AUX area tracing to snapshot\n");
|
||||||
|
@@ -836,15 +836,18 @@ out:
|
|||||||
int maps__clone(struct thread *thread, struct maps *parent)
|
int maps__clone(struct thread *thread, struct maps *parent)
|
||||||
{
|
{
|
||||||
struct maps *maps = thread->maps;
|
struct maps *maps = thread->maps;
|
||||||
int err = -ENOMEM;
|
int err;
|
||||||
struct map *map;
|
struct map *map;
|
||||||
|
|
||||||
down_read(&parent->lock);
|
down_read(&parent->lock);
|
||||||
|
|
||||||
maps__for_each_entry(parent, map) {
|
maps__for_each_entry(parent, map) {
|
||||||
struct map *new = map__clone(map);
|
struct map *new = map__clone(map);
|
||||||
if (new == NULL)
|
|
||||||
|
if (new == NULL) {
|
||||||
|
err = -ENOMEM;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
err = unwind__prepare_access(maps, new, NULL);
|
err = unwind__prepare_access(maps, new, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
|
Reference in New Issue
Block a user